authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-03 16:57:15+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-03 16:57:15+01:00
log7641561f2d538cdccf452bc801a1bea88b91fed7
tree8c9515c442dc9d76a31be1fbb0bc36276203e88d
parent1ad545c97bbfed8e29f0312a794731638377705a

macho: refactor section/segment handle tracking logic


3 files changed, 99 insertions(+), 46 deletions(-)

src/link/MachO.zig+85-22
...@@ -613,7 +613,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -613,7 +613,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
613 if (!atom.flags.alive) continue;613 if (!atom.flags.alive) continue;
614 const sect = &self.sections.items(.header)[atom.out_n_sect];614 const sect = &self.sections.items(.header)[atom.out_n_sect];
615 if (sect.isZerofill()) continue;615 if (sect.isZerofill()) continue;
616 if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately616 if (!self.isZigSection(atom.out_n_sect)) continue; // Non-Zig sections are handled separately
617 if (atom.getRelocs(self).len == 0) continue;617 if (atom.getRelocs(self).len == 0) continue;
618 // TODO: we will resolve and write ZigObject's TLS data twice:618 // TODO: we will resolve and write ZigObject's TLS data twice:
619 // once here, and once in writeAtoms619 // once here, and once in writeAtoms
...@@ -2231,11 +2231,11 @@ fn initSegments(self: *MachO) !void {...@@ -2231,11 +2231,11 @@ fn initSegments(self: *MachO) !void {
2231 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_size});2231 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_size});
2232 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_size});2232 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_size});
2233 }2233 }
2234 _ = try self.addSegment("__PAGEZERO", .{ .vmsize = aligned_pagezero_size });2234 self.pagezero_seg_index = try self.addSegment("__PAGEZERO", .{ .vmsize = aligned_pagezero_size });
2235 }2235 }
22362236
2237 // __TEXT segment is non-optional2237 // __TEXT segment is non-optional
2238 _ = try self.addSegment("__TEXT", .{ .prot = getSegmentProt("__TEXT") });2238 self.text_seg_index = try self.addSegment("__TEXT", .{ .prot = getSegmentProt("__TEXT") });
22392239
2240 // Next, create segments required by sections2240 // Next, create segments required by sections
2241 for (slice.items(.header)) |header| {2241 for (slice.items(.header)) |header| {
...@@ -2247,15 +2247,57 @@ fn initSegments(self: *MachO) !void {...@@ -2247,15 +2247,57 @@ fn initSegments(self: *MachO) !void {
2247 }2247 }
22482248
2249 // Add __LINKEDIT2249 // Add __LINKEDIT
2250 _ = try self.addSegment("__LINKEDIT", .{ .prot = getSegmentProt("__LINKEDIT") });2250 self.linkedit_seg_index = try self.addSegment("__LINKEDIT", .{ .prot = getSegmentProt("__LINKEDIT") });
22512251
2252 // Sort segments2252 // Sort segments
2253 const sortFn = struct {2253 const Entry = struct {
2254 fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {2254 index: u8,
2255 return segmentLessThan(ctx, lhs.segName(), rhs.segName());2255
2256 pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool {
2257 return segmentLessThan(
2258 {},
2259 macho_file.segments.items[lhs.index].segName(),
2260 macho_file.segments.items[rhs.index].segName(),
2261 );
2256 }2262 }
2257 }.sortFn;2263 };
2258 mem.sort(macho.segment_command_64, self.segments.items, {}, sortFn);2264
2265 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.segments.items.len);
2266 defer entries.deinit();
2267 for (0..self.segments.items.len) |index| {
2268 entries.appendAssumeCapacity(.{ .index = @intCast(index) });
2269 }
2270
2271 mem.sort(Entry, entries.items, self, Entry.lessThan);
2272
2273 const backlinks = try gpa.alloc(u8, entries.items.len);
2274 defer gpa.free(backlinks);
2275 for (entries.items, 0..) |entry, i| {
2276 backlinks[entry.index] = @intCast(i);
2277 }
2278
2279 const segments = try self.segments.toOwnedSlice(gpa);
2280 defer gpa.free(segments);
2281
2282 try self.segments.ensureTotalCapacityPrecise(gpa, segments.len);
2283 for (entries.items) |sorted| {
2284 self.segments.appendAssumeCapacity(segments[sorted.index]);
2285 }
2286
2287 for (&[_]*?u8{
2288 &self.pagezero_seg_index,
2289 &self.text_seg_index,
2290 &self.linkedit_seg_index,
2291 &self.zig_text_seg_index,
2292 &self.zig_got_seg_index,
2293 &self.zig_const_seg_index,
2294 &self.zig_data_seg_index,
2295 &self.zig_bss_seg_index,
2296 }) |maybe_index| {
2297 if (maybe_index.*) |*index| {
2298 index.* = backlinks[index.*];
2299 }
2300 }
22592301
2260 // Attach sections to segments2302 // Attach sections to segments
2261 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {2303 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
...@@ -2276,15 +2318,6 @@ fn initSegments(self: *MachO) !void {...@@ -2276,15 +2318,6 @@ fn initSegments(self: *MachO) !void {
2276 segment.nsects += 1;2318 segment.nsects += 1;
2277 seg_id.* = segment_id;2319 seg_id.* = segment_id;
2278 }2320 }
2279
2280 self.pagezero_seg_index = self.getSegmentByName("__PAGEZERO");
2281 self.text_seg_index = self.getSegmentByName("__TEXT").?;
2282 self.linkedit_seg_index = self.getSegmentByName("__LINKEDIT").?;
2283 self.zig_text_seg_index = self.getSegmentByName("__TEXT_ZIG");
2284 self.zig_got_seg_index = self.getSegmentByName("__GOT_ZIG");
2285 self.zig_const_seg_index = self.getSegmentByName("__CONST_ZIG");
2286 self.zig_data_seg_index = self.getSegmentByName("__DATA_ZIG");
2287 self.zig_bss_seg_index = self.getSegmentByName("__BSS_ZIG");
2288}2321}
22892322
2290fn allocateSections(self: *MachO) !void {2323fn allocateSections(self: *MachO) !void {
...@@ -2299,8 +2332,8 @@ fn allocateSections(self: *MachO) !void {...@@ -2299,8 +2332,8 @@ fn allocateSections(self: *MachO) !void {
22992332
2300 const page_size = self.getPageSize();2333 const page_size = self.getPageSize();
2301 const slice = self.sections.slice();2334 const slice = self.sections.slice();
2302 const last_index = for (slice.items(.header), 0..) |header, i| {2335 const last_index = for (0..slice.items(.header).len) |i| {
2303 if (mem.indexOf(u8, header.segName(), "ZIG")) |_| break i;2336 if (self.isZigSection(@intCast(i))) break i;
2304 } else slice.items(.header).len;2337 } else slice.items(.header).len;
23052338
2306 for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {2339 for (slice.items(.header)[0..last_index], slice.items(.segment_id)[0..last_index]) |*header, curr_seg_id| {
...@@ -2353,8 +2386,8 @@ fn allocateSections(self: *MachO) !void {...@@ -2353,8 +2386,8 @@ fn allocateSections(self: *MachO) !void {
2353/// We allocate segments in a separate step to also consider segments that have no sections.2386/// We allocate segments in a separate step to also consider segments that have no sections.
2354fn allocateSegments(self: *MachO) void {2387fn allocateSegments(self: *MachO) void {
2355 const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0;2388 const first_index = if (self.pagezero_seg_index) |index| index + 1 else 0;
2356 const last_index = for (self.segments.items, 0..) |seg, i| {2389 const last_index = for (0..self.segments.items.len) |i| {
2357 if (mem.indexOf(u8, seg.segName(), "ZIG")) |_| break i;2390 if (self.isZigSegment(@intCast(i))) break i;
2358 } else self.segments.items.len;2391 } else self.segments.items.len;
23592392
2360 var vmaddr: u64 = if (self.pagezero_seg_index) |index|2393 var vmaddr: u64 = if (self.pagezero_seg_index) |index|
...@@ -3622,6 +3655,36 @@ inline fn requiresThunks(self: MachO) bool {...@@ -3622,6 +3655,36 @@ inline fn requiresThunks(self: MachO) bool {
3622 return self.getTarget().cpu.arch == .aarch64;3655 return self.getTarget().cpu.arch == .aarch64;
3623}3656}
36243657
3658pub fn isZigSegment(self: MachO, seg_id: u8) bool {
3659 inline for (&[_]?u8{
3660 self.zig_text_seg_index,
3661 self.zig_got_seg_index,
3662 self.zig_const_seg_index,
3663 self.zig_data_seg_index,
3664 self.zig_bss_seg_index,
3665 }) |maybe_index| {
3666 if (maybe_index) |index| {
3667 if (index == seg_id) return true;
3668 }
3669 }
3670 return false;
3671}
3672
3673pub fn isZigSection(self: MachO, sect_id: u8) bool {
3674 inline for (&[_]?u8{
3675 self.zig_text_sect_index,
3676 self.zig_got_sect_index,
3677 self.zig_const_sect_index,
3678 self.zig_data_sect_index,
3679 self.zig_bss_sect_index,
3680 }) |maybe_index| {
3681 if (maybe_index) |index| {
3682 if (index == sect_id) return true;
3683 }
3684 }
3685 return false;
3686}
3687
3625pub fn addSegment(self: *MachO, name: []const u8, opts: struct {3688pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
3626 vmaddr: u64 = 0,3689 vmaddr: u64 = 0,
3627 vmsize: u64 = 0,3690 vmsize: u64 = 0,
src/link/MachO/Atom.zig+7-17
...@@ -119,16 +119,9 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk {...@@ -119,16 +119,9 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk {
119119
120pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {120pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {
121 const segname, const sectname, const flags = blk: {121 const segname, const sectname, const flags = blk: {
122 // Sanitize names produced by Zig self-hosted backends.122 const segname = sect.segName();
123 // TODO perhaps we simply should emit different names instead?123 const sectname = sect.sectName();
124 const segname = if (mem.indexOf(u8, sect.segName(), "_ZIG")) |idx|124
125 sect.segName()[0..idx]
126 else
127 sect.segName();
128 const sectname = if (mem.indexOf(u8, sect.sectName(), "_zig")) |idx|
129 sect.sectName()[0..idx]
130 else
131 sect.sectName();
132 if (sect.isCode()) break :blk .{125 if (sect.isCode()) break :blk .{
133 "__TEXT",126 "__TEXT",
134 sectname,127 sectname,
...@@ -150,22 +143,19 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {...@@ -150,22 +143,19 @@ pub fn initOutputSection(sect: macho.section_64, macho_file: *MachO) !u8 {
150143
151 macho.S_MOD_INIT_FUNC_POINTERS,144 macho.S_MOD_INIT_FUNC_POINTERS,
152 macho.S_MOD_TERM_FUNC_POINTERS,145 macho.S_MOD_TERM_FUNC_POINTERS,
146 macho.S_LITERAL_POINTERS,
153 => break :blk .{ "__DATA_CONST", sectname, sect.flags },147 => break :blk .{ "__DATA_CONST", sectname, sect.flags },
154148
155 macho.S_LITERAL_POINTERS,
156 macho.S_ZEROFILL,149 macho.S_ZEROFILL,
157 macho.S_GB_ZEROFILL,150 macho.S_GB_ZEROFILL,
158 macho.S_THREAD_LOCAL_VARIABLES,151 macho.S_THREAD_LOCAL_VARIABLES,
159 macho.S_THREAD_LOCAL_VARIABLE_POINTERS,152 macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
160 macho.S_THREAD_LOCAL_REGULAR,153 macho.S_THREAD_LOCAL_REGULAR,
161 macho.S_THREAD_LOCAL_ZEROFILL,154 macho.S_THREAD_LOCAL_ZEROFILL,
162 => break :blk .{ segname, sectname, sect.flags },155 => break :blk .{ "__DATA", sectname, sect.flags },
163156
164 macho.S_COALESCED => break :blk .{157 // TODO: do we need this check here?
165 segname,158 macho.S_COALESCED => break :blk .{ segname, sectname, macho.S_REGULAR },
166 sectname,
167 macho.S_REGULAR,
168 },
169159
170 macho.S_REGULAR => {160 macho.S_REGULAR => {
171 if (mem.eql(u8, segname, "__DATA")) {161 if (mem.eql(u8, segname, "__DATA")) {
src/link/MachO/relocatable.zig+7-7
...@@ -196,7 +196,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -196,7 +196,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
196 const atom = macho_file.getAtom(atom_index) orelse continue;196 const atom = macho_file.getAtom(atom_index) orelse continue;
197 if (!atom.flags.alive) continue;197 if (!atom.flags.alive) continue;
198 const header = &macho_file.sections.items(.header)[atom.out_n_sect];198 const header = &macho_file.sections.items(.header)[atom.out_n_sect];
199 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;199 if (!macho_file.isZigSection(atom.out_n_sect)) continue;
200 header.nreloc += atom.calcNumRelocs(macho_file);200 header.nreloc += atom.calcNumRelocs(macho_file);
201 }201 }
202 }202 }
...@@ -231,8 +231,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {...@@ -231,8 +231,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
231fn allocateSections(macho_file: *MachO) !void {231fn allocateSections(macho_file: *MachO) !void {
232 const slice = macho_file.sections.slice();232 const slice = macho_file.sections.slice();
233233
234 const last_index = for (slice.items(.header), 0..) |header, i| {234 const last_index = for (0..slice.items(.header).len) |i| {
235 if (mem.indexOf(u8, header.segName(), "ZIG")) |_| break i;235 if (macho_file.isZigSection(@intCast(i))) break i;
236 } else slice.items(.header).len;236 } else slice.items(.header).len;
237237
238 for (slice.items(.header)[0..last_index]) |*header| {238 for (slice.items(.header)[0..last_index]) |*header| {
...@@ -305,10 +305,10 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -305,10 +305,10 @@ fn writeAtoms(macho_file: *MachO) !void {
305 const cpu_arch = macho_file.getTarget().cpu.arch;305 const cpu_arch = macho_file.getTarget().cpu.arch;
306 const slice = macho_file.sections.slice();306 const slice = macho_file.sections.slice();
307307
308 for (slice.items(.header), slice.items(.atoms)) |header, atoms| {308 for (slice.items(.header), slice.items(.atoms), 0..) |header, atoms, i| {
309 if (atoms.items.len == 0) continue;309 if (atoms.items.len == 0) continue;
310 if (header.isZerofill()) continue;310 if (header.isZerofill()) continue;
311 if (mem.indexOf(u8, header.segName(), "ZIG") != null) continue;311 if (macho_file.isZigSection(@intCast(i))) continue;
312312
313 const size = math.cast(usize, header.size) orelse return error.Overflow;313 const size = math.cast(usize, header.size) orelse return error.Overflow;
314 const code = try gpa.alloc(u8, size);314 const code = try gpa.alloc(u8, size);
...@@ -349,7 +349,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -349,7 +349,7 @@ fn writeAtoms(macho_file: *MachO) !void {
349349
350 for (macho_file.sections.items(.header), 0..) |header, n_sect| {350 for (macho_file.sections.items(.header), 0..) |header, n_sect| {
351 if (header.isZerofill()) continue;351 if (header.isZerofill()) continue;
352 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;352 if (!macho_file.isZigSection(@intCast(n_sect))) continue;
353 const gop = try relocs.getOrPut(@intCast(n_sect));353 const gop = try relocs.getOrPut(@intCast(n_sect));
354 if (gop.found_existing) continue;354 if (gop.found_existing) continue;
355 gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);355 gop.value_ptr.* = try std.ArrayList(macho.relocation_info).initCapacity(gpa, header.nreloc);
...@@ -360,7 +360,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -360,7 +360,7 @@ fn writeAtoms(macho_file: *MachO) !void {
360 if (!atom.flags.alive) continue;360 if (!atom.flags.alive) continue;
361 const header = macho_file.sections.items(.header)[atom.out_n_sect];361 const header = macho_file.sections.items(.header)[atom.out_n_sect];
362 if (header.isZerofill()) continue;362 if (header.isZerofill()) continue;
363 if (mem.indexOf(u8, header.segName(), "ZIG") == null) continue;363 if (!macho_file.isZigSection(atom.out_n_sect)) continue;
364 if (atom.getRelocs(macho_file).len == 0) continue;364 if (atom.getRelocs(macho_file).len == 0) continue;
365 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;365 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
366 const code = try gpa.alloc(u8, atom_size);366 const code = try gpa.alloc(u8, atom_size);