authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-10 16:58:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-11 10:33:54-07:00
log4669269673e0240301699127abb16b3072c5e592
treef41f071ac888c0aebf07bfeea0b213d29d82bdba
parentec67d6e03a05a2d87880d7a97654ae55f4c733a2

link.Elf: fix phdr_gnu_stack_index not included in sortPhdrs

Adds type safety for program header indexes. Reduce the amount of state sortPhdrs has access to, helping make the data dependencies clear.

1 files changed, 141 insertions(+), 111 deletions(-)

src/link/Elf.zig+141-111
......@@ -53,26 +53,10 @@ shdr_table_offset: ?u64 = null,
5353
5454/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
5555/// Same order as in the file.
56phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .empty,
57
58/// Special program headers
59/// PT_PHDR
60phdr_table_index: ?u16 = null,
61/// PT_LOAD for PHDR table
62/// We add this special load segment to ensure the EHDR and PHDR table are always
63/// loaded into memory.
64phdr_table_load_index: ?u16 = null,
65/// PT_INTERP
66phdr_interp_index: ?u16 = null,
67/// PT_DYNAMIC
68phdr_dynamic_index: ?u16 = null,
69/// PT_GNU_EH_FRAME
70phdr_gnu_eh_frame_index: ?u16 = null,
71/// PT_GNU_STACK
72phdr_gnu_stack_index: ?u16 = null,
73/// PT_TLS
74/// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
75phdr_tls_index: ?u16 = null,
56phdrs: ProgramHeaderList = .empty,
57
58/// Special program headers.
59phdr_indexes: ProgramHeaderIndexes = .{},
7660
7761page_size: u32,
7862default_sym_version: elf.Elf64_Versym,
......@@ -152,6 +136,57 @@ comment_merge_section_index: ?MergeSection.Index = null,
152136
153137first_eflags: ?elf.Elf64_Word = null,
154138
139const ProgramHeaderList = std.ArrayListUnmanaged(elf.Elf64_Phdr);
140
141const OptionalProgramHeaderIndex = enum(u16) {
142 none = std.math.maxInt(u16),
143 _,
144
145 fn unwrap(i: OptionalProgramHeaderIndex) ?ProgramHeaderIndex {
146 if (i == .none) return null;
147 return @enumFromInt(@intFromEnum(i));
148 }
149
150 fn int(i: OptionalProgramHeaderIndex) ?u16 {
151 if (i == .none) return null;
152 return @intFromEnum(i);
153 }
154};
155
156const ProgramHeaderIndex = enum(u16) {
157 _,
158
159 fn toOptional(i: ProgramHeaderIndex) OptionalProgramHeaderIndex {
160 const result: OptionalProgramHeaderIndex = @enumFromInt(@intFromEnum(i));
161 assert(result != .none);
162 return result;
163 }
164
165 fn int(i: ProgramHeaderIndex) u16 {
166 return @intFromEnum(i);
167 }
168};
169
170const ProgramHeaderIndexes = struct {
171 /// PT_PHDR
172 table: OptionalProgramHeaderIndex = .none,
173 /// PT_LOAD for PHDR table
174 /// We add this special load segment to ensure the EHDR and PHDR table are always
175 /// loaded into memory.
176 table_load: OptionalProgramHeaderIndex = .none,
177 /// PT_INTERP
178 interp: OptionalProgramHeaderIndex = .none,
179 /// PT_DYNAMIC
180 dynamic: OptionalProgramHeaderIndex = .none,
181 /// PT_GNU_EH_FRAME
182 gnu_eh_frame: OptionalProgramHeaderIndex = .none,
183 /// PT_GNU_STACK
184 gnu_stack: OptionalProgramHeaderIndex = .none,
185 /// PT_TLS
186 /// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
187 tls: OptionalProgramHeaderIndex = .none,
188};
189
155190/// When allocating, the ideal_capacity is calculated by
156191/// actual_capacity + (actual_capacity / ideal_factor)
157192const ideal_factor = 3;
......@@ -358,7 +393,7 @@ pub fn createEmpty(
358393 };
359394 const max_nphdrs = comptime getMaxNumberOfPhdrs();
360395 const reserved: u64 = mem.alignForward(u64, padToIdeal(max_nphdrs * phsize), self.page_size);
361 self.phdr_table_index = try self.addPhdr(.{
396 self.phdr_indexes.table = (try self.addPhdr(.{
362397 .type = elf.PT_PHDR,
363398 .flags = elf.PF_R,
364399 .@"align" = p_align,
......@@ -366,8 +401,8 @@ pub fn createEmpty(
366401 .offset = ehsize,
367402 .filesz = reserved,
368403 .memsz = reserved,
369 });
370 self.phdr_table_load_index = try self.addPhdr(.{
404 })).toOptional();
405 self.phdr_indexes.table_load = (try self.addPhdr(.{
371406 .type = elf.PT_LOAD,
372407 .flags = elf.PF_R,
373408 .@"align" = self.page_size,
......@@ -375,7 +410,7 @@ pub fn createEmpty(
375410 .offset = 0,
376411 .filesz = reserved + ehsize,
377412 .memsz = reserved + ehsize,
378 });
413 })).toOptional();
379414 }
380415
381416 if (opt_zcu) |zcu| {
......@@ -966,7 +1001,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
9661001 try self.addLoadPhdrs();
9671002 try self.allocatePhdrTable();
9681003 try self.allocateAllocSections();
969 try self.sortPhdrs();
1004 try sortPhdrs(gpa, &self.phdrs, &self.phdr_indexes, self.sections.items(.phndx));
9701005 try self.allocateNonAllocSections();
9711006 self.allocateSpecialPhdrs();
9721007 if (self.linkerDefinedPtr()) |obj| {
......@@ -2461,7 +2496,7 @@ fn writePhdrTable(self: *Elf) !void {
24612496 const gpa = self.base.comp.gpa;
24622497 const target_endian = self.getTarget().cpu.arch.endian();
24632498 const foreign_endian = target_endian != builtin.cpu.arch.endian();
2464 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
2499 const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?];
24652500
24662501 log.debug("writing program headers from 0x{x} to 0x{x}", .{
24672502 phdr_table.p_offset,
......@@ -2573,18 +2608,18 @@ pub fn writeElfHeader(self: *Elf) !void {
25732608 const entry_sym = obj.entrySymbol(self) orelse break :blk 0;
25742609 break :blk @intCast(entry_sym.address(.{}, self));
25752610 } else 0;
2576 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
2611 const phdr_table_offset = if (self.phdr_indexes.table.int()) |phndx| self.phdrs.items[phndx].p_offset else 0;
25772612 switch (self.ptr_width) {
25782613 .p32 => {
2579 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
2614 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(e_entry), endian);
25802615 index += 4;
25812616
25822617 // e_phoff
2583 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(phdr_table_offset)), endian);
2618 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(phdr_table_offset), endian);
25842619 index += 4;
25852620
25862621 // e_shoff
2587 mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(self.shdr_table_offset.?)), endian);
2622 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(self.shdr_table_offset.?), endian);
25882623 index += 4;
25892624 },
25902625 .p64 => {
......@@ -2631,7 +2666,7 @@ pub fn writeElfHeader(self: *Elf) !void {
26312666 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
26322667 index += 2;
26332668
2634 const e_shnum = @as(u16, @intCast(self.sections.items(.shdr).len));
2669 const e_shnum: u16 = @intCast(self.sections.items(.shdr).len);
26352670 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
26362671 index += 2;
26372672
......@@ -3081,43 +3116,43 @@ pub fn initShStrtab(self: *Elf) !void {
30813116fn initSpecialPhdrs(self: *Elf) !void {
30823117 comptime assert(max_number_of_special_phdrs == 5);
30833118
3084 if (self.interp_section_index != null and self.phdr_interp_index == null) {
3085 self.phdr_interp_index = try self.addPhdr(.{
3119 if (self.interp_section_index != null and self.phdr_indexes.interp == .none) {
3120 self.phdr_indexes.interp = (try self.addPhdr(.{
30863121 .type = elf.PT_INTERP,
30873122 .flags = elf.PF_R,
30883123 .@"align" = 1,
3089 });
3124 })).toOptional();
30903125 }
3091 if (self.dynamic_section_index != null and self.phdr_dynamic_index == null) {
3092 self.phdr_dynamic_index = try self.addPhdr(.{
3126 if (self.dynamic_section_index != null and self.phdr_indexes.dynamic == .none) {
3127 self.phdr_indexes.dynamic = (try self.addPhdr(.{
30933128 .type = elf.PT_DYNAMIC,
30943129 .flags = elf.PF_R | elf.PF_W,
3095 });
3130 })).toOptional();
30963131 }
3097 if (self.eh_frame_hdr_section_index != null and self.phdr_gnu_eh_frame_index == null) {
3098 self.phdr_gnu_eh_frame_index = try self.addPhdr(.{
3132 if (self.eh_frame_hdr_section_index != null and self.phdr_indexes.gnu_eh_frame == .none) {
3133 self.phdr_indexes.gnu_eh_frame = (try self.addPhdr(.{
30993134 .type = elf.PT_GNU_EH_FRAME,
31003135 .flags = elf.PF_R,
3101 });
3136 })).toOptional();
31023137 }
3103 if (self.phdr_gnu_stack_index == null) {
3104 self.phdr_gnu_stack_index = try self.addPhdr(.{
3138 if (self.phdr_indexes.gnu_stack == .none) {
3139 self.phdr_indexes.gnu_stack = (try self.addPhdr(.{
31053140 .type = elf.PT_GNU_STACK,
31063141 .flags = elf.PF_W | elf.PF_R,
31073142 .memsz = self.base.stack_size,
31083143 .@"align" = 1,
3109 });
3144 })).toOptional();
31103145 }
31113146
31123147 const has_tls = for (self.sections.items(.shdr)) |shdr| {
31133148 if (shdr.sh_flags & elf.SHF_TLS != 0) break true;
31143149 } else false;
3115 if (has_tls and self.phdr_tls_index == null) {
3116 self.phdr_tls_index = try self.addPhdr(.{
3150 if (has_tls and self.phdr_indexes.tls == .none) {
3151 self.phdr_indexes.tls = (try self.addPhdr(.{
31173152 .type = elf.PT_TLS,
31183153 .flags = elf.PF_R,
31193154 .@"align" = 1,
3120 });
3155 })).toOptional();
31213156 }
31223157}
31233158
......@@ -3251,25 +3286,30 @@ fn setHashSections(self: *Elf) !void {
32513286}
32523287
32533288fn phdrRank(phdr: elf.Elf64_Phdr) u8 {
3254 switch (phdr.p_type) {
3255 elf.PT_NULL => return 0,
3256 elf.PT_PHDR => return 1,
3257 elf.PT_INTERP => return 2,
3258 elf.PT_LOAD => return 3,
3259 elf.PT_DYNAMIC, elf.PT_TLS => return 4,
3260 elf.PT_GNU_EH_FRAME => return 5,
3261 elf.PT_GNU_STACK => return 6,
3262 else => return 7,
3263 }
3289 return switch (phdr.p_type) {
3290 elf.PT_NULL => 0,
3291 elf.PT_PHDR => 1,
3292 elf.PT_INTERP => 2,
3293 elf.PT_LOAD => 3,
3294 elf.PT_DYNAMIC, elf.PT_TLS => 4,
3295 elf.PT_GNU_EH_FRAME => 5,
3296 elf.PT_GNU_STACK => 6,
3297 else => 7,
3298 };
32643299}
32653300
3266fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
3301fn sortPhdrs(
3302 gpa: Allocator,
3303 phdrs: *ProgramHeaderList,
3304 special_indexes: *ProgramHeaderIndexes,
3305 section_indexes: []OptionalProgramHeaderIndex,
3306) error{OutOfMemory}!void {
32673307 const Entry = struct {
32683308 phndx: u16,
32693309
3270 pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
3271 const lhs_phdr = elf_file.phdrs.items[lhs.phndx];
3272 const rhs_phdr = elf_file.phdrs.items[rhs.phndx];
3310 pub fn lessThan(program_headers: []const elf.Elf64_Phdr, lhs: @This(), rhs: @This()) bool {
3311 const lhs_phdr = program_headers[lhs.phndx];
3312 const rhs_phdr = program_headers[rhs.phndx];
32733313 const lhs_rank = phdrRank(lhs_phdr);
32743314 const rhs_rank = phdrRank(rhs_phdr);
32753315 if (lhs_rank == rhs_rank) return lhs_phdr.p_vaddr < rhs_phdr.p_vaddr;
......@@ -3277,45 +3317,34 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
32773317 }
32783318 };
32793319
3280 const gpa = self.base.comp.gpa;
3281 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.phdrs.items.len);
3282 defer entries.deinit();
3283 for (0..self.phdrs.items.len) |phndx| {
3284 entries.appendAssumeCapacity(.{ .phndx = @as(u16, @intCast(phndx)) });
3320 const entries = try gpa.alloc(Entry, phdrs.items.len);
3321 defer gpa.free(entries);
3322 for (entries, 0..) |*entry, phndx| {
3323 entry.* = .{ .phndx = @intCast(phndx) };
32853324 }
32863325
3287 mem.sort(Entry, entries.items, self, Entry.lessThan);
3326 mem.sort(Entry, entries, phdrs.items, Entry.lessThan);
32883327
3289 const backlinks = try gpa.alloc(u16, entries.items.len);
3328 const backlinks = try gpa.alloc(u16, entries.len);
32903329 defer gpa.free(backlinks);
3291 for (entries.items, 0..) |entry, i| {
3292 backlinks[entry.phndx] = @as(u16, @intCast(i));
3293 }
3294
3295 const slice = try self.phdrs.toOwnedSlice(gpa);
3330 const slice = try phdrs.toOwnedSlice(gpa);
32963331 defer gpa.free(slice);
3332 try phdrs.resize(gpa, slice.len);
32973333
3298 try self.phdrs.ensureTotalCapacityPrecise(gpa, slice.len);
3299 for (entries.items) |sorted| {
3300 self.phdrs.appendAssumeCapacity(slice[sorted.phndx]);
3334 for (entries, phdrs.items, 0..) |entry, *phdr, i| {
3335 backlinks[entry.phndx] = @intCast(i);
3336 phdr.* = slice[entry.phndx];
33013337 }
33023338
3303 for (&[_]*?u16{
3304 &self.phdr_table_index,
3305 &self.phdr_table_load_index,
3306 &self.phdr_interp_index,
3307 &self.phdr_dynamic_index,
3308 &self.phdr_gnu_eh_frame_index,
3309 &self.phdr_tls_index,
3310 }) |maybe_index| {
3311 if (maybe_index.*) |*index| {
3312 index.* = backlinks[index.*];
3339 inline for (@typeInfo(ProgramHeaderIndexes).@"struct".fields) |field| {
3340 if (@field(special_indexes, field.name).int()) |special_index| {
3341 @field(special_indexes, field.name) = @enumFromInt(backlinks[special_index]);
33133342 }
33143343 }
33153344
3316 for (self.sections.items(.phndx)) |*maybe_phndx| {
3317 if (maybe_phndx.*) |*index| {
3318 index.* = backlinks[index.*];
3345 for (section_indexes) |*opt_phndx| {
3346 if (opt_phndx.int()) |index| {
3347 opt_phndx.* = @enumFromInt(backlinks[index]);
33193348 }
33203349 }
33213350}
......@@ -3656,7 +3685,7 @@ fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void {
36563685 if (shdr.sh_type == elf.SHT_NULL) continue;
36573686 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
36583687 const flags = shdrToPhdrFlags(shdr.sh_flags);
3659 if (self.getPhdr(.{ .flags = flags, .type = elf.PT_LOAD }) == null) {
3688 if (self.getPhdr(.{ .flags = flags, .type = elf.PT_LOAD }) == .none) {
36603689 _ = try self.addPhdr(.{ .flags = flags, .type = elf.PT_LOAD });
36613690 }
36623691 }
......@@ -3664,8 +3693,8 @@ fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void {
36643693
36653694/// Allocates PHDR table in virtual memory and in file.
36663695fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
3667 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
3668 const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?];
3696 const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?];
3697 const phdr_table_load = &self.phdrs.items[self.phdr_indexes.table_load.int().?];
36693698
36703699 const ehsize: u64 = switch (self.ptr_width) {
36713700 .p32 => @sizeOf(elf.Elf32_Ehdr),
......@@ -3757,7 +3786,7 @@ pub fn allocateAllocSections(self: *Elf) !void {
37573786 // When allocating we first find the largest required alignment
37583787 // of any section that is contained in a cover and use it to align
37593788 // the start address of the segement (and first section).
3760 const phdr_table = &self.phdrs.items[self.phdr_table_load_index.?];
3789 const phdr_table = &self.phdrs.items[self.phdr_indexes.table_load.int().?];
37613790 var addr = phdr_table.p_vaddr + phdr_table.p_memsz;
37623791
37633792 for (covers) |cover| {
......@@ -3817,8 +3846,8 @@ pub fn allocateAllocSections(self: *Elf) !void {
38173846 }
38183847
38193848 const first = slice.items(.shdr)[cover.items[0]];
3820 const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).?;
3821 const phdr = &self.phdrs.items[phndx];
3849 const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).unwrap().?;
3850 const phdr = &self.phdrs.items[phndx.int()];
38223851 const allocated_size = self.allocatedSize(phdr.p_offset);
38233852 if (filesz > allocated_size) {
38243853 const old_offset = phdr.p_offset;
......@@ -3830,7 +3859,7 @@ pub fn allocateAllocSections(self: *Elf) !void {
38303859
38313860 for (cover.items) |shndx| {
38323861 const shdr = &slice.items(.shdr)[shndx];
3833 slice.items(.phndx)[shndx] = phndx;
3862 slice.items(.phndx)[shndx] = phndx.toOptional();
38343863 if (shdr.sh_type == elf.SHT_NOBITS) {
38353864 shdr.sh_offset = 0;
38363865 continue;
......@@ -3906,12 +3935,12 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
39063935fn allocateSpecialPhdrs(self: *Elf) void {
39073936 const slice = self.sections.slice();
39083937
3909 for (&[_]struct { ?u16, ?u32 }{
3910 .{ self.phdr_interp_index, self.interp_section_index },
3911 .{ self.phdr_dynamic_index, self.dynamic_section_index },
3912 .{ self.phdr_gnu_eh_frame_index, self.eh_frame_hdr_section_index },
3938 for (&[_]struct { OptionalProgramHeaderIndex, ?u32 }{
3939 .{ self.phdr_indexes.interp, self.interp_section_index },
3940 .{ self.phdr_indexes.dynamic, self.dynamic_section_index },
3941 .{ self.phdr_indexes.gnu_eh_frame, self.eh_frame_hdr_section_index },
39133942 }) |pair| {
3914 if (pair[0]) |index| {
3943 if (pair[0].int()) |index| {
39153944 const shdr = slice.items(.shdr)[pair[1].?];
39163945 const phdr = &self.phdrs.items[index];
39173946 phdr.p_align = shdr.sh_addralign;
......@@ -3926,7 +3955,7 @@ fn allocateSpecialPhdrs(self: *Elf) void {
39263955 // Set the TLS segment boundaries.
39273956 // We assume TLS sections are laid out contiguously and that there is
39283957 // a single TLS segment.
3929 if (self.phdr_tls_index) |index| {
3958 if (self.phdr_indexes.tls.int()) |index| {
39303959 const shdrs = slice.items(.shdr);
39313960 const phdr = &self.phdrs.items[index];
39323961 var shndx: u32 = 0;
......@@ -4482,14 +4511,15 @@ pub fn isEffectivelyDynLib(self: Elf) bool {
44824511fn getPhdr(self: *Elf, opts: struct {
44834512 type: u32 = 0,
44844513 flags: u32 = 0,
4485}) ?u16 {
4514}) OptionalProgramHeaderIndex {
44864515 for (self.phdrs.items, 0..) |phdr, phndx| {
4487 if (self.phdr_table_load_index) |index| {
4516 if (self.phdr_indexes.table_load.int()) |index| {
44884517 if (phndx == index) continue;
44894518 }
4490 if (phdr.p_type == opts.type and phdr.p_flags == opts.flags) return @intCast(phndx);
4519 if (phdr.p_type == opts.type and phdr.p_flags == opts.flags)
4520 return @enumFromInt(phndx);
44914521 }
4492 return null;
4522 return .none;
44934523}
44944524
44954525fn addPhdr(self: *Elf, opts: struct {
......@@ -4500,9 +4530,9 @@ fn addPhdr(self: *Elf, opts: struct {
45004530 addr: u64 = 0,
45014531 filesz: u64 = 0,
45024532 memsz: u64 = 0,
4503}) error{OutOfMemory}!u16 {
4533}) error{OutOfMemory}!ProgramHeaderIndex {
45044534 const gpa = self.base.comp.gpa;
4505 const index = @as(u16, @intCast(self.phdrs.items.len));
4535 const index: ProgramHeaderIndex = @enumFromInt(self.phdrs.items.len);
45064536 try self.phdrs.append(gpa, .{
45074537 .p_type = opts.type,
45084538 .p_flags = opts.flags,
......@@ -4756,7 +4786,7 @@ pub fn gotAddress(self: *Elf) i64 {
47564786}
47574787
47584788pub fn tpAddress(self: *Elf) i64 {
4759 const index = self.phdr_tls_index orelse return 0;
4789 const index = self.phdr_indexes.tls.int() orelse return 0;
47604790 const phdr = self.phdrs.items[index];
47614791 const addr = switch (self.getTarget().cpu.arch) {
47624792 .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align),
......@@ -4768,13 +4798,13 @@ pub fn tpAddress(self: *Elf) i64 {
47684798}
47694799
47704800pub fn dtpAddress(self: *Elf) i64 {
4771 const index = self.phdr_tls_index orelse return 0;
4801 const index = self.phdr_indexes.tls.int() orelse return 0;
47724802 const phdr = self.phdrs.items[index];
47734803 return @intCast(phdr.p_vaddr);
47744804}
47754805
47764806pub fn tlsAddress(self: *Elf) i64 {
4777 const index = self.phdr_tls_index orelse return 0;
4807 const index = self.phdr_indexes.tls.int() orelse return 0;
47784808 const phdr = self.phdrs.items[index];
47794809 return @intCast(phdr.p_vaddr);
47804810}
......@@ -5393,7 +5423,7 @@ const Section = struct {
53935423 shdr: elf.Elf64_Shdr,
53945424
53955425 /// Assigned program header index if any.
5396 phndx: ?u32 = null,
5426 phndx: OptionalProgramHeaderIndex = .none,
53975427
53985428 /// List of atoms contributing to this section.
53995429 /// TODO currently this is only used for relocations tracking in relocatable mode