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) {...@@ -3971,7 +3971,7 @@ pub const dl_phdr_info = switch (native_os) {
3971 /// Module name.3971 /// Module name.
3972 name: ?[*:0]const u8,3972 name: ?[*:0]const u8,
3973 /// Pointer to module's phdr.3973 /// Pointer to module's phdr.
3974 phdr: [*]std.elf.Phdr,3974 phdr: [*]std.elf.ElfN.Phdr,
3975 /// Number of entries in phdr.3975 /// Number of entries in phdr.
3976 phnum: u16,3976 phnum: u16,
3977 /// Total number of loads.3977 /// Total number of loads.
...@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {...@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {
3984 .illumos => extern struct {3984 .illumos => extern struct {
3985 addr: std.elf.Addr,3985 addr: std.elf.Addr,
3986 name: ?[*:0]const u8,3986 name: ?[*:0]const u8,
3987 phdr: [*]std.elf.Phdr,3987 phdr: [*]std.elf.ElfN.Phdr,
3988 phnum: std.elf.Half,3988 phnum: std.elf.Half,
3989 /// Incremented when a new object is mapped into the process.3989 /// Incremented when a new object is mapped into the process.
3990 adds: u64,3990 adds: u64,
...@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {...@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {
3995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {3995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {
3996 addr: usize,3996 addr: usize,
3997 name: ?[*:0]const u8,3997 name: ?[*:0]const u8,
3998 phdr: [*]std.elf.Phdr,3998 phdr: [*]std.elf.ElfN.Phdr,
3999 phnum: std.elf.Half,3999 phnum: std.elf.Half,
4000 },4000 },
4001 else => void,4001 else => void,
lib/std/debug/SelfInfo/Elf.zig+10-10
...@@ -441,11 +441,11 @@ const DlIterContext = struct {...@@ -441,11 +441,11 @@ const DlIterContext = struct {
441441
442 // Populate `build_id` and `gnu_eh_frame`442 // Populate `build_id` and `gnu_eh_frame`
443 for (info.phdr[0..info.phnum]) |phdr| {443 for (info.phdr[0..info.phnum]) |phdr| {
444 switch (phdr.p_type) {444 switch (phdr.type) {
445 std.elf.PT_NOTE => {445 .NOTE => {
446 // Look for .note.gnu.build-id446 // Look for .note.gnu.build-id
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.p_memsz]);448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.memsz]);
449 const name_size = r.takeInt(u32, native_endian) catch continue;449 const name_size = r.takeInt(u32, native_endian) catch continue;
450 const desc_size = r.takeInt(u32, native_endian) catch continue;450 const desc_size = r.takeInt(u32, native_endian) catch continue;
451 const note_type = r.takeInt(u32, native_endian) catch continue;451 const note_type = r.takeInt(u32, native_endian) catch continue;
...@@ -455,9 +455,9 @@ const DlIterContext = struct {...@@ -455,9 +455,9 @@ const DlIterContext = struct {
455 const desc = r.take(desc_size) catch continue;455 const desc = r.take(desc_size) catch continue;
456 build_id = desc;456 build_id = desc;
457 },457 },
458 std.elf.PT_GNU_EH_FRAME => {458 std.elf.PT.GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.p_memsz];460 gnu_eh_frame = segment_ptr[0..phdr.memsz];
461 },461 },
462 else => {},462 else => {},
463 }463 }
...@@ -478,11 +478,11 @@ const DlIterContext = struct {...@@ -478,11 +478,11 @@ const DlIterContext = struct {
478 });478 });
479479
480 for (info.phdr[0..info.phnum]) |phdr| {480 for (info.phdr[0..info.phnum]) |phdr| {
481 if (phdr.p_type != std.elf.PT_LOAD) continue;481 if (phdr.type != .LOAD) continue;
482 try context.si.ranges.append(gpa, .{482 try context.si.ranges.append(gpa, .{
483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000
484 .start = info.addr +% phdr.p_vaddr,484 .start = info.addr +% phdr.vaddr,
485 .len = phdr.p_memsz,485 .len = phdr.memsz,
486 .module_index = module_index,486 .module_index = module_index,
487 });487 });
488 }488 }
lib/std/dynamic_library.zig+1-2
...@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {...@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
92 });92 });
93}93}
9494
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {95pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
96 _ = phdrs;
97 const _DYNAMIC = get_DYNAMIC() orelse {96 const _DYNAMIC = get_DYNAMIC() orelse {
98 // No PT_DYNAMIC means this is a statically-linked non-PIE program.97 // No PT_DYNAMIC means this is a statically-linked non-PIE program.
99 return .{ .current = null };98 return .{ .current = null };
lib/std/elf.zig+1
...@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;...@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;
50pub const AT_L2_CACHEGEOMETRY = 45;50pub const AT_L2_CACHEGEOMETRY = 45;
51pub const AT_L3_CACHESIZE = 46;51pub const AT_L3_CACHESIZE = 46;
52pub const AT_L3_CACHEGEOMETRY = 47;52pub const AT_L3_CACHEGEOMETRY = 47;
53pub const AT_MINSIGSTKSZ = 51;
5354
54pub const DT_NULL = 0;55pub const DT_NULL = 0;
55pub const DT_NEEDED = 1;56pub const DT_NEEDED = 1;
lib/std/os/linux.zig+1-1
...@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {...@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {
6101pub const dl_phdr_info = extern struct {6101pub const dl_phdr_info = extern struct {
6102 addr: usize,6102 addr: usize,
6103 name: ?[*:0]const u8,6103 name: ?[*:0]const u8,
6104 phdr: [*]std.elf.Phdr,6104 phdr: [*]std.elf.ElfN.Phdr,
6105 phnum: u16,6105 phnum: u16,
6106};6106};
61076107
lib/std/posix.zig+30-39
...@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {...@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
5048 }5048 }
5049}5049}
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
5051pub fn dl_iterate_phdr(5058pub fn dl_iterate_phdr(
5052 context: anytype,5059 context: anytype,
5053 comptime Error: type,5060 comptime Error: type,
...@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(...@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(
5075 }5082 }
5076 }5083 }
50775084
5078 const elf_base = std.process.getBaseAddress();5085 var it = dl.linkmap_iterator() catch unreachable;
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;
50865086
5087 // The executable has no dynamic link segment, create a single entry for5087 // The executable has no dynamic link segment, create a single entry for
5088 // the whole ELF image.5088 // the whole ELF image.
5089 if (it.end()) {5089 if (it.end()) {
5090 // Find the base address for the ELF image, if this is a PIE the value5090 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5091 // is non-zero.5091 const phdrs = getSelfPhdrs();
5092 const base_address = for (phdrs) |*phdr| {5092 var info: dl_phdr_info = .{
5093 if (phdr.p_type == elf.PT_PHDR) {5093 .addr = for (phdrs) |phdr| switch (phdr.type) {
5094 break @intFromPtr(phdrs.ptr) - phdr.p_vaddr;5094 .PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr,
5095 // We could try computing the difference between _DYNAMIC and5095 else => {},
5096 // the p_vaddr of the PT_DYNAMIC section, but using the phdr is5096 } else unreachable,
5097 // good enough (Is it?).5097 .name = switch (getauxval(std.elf.AT_EXECFN)) {
5098 }5098 0 => "/proc/self/exe",
5099 } else unreachable;5099 else => |name| @ptrFromInt(name),
51005100 },
5101 var info = dl_phdr_info{
5102 .addr = base_address,
5103 .name = "/proc/self/exe",
5104 .phdr = phdrs.ptr,5101 .phdr = phdrs.ptr,
5105 .phnum = ehdr.e_phnum,5102 .phnum = @intCast(phdrs.len),
5106 };5103 };
51075104
5108 return callback(&info, @sizeOf(dl_phdr_info), context);5105 return callback(&info, @sizeOf(dl_phdr_info), context);
...@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(...@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(
51105107
5111 // Last return value from the callback function.5108 // Last return value from the callback function.
5112 while (it.next()) |entry| {5109 while (it.next()) |entry| {
5113 var phdr: [*]elf.Phdr = undefined;5110 const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
5114 var phnum: u16 = undefined;5111 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
51155112 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
5116 if (entry.l_addr != 0) {5113 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
5117 const elf_header: *elf.Ehdr = @ptrFromInt(entry.l_addr);5114 break :phdrs phdrs[0..ehdr.phnum];
5118 phdr = @ptrFromInt(entry.l_addr + elf_header.e_phoff);5115 } else getSelfPhdrs();
5119 phnum = elf_header.e_phnum;5116
5120 } else {5117 var info: dl_phdr_info = .{
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{
5127 .addr = entry.l_addr,5118 .addr = entry.l_addr,
5128 .name = entry.l_name,5119 .name = entry.l_name,
5129 .phdr = phdr,5120 .phdr = phdrs.ptr,
5130 .phnum = phnum,5121 .phnum = @intCast(phdrs.len),
5131 };5122 };
51325123
5133 try callback(&info, @sizeOf(dl_phdr_info), context);5124 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 {...@@ -257,11 +257,11 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
257 while (i < info.phnum) : (i += 1) {257 while (i < info.phnum) : (i += 1) {
258 const phdr = info.phdr[i];258 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;
263 // Find the ELF header263 // 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));
265 // Validate the magic265 // Validate the magic
266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
267 // Consistency check267 // Consistency check
lib/std/process.zig+7-7
...@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI...@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI
1658pub fn getBaseAddress() usize {1658pub fn getBaseAddress() usize {
1659 switch (native_os) {1659 switch (native_os) {
1660 .linux => {1660 .linux => {
1661 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;1661 const phdrs = std.posix.getSelfPhdrs();
1662 const base = getauxval(std.elf.AT_BASE);1662 var base: usize = 0;
1663 if (base != 0) {1663 for (phdrs) |phdr| switch (phdr.type) {
1664 return base;1664 .LOAD => return base + phdr.vaddr,
1665 }1665 .PHDR => base = @intFromPtr(phdrs.ptr) - phdr.vaddr,
1666 const phdr = getauxval(std.elf.AT_PHDR);1666 else => {},
1667 return phdr - @sizeOf(std.elf.Ehdr);1667 } else unreachable;
1668 },1668 },
1669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {1669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
1670 return @intFromPtr(&std.c._mh_execute_header);1670 return @intFromPtr(&std.c._mh_execute_header);