authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-20 09:49:21+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-20 09:49:21+02:00
log792fd9c4a362f44f900007562504bfaceffbcc82
treed4071d2b3d23c45c0d1c6d4e0554734314f3e005
parent153e2317748cff7d59d2709f72fe8b22c14f2a7b

macho: extract logic for creating and tracking atoms into fn


1 files changed, 172 insertions(+), 72 deletions(-)

src/link/MachO.zig+172-72
...@@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
770770
771 for (self.pending_updates.items) |update| {771 for (self.pending_updates.items) |update| {
772 switch (update) {772 switch (update) {
773 .resolve_undef => |sym_index| {
774 const sym = &self.undefs.items[sym_index];
775 const sym_name = self.getString(sym.n_strx);
776 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
777
778 for (self.dylibs.items) |dylib, id| {
779 if (!dylib.symbols.contains(sym_name)) continue;
780
781 const dylib_id = @intCast(u16, id);
782 if (!self.referenced_dylibs.contains(dylib_id)) {
783 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
784 }
785
786 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
787 sym.n_type |= macho.N_EXT;
788 sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
789
790 break;
791 } else {
792 try still_pending.append(update);
793 log.warn("undefined reference to symbol '{s}'", .{sym_name});
794 // TODO self-reference for incremental means resolv.file == 0!
795 if (self.objects.items.len > 0) {
796 log.warn(" first referenced in '{s}'", .{self.objects.items[resolv.file].name});
797 }
798 }
799 },
800 .add_got_entry => return error.TODOAddGotEntryUpdate,
801 .add_stub_entry => |stub_index| {773 .add_stub_entry => |stub_index| {
802 try self.writeStub(stub_index);774 try self.writeStub(stub_index);
803 try self.writeStubInStubHelper(stub_index);775 try self.writeStubInStubHelper(stub_index);
...@@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
805 self.rebase_info_dirty = true;777 self.rebase_info_dirty = true;
806 self.lazy_binding_info_dirty = true;778 self.lazy_binding_info_dirty = true;
807 },779 },
780 else => unreachable,
808 }781 }
809 }782 }
810783
...@@ -856,6 +829,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -856,6 +829,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
856 defer tracy.end();829 defer tracy.end();
857830
858 try self.setEntryPoint();831 try self.setEntryPoint();
832 try self.writeTextBlocks();
859 try self.writeRebaseInfoTable();833 try self.writeRebaseInfoTable();
860 try self.writeBindInfoTable();834 try self.writeBindInfoTable();
861 try self.writeLazyBindInfoTable();835 try self.writeLazyBindInfoTable();
...@@ -1946,6 +1920,174 @@ fn writeTextBlocks(self: *MachO) !void {...@@ -1946,6 +1920,174 @@ fn writeTextBlocks(self: *MachO) !void {
1946 }1920 }
1947}1921}
19481922
1923fn createEmptyAtom(
1924 self: *MachO,
1925 match: MatchingSection,
1926 local_sym_index: u32,
1927 size: u64,
1928 alignment: u32,
1929) !*TextBlock {
1930 const code = try self.base.allocator.alloc(u8, size);
1931 defer self.base.allocator.free(code);
1932 mem.set(u8, code, 0);
1933
1934 const block = try self.base.allocator.create(TextBlock);
1935 errdefer self.base.allocator.destroy(block);
1936 block.* = TextBlock.empty;
1937 block.local_sym_index = local_sym_index;
1938 block.size = size;
1939 block.alignment = alignment;
1940 try block.code.appendSlice(self.base.allocator, code);
1941
1942 try self.managed_blocks.append(self.base.allocator, block);
1943
1944 // Update target section's metadata
1945 // TODO should we update segment's size here too?
1946 // How does it tie with incremental space allocs?
1947 const tseg = &self.load_commands.items[match.seg].Segment;
1948 const tsect = &tseg.sections.items[match.sect];
1949 const new_alignment = math.max(tsect.@"align", alignment);
1950 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
1951 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + size;
1952 tsect.size = new_size;
1953 tsect.@"align" = new_alignment;
1954
1955 if (self.blocks.getPtr(match)) |last| {
1956 last.*.next = block;
1957 block.prev = last.*;
1958 last.* = block;
1959 } else {
1960 try self.blocks.putNoClobber(self.base.allocator, match, block);
1961 }
1962
1963 return block;
1964}
1965
1966// fn createStubHelperPreambleAtom(self: *MachO) !void {
1967// switch (self.base.options.target.cpu.arch) {
1968// .x86_64 => {
1969// const code_size = 15;
1970// var code = try self.base.allocator.alloc(u8, code_size);
1971// errdefer self.base.allocator.free(code);
1972// // lea %r11, [rip + disp]
1973// code[0] = 0x4c;
1974// code[1] = 0x8d;
1975// code[2] = 0x1d;
1976// {
1977// const target_addr = data.addr + data.size - @sizeOf(u64);
1978// const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7);
1979// mem.writeIntLittle(u32, code[3..7], displacement);
1980// }
1981// // push %r11
1982// code[7] = 0x41;
1983// code[8] = 0x53;
1984// // jmp [rip + disp]
1985// code[9] = 0xff;
1986// code[10] = 0x25;
1987// {
1988// const got_index = self.got_entries_map.get(.{
1989// .where = .undef,
1990// .where_index = self.dyld_stub_binder_index.?,
1991// }) orelse unreachable;
1992// const addr = got.addr + got_index * @sizeOf(u64);
1993// const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);
1994// mem.writeIntLittle(u32, code[11..], displacement);
1995// }
1996// try self.base.file.?.pwriteAll(&code, stub_helper.offset);
1997// break :blk stub_helper.offset + code_size;
1998// },
1999// .aarch64 => {
2000// var code: [6 * @sizeOf(u32)]u8 = undefined;
2001// data_blk_outer: {
2002// const this_addr = stub_helper.addr;
2003// const target_addr = data.addr + data.size - @sizeOf(u64);
2004// data_blk: {
2005// const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk;
2006// // adr x17, disp
2007// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32());
2008// // nop
2009// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32());
2010// break :data_blk_outer;
2011// }
2012// data_blk: {
2013// const new_this_addr = this_addr + @sizeOf(u32);
2014// const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk;
2015// // nop
2016// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32());
2017// // adr x17, disp
2018// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32());
2019// break :data_blk_outer;
2020// }
2021// // Jump is too big, replace adr with adrp and add.
2022// const this_page = @intCast(i32, this_addr >> 12);
2023// const target_page = @intCast(i32, target_addr >> 12);
2024// const pages = @intCast(i21, target_page - this_page);
2025// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32());
2026// const narrowed = @truncate(u12, target_addr);
2027// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32());
2028// }
2029// // stp x16, x17, [sp, #-16]!
2030// code[8] = 0xf0;
2031// code[9] = 0x47;
2032// code[10] = 0xbf;
2033// code[11] = 0xa9;
2034// binder_blk_outer: {
2035// const got_index = self.got_entries_map.get(.{
2036// .where = .undef,
2037// .where_index = self.dyld_stub_binder_index.?,
2038// }) orelse unreachable;
2039// const this_addr = stub_helper.addr + 3 * @sizeOf(u32);
2040// const target_addr = got.addr + got_index * @sizeOf(u64);
2041// binder_blk: {
2042// const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk;
2043// const literal = math.cast(u18, displacement) catch break :binder_blk;
2044// // ldr x16, label
2045// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{
2046// .literal = literal,
2047// }).toU32());
2048// // nop
2049// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32());
2050// break :binder_blk_outer;
2051// }
2052// binder_blk: {
2053// const new_this_addr = this_addr + @sizeOf(u32);
2054// const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk;
2055// const literal = math.cast(u18, displacement) catch break :binder_blk;
2056// // Pad with nop to please division.
2057// // nop
2058// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32());
2059// // ldr x16, label
2060// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{
2061// .literal = literal,
2062// }).toU32());
2063// break :binder_blk_outer;
2064// }
2065// // Use adrp followed by ldr(immediate).
2066// const this_page = @intCast(i32, this_addr >> 12);
2067// const target_page = @intCast(i32, target_addr >> 12);
2068// const pages = @intCast(i21, target_page - this_page);
2069// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32());
2070// const narrowed = @truncate(u12, target_addr);
2071// const offset = try math.divExact(u12, narrowed, 8);
2072// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{
2073// .register = .{
2074// .rn = .x16,
2075// .offset = aarch64.Instruction.LoadStoreOffset.imm(offset),
2076// },
2077// }).toU32());
2078// }
2079// // br x16
2080// code[20] = 0x00;
2081// code[21] = 0x02;
2082// code[22] = 0x1f;
2083// code[23] = 0xd6;
2084// try self.base.file.?.pwriteAll(&code, stub_helper.offset);
2085// break :blk stub_helper.offset + 6 * @sizeOf(u32);
2086// },
2087// else => unreachable,
2088// }
2089// }
2090
1949fn writeStubHelperPreamble(self: *MachO) !void {2091fn writeStubHelperPreamble(self: *MachO) !void {
1950 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;2092 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1951 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];2093 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
...@@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void {
2331 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);2473 _ = try self.section_ordinals.getOrPut(self.base.allocator, match);
23322474
2333 const size = sym.n_value;2475 const size = sym.n_value;
2334 const code = try self.base.allocator.alloc(u8, size);
2335 defer self.base.allocator.free(code);
2336 mem.set(u8, code, 0);
2337 const alignment = (sym.n_desc >> 8) & 0x0f;2476 const alignment = (sym.n_desc >> 8) & 0x0f;
23382477
2339 sym.n_value = 0;2478 sym.n_value = 0;
...@@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void {
2348 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;2487 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
2349 resolv.local_sym_index = local_sym_index;2488 resolv.local_sym_index = local_sym_index;
23502489
2351 const block = try self.base.allocator.create(TextBlock);2490 _ = try self.createEmptyAtom(match, local_sym_index, size, alignment);
2352 block.* = TextBlock.empty;
2353 block.local_sym_index = local_sym_index;
2354 block.size = size;
2355 block.alignment = alignment;
2356 try self.managed_blocks.append(self.base.allocator, block);
2357
2358 try block.code.appendSlice(self.base.allocator, code);
2359
2360 // Update target section's metadata
2361 // TODO should we update segment's size here too?
2362 // How does it tie with incremental space allocs?
2363 const tseg = &self.load_commands.items[match.seg].Segment;
2364 const tsect = &tseg.sections.items[match.sect];
2365 const new_alignment = math.max(tsect.@"align", block.alignment);
2366 const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
2367 const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
2368 tsect.size = new_size;
2369 tsect.@"align" = new_alignment;
2370
2371 if (self.blocks.getPtr(match)) |last| {
2372 last.*.next = block;
2373 block.prev = last.*;
2374 last.* = block;
2375 } else {
2376 try self.blocks.putNoClobber(self.base.allocator, match, block);
2377 }
2378 }2491 }
23792492
2380 // Third pass, resolve symbols in dynamic libraries.2493 // Third pass, resolve symbols in dynamic libraries.
...@@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void {
2449 // We create an empty atom for this symbol.2562 // We create an empty atom for this symbol.
2450 // TODO perhaps we should special-case special symbols? Create a separate2563 // TODO perhaps we should special-case special symbols? Create a separate
2451 // linked list of atoms?2564 // linked list of atoms?
2452 const block = try self.base.allocator.create(TextBlock);2565 _ = try self.createEmptyAtom(match, local_sym_index, 0, 0);
2453 block.* = TextBlock.empty;
2454 block.local_sym_index = local_sym_index;
2455 block.size = 0;
2456 block.alignment = 0;
2457 try self.managed_blocks.append(self.base.allocator, block);
2458
2459 if (self.blocks.getPtr(match)) |last| {
2460 last.*.next = block;
2461 block.prev = last.*;
2462 last.* = block;
2463 } else {
2464 try self.blocks.putNoClobber(self.base.allocator, match, block);
2465 }
2466 }2566 }
24672567
2468 for (self.unresolved.keys()) |index| {2568 for (self.unresolved.keys()) |index| {