authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-24 13:16:43+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-24 13:16:43+02:00
log8d300927045f3f2be3cc2eb6c665a7b17d81a655
tree0424d8d624b3de8e2a8e1b2745d79c516641b3e8
parent91c0552cfcb727dd6c2e6aa402112145993fac5b

macho: port stub and lazy ptr atoms to stage2


1 files changed, 115 insertions(+), 85 deletions(-)

src/link/MachO.zig+115-85
......@@ -138,7 +138,11 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
138138globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
139139undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},
140140symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{},
141unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
141unresolved: std.AutoArrayHashMapUnmanaged(u32, enum {
142 none,
143 stub,
144 got,
145}) = .{},
142146
143147locals_free_list: std.ArrayListUnmanaged(u32) = .{},
144148globals_free_list: std.ArrayListUnmanaged(u32) = .{},
......@@ -147,8 +151,6 @@ dyld_private_sym_index: ?u32 = null,
147151dyld_stub_binder_index: ?u32 = null,
148152stub_preamble_sym_index: ?u32 = null,
149153
150stub_helper_stubs_start_off: ?u64 = null,
151
152154strtab: std.ArrayListUnmanaged(u8) = .{},
153155strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
154156
......@@ -382,26 +384,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
382384 try ds.writeLocalSymbol(0);
383385 }
384386
385 {
386 const atom = try self.createDyldPrivateAtom();
387 const match = MatchingSection{
388 .seg = self.data_segment_cmd_index.?,
389 .sect = self.data_section_index.?,
390 };
391 const vaddr = try self.allocateAtom(atom, match);
392 try self.writeAtom(atom, match);
393 }
394
395 {
396 const atom = try self.createStubHelperPreambleAtom();
397 const match = MatchingSection{
398 .seg = self.text_segment_cmd_index.?,
399 .sect = self.stub_helper_section_index.?,
400 };
401 const vaddr = try self.allocateAtom(atom, match);
402 try self.writeAtom(atom, match);
403 }
404
405387 return self;
406388}
407389
......@@ -776,8 +758,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
776758
777759 try self.parseInputFiles(positionals.items, self.base.options.sysroot);
778760 try self.parseLibs(libs.items, self.base.options.sysroot);
761
779762 try self.resolveSymbols();
780 try self.resolveDyldStubBinder();
781763 try self.addRpathLCs(rpath_table.keys());
782764 try self.addLoadDylibLCs();
783765 try self.addDataInCodeLC();
......@@ -799,7 +781,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
799781 .seg = self.text_segment_cmd_index.?,
800782 .sect = self.stub_helper_section_index.?,
801783 });
802
803784 // TODO this is just a temp
804785 // We already prealloc stub helper size in populateMissingMetadata(), but
805786 // perhaps it's not needed after all?
......@@ -807,6 +788,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
807788 const sect = &seg.sections.items[self.stub_helper_section_index.?];
808789 sect.size -= atom.size;
809790 }
791
810792 for (self.stubs.items) |_| {
811793 const stub_helper_atom = try self.createStubHelperAtom();
812794 try self.allocateAtomStage1(stub_helper_atom, .{
......@@ -826,21 +808,12 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
826808 .sect = self.stubs_section_index.?,
827809 });
828810 }
811
829812 try self.allocateTextSegment();
830813 try self.allocateDataConstSegment();
831814 try self.allocateDataSegment();
832815 self.allocateLinkeditSegment();
833816 try self.allocateTextBlocks();
834 {
835 // TODO just a temp
836 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
837 const sect = seg.sections.items[self.stub_helper_section_index.?];
838 self.stub_helper_stubs_start_off = sect.offset + switch (self.base.options.target.cpu.arch) {
839 .x86_64 => @intCast(u64, 15),
840 .aarch64 => @intCast(u64, 6 * @sizeOf(u32)),
841 else => unreachable,
842 };
843 }
844817 try self.flushZld();
845818 } else {
846819 try self.flushModule(comp);
......@@ -1937,13 +1910,7 @@ fn writeTextBlocks(self: *MachO) !void {
19371910 }
19381911}
19391912
1940fn createEmptyAtom(
1941 self: *MachO,
1942 match: MatchingSection,
1943 local_sym_index: u32,
1944 size: u64,
1945 alignment: u32,
1946) !*TextBlock {
1913fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32) !*TextBlock {
19471914 const code = try self.base.allocator.alloc(u8, size);
19481915 defer self.base.allocator.free(code);
19491916 mem.set(u8, code, 0);
......@@ -1964,15 +1931,20 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
19641931 // TODO converge with `allocateTextBlock`
19651932 const seg = self.load_commands.items[match.seg].Segment;
19661933 const sect = seg.sections.items[match.sect];
1967 const base_addr = if (atom.prev) |prev| blk: {
1968 const prev_atom_sym = self.locals.items[prev.local_sym_index];
1969 break :blk prev_atom_sym.n_value;
1934 const sym = &self.locals.items[atom.local_sym_index];
1935 const base_addr = if (self.blocks.get(match)) |last| blk: {
1936 const last_atom_sym = self.locals.items[last.local_sym_index];
1937 break :blk last_atom_sym.n_value + last.size;
19701938 } else sect.addr;
19711939 const atom_alignment = try math.powi(u32, 2, atom.alignment);
19721940 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);
1941 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
19731942
19741943 // TODO we should check if we need to expand the section or not like we
19751944 // do in `allocateTextBlock`.
1945 sym.n_value = vaddr;
1946 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1947
19761948 if (self.blocks.getPtr(match)) |last| {
19771949 last.*.next = atom;
19781950 atom.prev = last.*;
......@@ -1987,15 +1959,9 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
19871959fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
19881960 const seg = self.load_commands.items[match.seg].Segment;
19891961 const sect = seg.sections.items[match.sect];
1990
1991 const vaddr = try self.allocateAtom(atom, match);
1992 const sym = &self.locals.items[atom.local_sym_index];
1993 sym.n_value = vaddr;
1994 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1995
1962 const sym = self.locals.items[atom.local_sym_index];
1963 const file_offset = sect.offset + sym.n_value - sect.addr;
19961964 try atom.resolveRelocs(self);
1997
1998 const file_offset = sect.offset + vaddr - sect.addr;
19991965 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset });
20001966 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
20011967 try self.writeLocalSymbol(atom.local_sym_index);
......@@ -2023,10 +1989,6 @@ fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !v
20231989}
20241990
20251991fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
2026 const match = MatchingSection{
2027 .seg = self.data_segment_cmd_index.?,
2028 .sect = self.data_section_index.?,
2029 };
20301992 const local_sym_index = @intCast(u32, self.locals.items.len);
20311993 try self.locals.append(self.base.allocator, .{
20321994 .n_strx = try self.makeString("dyld_private"),
......@@ -2036,15 +1998,11 @@ fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
20361998 .n_value = 0,
20371999 });
20382000 self.dyld_private_sym_index = local_sym_index;
2039 return self.createEmptyAtom(match, local_sym_index, @sizeOf(u64), 3);
2001 return self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3);
20402002}
20412003
20422004fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
20432005 const arch = self.base.options.target.cpu.arch;
2044 const match = MatchingSection{
2045 .seg = self.text_segment_cmd_index.?,
2046 .sect = self.stub_helper_section_index.?,
2047 };
20482006 const size: u64 = switch (arch) {
20492007 .x86_64 => 15,
20502008 .aarch64 => 6 * @sizeOf(u32),
......@@ -2063,7 +2021,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
20632021 .n_desc = 0,
20642022 .n_value = 0,
20652023 });
2066 const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment);
2024 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
20672025 switch (arch) {
20682026 .x86_64 => {
20692027 try atom.relocs.ensureUnusedCapacity(self.base.allocator, 2);
......@@ -2196,10 +2154,7 @@ fn createStubHelperAtom(self: *MachO) !*TextBlock {
21962154 .n_desc = 0,
21972155 .n_value = 0,
21982156 });
2199 const atom = try self.createEmptyAtom(.{
2200 .seg = self.text_segment_cmd_index.?,
2201 .sect = self.stub_helper_section_index.?,
2202 }, local_sym_index, stub_size, alignment);
2157 const atom = try self.createEmptyAtom(local_sym_index, stub_size, alignment);
22032158 try atom.relocs.ensureTotalCapacity(self.base.allocator, 1);
22042159
22052160 switch (arch) {
......@@ -2254,10 +2209,7 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32) !*TextBlock {
22542209 .n_desc = 0,
22552210 .n_value = 0,
22562211 });
2257 const atom = try self.createEmptyAtom(.{
2258 .seg = self.data_segment_cmd_index.?,
2259 .sect = self.la_symbol_ptr_section_index.?,
2260 }, local_sym_index, @sizeOf(u64), 3);
2212 const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), 3);
22612213 try atom.relocs.append(self.base.allocator, .{
22622214 .offset = 0,
22632215 .where = .local,
......@@ -2294,10 +2246,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
22942246 .n_desc = 0,
22952247 .n_value = 0,
22962248 });
2297 const atom = try self.createEmptyAtom(.{
2298 .seg = self.text_segment_cmd_index.?,
2299 .sect = self.stubs_section_index.?,
2300 }, local_sym_index, stub_size, alignment);
2249 const atom = try self.createEmptyAtom(local_sym_index, stub_size, alignment);
23012250 switch (arch) {
23022251 .x86_64 => {
23032252 // jmp
......@@ -2547,12 +2496,14 @@ fn resolveSymbolsInObject(
25472496 .where_index = undef_sym_index,
25482497 .file = object_id,
25492498 });
2550 _ = try self.unresolved.getOrPut(self.base.allocator, undef_sym_index);
2499 try self.unresolved.putNoClobber(self.base.allocator, undef_sym_index, .none);
25512500 }
25522501 }
25532502}
25542503
25552504fn resolveSymbols(self: *MachO) !void {
2505 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
2506
25562507 var tentatives = std.AutoArrayHashMap(u32, void).init(self.base.allocator);
25572508 defer tentatives.deinit();
25582509
......@@ -2620,7 +2571,32 @@ fn resolveSymbols(self: *MachO) !void {
26202571 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
26212572 resolv.local_sym_index = local_sym_index;
26222573
2623 _ = try self.createEmptyAtom(match, local_sym_index, size, alignment);
2574 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
2575 if (use_stage1) {
2576 try self.allocateAtomStage1(atom, match);
2577 }
2578 }
2579
2580 try self.resolveDyldStubBinder();
2581 if (!use_stage1) {
2582 {
2583 const atom = try self.createDyldPrivateAtom();
2584 const match = MatchingSection{
2585 .seg = self.data_segment_cmd_index.?,
2586 .sect = self.data_section_index.?,
2587 };
2588 _ = try self.allocateAtom(atom, match);
2589 try self.writeAtom(atom, match);
2590 }
2591 {
2592 const atom = try self.createStubHelperPreambleAtom();
2593 const match = MatchingSection{
2594 .seg = self.text_segment_cmd_index.?,
2595 .sect = self.stub_helper_section_index.?,
2596 };
2597 _ = try self.allocateAtom(atom, match);
2598 try self.writeAtom(atom, match);
2599 }
26242600 }
26252601
26262602 // Third pass, resolve symbols in dynamic libraries.
......@@ -2643,7 +2619,43 @@ fn resolveSymbols(self: *MachO) !void {
26432619 undef.n_type |= macho.N_EXT;
26442620 undef.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
26452621
2646 _ = self.unresolved.fetchSwapRemove(resolv.where_index);
2622 if (self.unresolved.fetchSwapRemove(resolv.where_index)) |entry| {
2623 switch (entry.value) {
2624 .none => {},
2625 .got => return error.TODOGotHint,
2626 .stub => {
2627 const stub_helper_atom = blk: {
2628 const atom = try self.createStubHelperAtom();
2629 const match = MatchingSection{
2630 .seg = self.text_segment_cmd_index.?,
2631 .sect = self.stub_helper_section_index.?,
2632 };
2633 _ = try self.allocateAtom(atom, match);
2634 try self.writeAtom(atom, match);
2635 break :blk atom;
2636 };
2637 const laptr_atom = blk: {
2638 const atom = try self.createLazyPointerAtom(stub_helper_atom.local_sym_index);
2639 const match = MatchingSection{
2640 .seg = self.data_segment_cmd_index.?,
2641 .sect = self.la_symbol_ptr_section_index.?,
2642 };
2643 _ = try self.allocateAtom(atom, match);
2644 try self.writeAtom(atom, match);
2645 break :blk atom;
2646 };
2647 {
2648 const atom = try self.createStubAtom(laptr_atom.local_sym_index);
2649 const match = MatchingSection{
2650 .seg = self.text_segment_cmd_index.?,
2651 .sect = self.stubs_section_index.?,
2652 };
2653 _ = try self.allocateAtom(atom, match);
2654 try self.writeAtom(atom, match);
2655 }
2656 },
2657 }
2658 }
26472659
26482660 continue :loop;
26492661 }
......@@ -2695,7 +2707,10 @@ fn resolveSymbols(self: *MachO) !void {
26952707 // We create an empty atom for this symbol.
26962708 // TODO perhaps we should special-case special symbols? Create a separate
26972709 // linked list of atoms?
2698 _ = try self.createEmptyAtom(match, local_sym_index, 0, 0);
2710 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2711 if (use_stage1) {
2712 try self.allocateAtomStage1(atom, match);
2713 }
26992714 }
27002715
27012716 for (self.unresolved.keys()) |index| {
......@@ -4554,14 +4569,12 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
45544569 .where = .undef,
45554570 .where_index = sym_index,
45564571 });
4557 _ = try self.unresolved.getOrPut(self.base.allocator, sym_index);
4572 try self.unresolved.putNoClobber(self.base.allocator, sym_index, .stub);
45584573
45594574 const stubs_index = @intCast(u32, self.stubs.items.len);
45604575 try self.stubs.append(self.base.allocator, sym_index);
45614576 try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index);
45624577
4563 // TODO create and write stub, stub_helper and lazy_ptr atoms
4564
45654578 return sym_index;
45664579}
45674580
......@@ -5271,7 +5284,11 @@ fn writeLazyBindInfoTable(self: *MachO) !void {
52715284}
52725285
52735286fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
5274 if (self.stubs.items.len == 0) return;
5287 const last_atom = self.blocks.get(.{
5288 .seg = self.text_segment_cmd_index.?,
5289 .sect = self.stub_helper_section_index.?,
5290 }) orelse return;
5291 if (last_atom.local_sym_index == self.stub_preamble_sym_index.?) return;
52755292
52765293 var stream = std.io.fixedBufferStream(buffer);
52775294 var reader = stream.reader();
......@@ -5316,7 +5333,6 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
53165333 else => {},
53175334 }
53185335 }
5319 assert(self.stubs.items.len <= offsets.items.len);
53205336
53215337 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
53225338 .x86_64 => 10,
......@@ -5329,8 +5345,22 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
53295345 else => unreachable,
53305346 };
53315347 var buf: [@sizeOf(u32)]u8 = undefined;
5348
5349 var first_atom = last_atom;
5350 while (first_atom.prev) |prev| {
5351 first_atom = prev;
5352 }
5353
5354 const start_off = blk: {
5355 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
5356 const sect = seg.sections.items[self.stub_helper_section_index.?];
5357 const sym = self.locals.items[first_atom.next.?.local_sym_index];
5358 break :blk sym.n_value - sect.addr + sect.offset;
5359 };
5360 log.warn("start_off = 0x{x}", .{start_off});
5361
53325362 for (self.stubs.items) |_, index| {
5333 const placeholder_off = self.stub_helper_stubs_start_off.? + index * stub_size + off;
5363 const placeholder_off = start_off + index * stub_size + off;
53345364 mem.writeIntLittle(u32, &buf, offsets.items[index]);
53355365 try self.base.file.?.pwriteAll(&buf, placeholder_off);
53365366 }