authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-08 23:03:10-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-09 03:31:26-05:00
log57889cae80310fa774b181ea9d0a8543f8437df7
tree291014054a5006247fc41cb8de7f47945273bacf
parentd33c00cad024c15e4fae84317d24d816eaf3da3a

posix: reduce the number of assumptions made by `dl_iterate_phdr`

Not yet fully compatible with the new linker, but still progress. Closes #25786

8 files changed, 56 insertions(+), 65 deletions(-)

lib/std/c.zig+3-3
......@@ -3971,7 +3971,7 @@ pub const dl_phdr_info = switch (native_os) {
39713971 /// Module name.
39723972 name: ?[*:0]const u8,
39733973 /// Pointer to module's phdr.
3974 phdr: [*]std.elf.Phdr,
3974 phdr: [*]std.elf.ElfN.Phdr,
39753975 /// Number of entries in phdr.
39763976 phnum: u16,
39773977 /// Total number of loads.
......@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {
39843984 .illumos => extern struct {
39853985 addr: std.elf.Addr,
39863986 name: ?[*:0]const u8,
3987 phdr: [*]std.elf.Phdr,
3987 phdr: [*]std.elf.ElfN.Phdr,
39883988 phnum: std.elf.Half,
39893989 /// Incremented when a new object is mapped into the process.
39903990 adds: u64,
......@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {
39953995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {
39963996 addr: usize,
39973997 name: ?[*:0]const u8,
3998 phdr: [*]std.elf.Phdr,
3998 phdr: [*]std.elf.ElfN.Phdr,
39993999 phnum: std.elf.Half,
40004000 },
40014001 else => void,
lib/std/debug/SelfInfo/Elf.zig+10-10
......@@ -441,11 +441,11 @@ const DlIterContext = struct {
441441
442442 // Populate `build_id` and `gnu_eh_frame`
443443 for (info.phdr[0..info.phnum]) |phdr| {
444 switch (phdr.p_type) {
445 std.elf.PT_NOTE => {
444 switch (phdr.type) {
445 .NOTE => {
446446 // Look for .note.gnu.build-id
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.p_memsz]);
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.memsz]);
449449 const name_size = r.takeInt(u32, native_endian) catch continue;
450450 const desc_size = r.takeInt(u32, native_endian) catch continue;
451451 const note_type = r.takeInt(u32, native_endian) catch continue;
......@@ -455,9 +455,9 @@ const DlIterContext = struct {
455455 const desc = r.take(desc_size) catch continue;
456456 build_id = desc;
457457 },
458 std.elf.PT_GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.p_memsz];
458 std.elf.PT.GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.memsz];
461461 },
462462 else => {},
463463 }
......@@ -478,11 +478,11 @@ const DlIterContext = struct {
478478 });
479479
480480 for (info.phdr[0..info.phnum]) |phdr| {
481 if (phdr.p_type != std.elf.PT_LOAD) continue;
481 if (phdr.type != .LOAD) continue;
482482 try context.si.ranges.append(gpa, .{
483483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000
484 .start = info.addr +% phdr.p_vaddr,
485 .len = phdr.p_memsz,
484 .start = info.addr +% phdr.vaddr,
485 .len = phdr.memsz,
486486 .module_index = module_index,
487487 });
488488 }
lib/std/dynamic_library.zig+1-2
......@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
9292 });
9393}
9494
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
96 _ = phdrs;
95pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
9796 const _DYNAMIC = get_DYNAMIC() orelse {
9897 // No PT_DYNAMIC means this is a statically-linked non-PIE program.
9998 return .{ .current = null };
lib/std/elf.zig+1
......@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;
5050pub const AT_L2_CACHEGEOMETRY = 45;
5151pub const AT_L3_CACHESIZE = 46;
5252pub const AT_L3_CACHEGEOMETRY = 47;
53pub const AT_MINSIGSTKSZ = 51;
5354
5455pub const DT_NULL = 0;
5556pub const DT_NEEDED = 1;
lib/std/os/linux.zig+1-1
......@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {
61016101pub const dl_phdr_info = extern struct {
61026102 addr: usize,
61036103 name: ?[*:0]const u8,
6104 phdr: [*]std.elf.Phdr,
6104 phdr: [*]std.elf.ElfN.Phdr,
61056105 phnum: u16,
61066106};
61076107
lib/std/posix.zig+30-39
......@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
50485048 }
50495049}
50505050
5051pub fn getSelfPhdrs() []std.elf.ElfN.Phdr {
5052 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5053 assert(getauxval(std.elf.AT_PHENT) == @sizeOf(std.elf.ElfN.Phdr));
5054 const phdrs: [*]std.elf.ElfN.Phdr = @ptrFromInt(getauxval(std.elf.AT_PHDR));
5055 return phdrs[0..getauxval(std.elf.AT_PHNUM)];
5056}
5057
50515058pub fn dl_iterate_phdr(
50525059 context: anytype,
50535060 comptime Error: type,
......@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(
50755082 }
50765083 }
50775084
5078 const elf_base = std.process.getBaseAddress();
5079 const ehdr: *elf.Ehdr = @ptrFromInt(elf_base);
5080 // Make sure the base address points to an ELF image.
5081 assert(mem.eql(u8, ehdr.e_ident[0..4], elf.MAGIC));
5082 const n_phdr = ehdr.e_phnum;
5083 const phdrs = (@as([*]elf.Phdr, @ptrFromInt(elf_base + ehdr.e_phoff)))[0..n_phdr];
5084
5085 var it = dl.linkmap_iterator(phdrs) catch unreachable;
5085 var it = dl.linkmap_iterator() catch unreachable;
50865086
50875087 // The executable has no dynamic link segment, create a single entry for
50885088 // the whole ELF image.
50895089 if (it.end()) {
5090 // Find the base address for the ELF image, if this is a PIE the value
5091 // is non-zero.
5092 const base_address = for (phdrs) |*phdr| {
5093 if (phdr.p_type == elf.PT_PHDR) {
5094 break @intFromPtr(phdrs.ptr) - phdr.p_vaddr;
5095 // We could try computing the difference between _DYNAMIC and
5096 // the p_vaddr of the PT_DYNAMIC section, but using the phdr is
5097 // good enough (Is it?).
5098 }
5099 } else unreachable;
5100
5101 var info = dl_phdr_info{
5102 .addr = base_address,
5103 .name = "/proc/self/exe",
5090 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5091 const phdrs = getSelfPhdrs();
5092 var info: dl_phdr_info = .{
5093 .addr = for (phdrs) |phdr| switch (phdr.type) {
5094 .PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr,
5095 else => {},
5096 } else unreachable,
5097 .name = switch (getauxval(std.elf.AT_EXECFN)) {
5098 0 => "/proc/self/exe",
5099 else => |name| @ptrFromInt(name),
5100 },
51045101 .phdr = phdrs.ptr,
5105 .phnum = ehdr.e_phnum,
5102 .phnum = @intCast(phdrs.len),
51065103 };
51075104
51085105 return callback(&info, @sizeOf(dl_phdr_info), context);
......@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(
51105107
51115108 // Last return value from the callback function.
51125109 while (it.next()) |entry| {
5113 var phdr: [*]elf.Phdr = undefined;
5114 var phnum: u16 = undefined;
5115
5116 if (entry.l_addr != 0) {
5117 const elf_header: *elf.Ehdr = @ptrFromInt(entry.l_addr);
5118 phdr = @ptrFromInt(entry.l_addr + elf_header.e_phoff);
5119 phnum = elf_header.e_phnum;
5120 } else {
5121 // This is the running ELF image
5122 phdr = @ptrFromInt(elf_base + ehdr.e_phoff);
5123 phnum = ehdr.e_phnum;
5124 }
5125
5126 var info = dl_phdr_info{
5110 const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
5111 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
5112 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
5113 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
5114 break :phdrs phdrs[0..ehdr.phnum];
5115 } else getSelfPhdrs();
5116
5117 var info: dl_phdr_info = .{
51275118 .addr = entry.l_addr,
51285119 .name = entry.l_name,
5129 .phdr = phdr,
5130 .phnum = phnum,
5120 .phdr = phdrs.ptr,
5121 .phnum = @intCast(phdrs.len),
51315122 };
51325123
51335124 try callback(&info, @sizeOf(dl_phdr_info), context);
lib/std/posix/test.zig+3-3
......@@ -257,11 +257,11 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
257257 while (i < info.phnum) : (i += 1) {
258258 const phdr = info.phdr[i];
259259
260 if (phdr.p_type != elf.PT_LOAD) continue;
260 if (phdr.type != .LOAD) continue;
261261
262 const reloc_addr = info.addr + phdr.p_vaddr;
262 const reloc_addr = info.addr + phdr.vaddr;
263263 // Find the ELF header
264 const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.p_offset));
264 const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.offset));
265265 // Validate the magic
266266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
267267 // Consistency check
lib/std/process.zig+7-7
......@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI
16581658pub fn getBaseAddress() usize {
16591659 switch (native_os) {
16601660 .linux => {
1661 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
1662 const base = getauxval(std.elf.AT_BASE);
1663 if (base != 0) {
1664 return base;
1665 }
1666 const phdr = getauxval(std.elf.AT_PHDR);
1667 return phdr - @sizeOf(std.elf.Ehdr);
1661 const phdrs = std.posix.getSelfPhdrs();
1662 var base: usize = 0;
1663 for (phdrs) |phdr| switch (phdr.type) {
1664 .LOAD => return base + phdr.vaddr,
1665 .PHDR => base = @intFromPtr(phdrs.ptr) - phdr.vaddr,
1666 else => {},
1667 } else unreachable;
16681668 },
16691669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
16701670 return @intFromPtr(&std.c._mh_execute_header);