| ... | ... | @@ -237,20 +237,19 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 237 | 237 | try self.allocateTentativeSymbols(); |
| 238 | 238 | try self.allocateProxyBindAddresses(); |
| 239 | 239 | |
| 240 | | log.warn("globals", .{}); |
| 241 | | for (self.globals.values()) |value| { |
| 242 | | log.warn(" | {s}: {}", .{ value.name, value.payload }); |
| 243 | | } |
| 244 | | |
| 245 | | for (self.objects.items) |object| { |
| 246 | | log.warn("object {s}", .{object.name.?}); |
| 247 | | for (object.symbols.items) |sym| { |
| 248 | | log.warn(" | {s}: {}", .{ sym.name, sym.payload }); |
| 249 | | } |
| 250 | | } |
| 251 | | |
| 252 | | return error.TODO; |
| 253 | | // try self.flush(); |
| 240 | // log.warn("globals", .{}); |
| 241 | // for (self.globals.values()) |value| { |
| 242 | // log.warn(" | {s}: {}", .{ value.name, value.payload }); |
| 243 | // } |
| 244 | |
| 245 | // for (self.objects.items) |object| { |
| 246 | // log.warn("object {s}", .{object.name.?}); |
| 247 | // for (object.symbols.items) |sym| { |
| 248 | // log.warn(" | {s}: {}", .{ sym.name, sym.payload }); |
| 249 | // } |
| 250 | // } |
| 251 | |
| 252 | try self.flush(); |
| 254 | 253 | } |
| 255 | 254 | |
| 256 | 255 | fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u8) !void { |
| ... | ... | @@ -1226,7 +1225,7 @@ fn writeStubHelperCommon(self: *Zld) !void { |
| 1226 | 1225 | code[9] = 0xff; |
| 1227 | 1226 | code[10] = 0x25; |
| 1228 | 1227 | { |
| 1229 | | const dyld_stub_binder = self.imports.get("dyld_stub_binder").?; |
| 1228 | const dyld_stub_binder = self.globals.get("dyld_stub_binder").?; |
| 1230 | 1229 | const addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64)); |
| 1231 | 1230 | const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); |
| 1232 | 1231 | mem.writeIntLittle(u32, code[11..], displacement); |
| ... | ... | @@ -1270,7 +1269,7 @@ fn writeStubHelperCommon(self: *Zld) !void { |
| 1270 | 1269 | code[10] = 0xbf; |
| 1271 | 1270 | code[11] = 0xa9; |
| 1272 | 1271 | binder_blk_outer: { |
| 1273 | | const dyld_stub_binder = self.imports.get("dyld_stub_binder").?; |
| 1272 | const dyld_stub_binder = self.globals.get("dyld_stub_binder").?; |
| 1274 | 1273 | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 1275 | 1274 | const target_addr = (got.addr + dyld_stub_binder.got_index.? * @sizeOf(u64)); |
| 1276 | 1275 | binder_blk: { |
| ... | ... | @@ -1789,8 +1788,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1789 | 1788 | break :rebase false; |
| 1790 | 1789 | } |
| 1791 | 1790 | if (rel.target == .symbol) { |
| 1792 | | const final = object.symbols.items[rel.target.symbol].getTopmostAlias(); |
| 1793 | | if (final.cast(Symbol.Proxy)) |_| { |
| 1791 | const sym = object.symbols.items[rel.target.symbol]; |
| 1792 | if (sym.payload == .proxy) { |
| 1794 | 1793 | break :rebase false; |
| 1795 | 1794 | } |
| 1796 | 1795 | } |
| ... | ... | @@ -1832,9 +1831,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1832 | 1831 | const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 1833 | 1832 | const got = dc_seg.sections.items[self.got_section_index.?]; |
| 1834 | 1833 | const sym = object.symbols.items[rel.target.symbol]; |
| 1835 | | const final = sym.getTopmostAlias(); |
| 1836 | | const got_index = final.got_index orelse { |
| 1837 | | log.err("expected GOT index relocating symbol '{s}'", .{final.name}); |
| 1834 | const got_index = sym.got_index orelse { |
| 1835 | log.err("expected GOT index relocating symbol '{s}'", .{sym.name}); |
| 1838 | 1836 | log.err("this is an internal linker error", .{}); |
| 1839 | 1837 | return error.FailedToResolveRelocationTarget; |
| 1840 | 1838 | }; |
| ... | ... | @@ -1890,37 +1888,40 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T |
| 1890 | 1888 | switch (target) { |
| 1891 | 1889 | .symbol => |sym_id| { |
| 1892 | 1890 | const sym = object.symbols.items[sym_id]; |
| 1893 | | const final = sym.getTopmostAlias(); |
| 1894 | | if (final.cast(Symbol.Regular)) |reg| { |
| 1895 | | log.debug(" | regular '{s}'", .{sym.name}); |
| 1896 | | break :blk reg.address; |
| 1897 | | } else if (final.cast(Symbol.Proxy)) |proxy| { |
| 1898 | | if (mem.eql(u8, sym.name, "__tlv_bootstrap")) { |
| 1899 | | log.debug(" | symbol '__tlv_bootstrap'", .{}); |
| 1900 | | const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1901 | | const tlv = segment.sections.items[self.tlv_section_index.?]; |
| 1902 | | break :blk tlv.addr; |
| 1903 | | } |
| 1904 | | |
| 1905 | | log.debug(" | symbol stub '{s}'", .{sym.name}); |
| 1906 | | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1907 | | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| 1908 | | const stubs_index = proxy.base.stubs_index orelse { |
| 1909 | | if (proxy.bind_info.items.len > 0) { |
| 1910 | | break :blk 0; // Dynamically bound by dyld. |
| 1891 | switch (sym.payload) { |
| 1892 | .regular => |reg| { |
| 1893 | log.debug(" | regular '{s}'", .{sym.name}); |
| 1894 | break :blk reg.address; |
| 1895 | }, |
| 1896 | .proxy => |proxy| { |
| 1897 | if (mem.eql(u8, sym.name, "__tlv_bootstrap")) { |
| 1898 | log.debug(" | symbol '__tlv_bootstrap'", .{}); |
| 1899 | const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1900 | const tlv = segment.sections.items[self.tlv_section_index.?]; |
| 1901 | break :blk tlv.addr; |
| 1911 | 1902 | } |
| 1912 | | log.err( |
| 1913 | | "expected stubs index or dynamic bind address when relocating symbol '{s}'", |
| 1914 | | .{final.name}, |
| 1915 | | ); |
| 1903 | |
| 1904 | log.debug(" | symbol stub '{s}'", .{sym.name}); |
| 1905 | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1906 | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| 1907 | const stubs_index = sym.stubs_index orelse { |
| 1908 | if (proxy.bind_info.items.len > 0) { |
| 1909 | break :blk 0; // Dynamically bound by dyld. |
| 1910 | } |
| 1911 | log.err( |
| 1912 | "expected stubs index or dynamic bind address when relocating symbol '{s}'", |
| 1913 | .{sym.name}, |
| 1914 | ); |
| 1915 | log.err("this is an internal linker error", .{}); |
| 1916 | return error.FailedToResolveRelocationTarget; |
| 1917 | }; |
| 1918 | break :blk stubs.addr + stubs_index * stubs.reserved2; |
| 1919 | }, |
| 1920 | else => { |
| 1921 | log.err("failed to resolve symbol '{s}' as a relocation target", .{sym.name}); |
| 1916 | 1922 | log.err("this is an internal linker error", .{}); |
| 1917 | 1923 | return error.FailedToResolveRelocationTarget; |
| 1918 | | }; |
| 1919 | | break :blk stubs.addr + stubs_index * stubs.reserved2; |
| 1920 | | } else { |
| 1921 | | log.err("failed to resolve symbol '{s}' as a relocation target", .{sym.name}); |
| 1922 | | log.err("this is an internal linker error", .{}); |
| 1923 | | return error.FailedToResolveRelocationTarget; |
| 1924 | }, |
| 1924 | 1925 | } |
| 1925 | 1926 | }, |
| 1926 | 1927 | .section => |sect_id| { |
| ... | ... | @@ -2320,8 +2321,8 @@ fn flush(self: *Zld) !void { |
| 2320 | 2321 | defer initializers.deinit(); |
| 2321 | 2322 | |
| 2322 | 2323 | for (self.objects.items) |object| { |
| 2323 | | for (object.initializers.items) |initializer| { |
| 2324 | | const address = initializer.cast(Symbol.Regular).?.address; |
| 2324 | for (object.initializers.items) |sym_id| { |
| 2325 | const address = object.symbols.items[sym_id].payload.regular.address; |
| 2325 | 2326 | try initializers.append(address); |
| 2326 | 2327 | } |
| 2327 | 2328 | } |
| ... | ... | @@ -2381,7 +2382,10 @@ fn writeGotEntries(self: *Zld) !void { |
| 2381 | 2382 | var writer = stream.writer(); |
| 2382 | 2383 | |
| 2383 | 2384 | for (self.got_entries.items) |sym| { |
| 2384 | | const address: u64 = if (sym.cast(Symbol.Regular)) |reg| reg.address else 0; |
| 2385 | const address: u64 = switch (sym.payload) { |
| 2386 | .regular => |reg| reg.address, |
| 2387 | else => 0, |
| 2388 | }; |
| 2385 | 2389 | try writer.writeIntLittle(u64, address); |
| 2386 | 2390 | } |
| 2387 | 2391 | |
| ... | ... | @@ -2397,9 +2401,8 @@ fn setEntryPoint(self: *Zld) !void { |
| 2397 | 2401 | // entrypoint. For now, assume default of `_main`. |
| 2398 | 2402 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2399 | 2403 | const sym = self.globals.get("_main") orelse return error.MissingMainEntrypoint; |
| 2400 | | const entry_sym = sym.cast(Symbol.Regular) orelse unreachable; |
| 2401 | 2404 | const ec = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 2402 | | ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr); |
| 2405 | ec.entryoff = @intCast(u32, sym.payload.regular.address - seg.inner.vmaddr); |
| 2403 | 2406 | ec.stacksize = self.stack_size; |
| 2404 | 2407 | } |
| 2405 | 2408 | |
| ... | ... | @@ -2417,7 +2420,8 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2417 | 2420 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2418 | 2421 | |
| 2419 | 2422 | for (self.got_entries.items) |sym| { |
| 2420 | | if (sym.@"type" == .proxy) continue; |
| 2423 | if (sym.payload == .proxy) continue; |
| 2424 | |
| 2421 | 2425 | try pointers.append(.{ |
| 2422 | 2426 | .offset = base_offset + sym.got_index.? * @sizeOf(u64), |
| 2423 | 2427 | .segment_id = segment_id, |
| ... | ... | @@ -2489,28 +2493,30 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2489 | 2493 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2490 | 2494 | |
| 2491 | 2495 | for (self.got_entries.items) |sym| { |
| 2492 | | if (sym.cast(Symbol.Proxy)) |proxy| { |
| 2493 | | try pointers.append(.{ |
| 2494 | | .offset = base_offset + proxy.base.got_index.? * @sizeOf(u64), |
| 2495 | | .segment_id = segment_id, |
| 2496 | | .dylib_ordinal = proxy.dylibOrdinal(), |
| 2497 | | .name = proxy.base.name, |
| 2498 | | }); |
| 2499 | | } |
| 2496 | if (sym.payload != .proxy) continue; |
| 2497 | |
| 2498 | const proxy = sym.payload.proxy; |
| 2499 | try pointers.append(.{ |
| 2500 | .offset = base_offset + sym.got_index.? * @sizeOf(u64), |
| 2501 | .segment_id = segment_id, |
| 2502 | .dylib_ordinal = proxy.dylibOrdinal(), |
| 2503 | .name = sym.name, |
| 2504 | }); |
| 2500 | 2505 | } |
| 2501 | 2506 | } |
| 2502 | 2507 | |
| 2503 | | for (self.imports.values()) |sym| { |
| 2504 | | if (sym.cast(Symbol.Proxy)) |proxy| { |
| 2505 | | for (proxy.bind_info.items) |info| { |
| 2506 | | const seg = self.load_commands.items[info.segment_id].Segment; |
| 2507 | | try pointers.append(.{ |
| 2508 | | .offset = info.address - seg.inner.vmaddr, |
| 2509 | | .segment_id = info.segment_id, |
| 2510 | | .dylib_ordinal = proxy.dylibOrdinal(), |
| 2511 | | .name = proxy.base.name, |
| 2512 | | }); |
| 2513 | | } |
| 2508 | for (self.globals.values()) |sym| { |
| 2509 | if (sym.payload != .proxy) continue; |
| 2510 | |
| 2511 | const proxy = sym.payload.proxy; |
| 2512 | for (proxy.bind_info.items) |info| { |
| 2513 | const seg = self.load_commands.items[info.segment_id].Segment; |
| 2514 | try pointers.append(.{ |
| 2515 | .offset = info.address - seg.inner.vmaddr, |
| 2516 | .segment_id = info.segment_id, |
| 2517 | .dylib_ordinal = proxy.dylibOrdinal(), |
| 2518 | .name = sym.name, |
| 2519 | }); |
| 2514 | 2520 | } |
| 2515 | 2521 | } |
| 2516 | 2522 | |
| ... | ... | @@ -2520,14 +2526,13 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2520 | 2526 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2521 | 2527 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 2522 | 2528 | |
| 2523 | | const sym = self.imports.get("__tlv_bootstrap") orelse unreachable; |
| 2524 | | const proxy = sym.cast(Symbol.Proxy) orelse unreachable; |
| 2525 | | |
| 2529 | const sym = self.globals.get("__tlv_bootstrap") orelse unreachable; |
| 2530 | const proxy = sym.payload.proxy; |
| 2526 | 2531 | try pointers.append(.{ |
| 2527 | 2532 | .offset = base_offset, |
| 2528 | 2533 | .segment_id = segment_id, |
| 2529 | 2534 | .dylib_ordinal = proxy.dylibOrdinal(), |
| 2530 | | .name = proxy.base.name, |
| 2535 | .name = sym.name, |
| 2531 | 2536 | }); |
| 2532 | 2537 | } |
| 2533 | 2538 | |
| ... | ... | @@ -2562,7 +2567,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void { |
| 2562 | 2567 | try pointers.ensureCapacity(self.stubs.items.len); |
| 2563 | 2568 | |
| 2564 | 2569 | for (self.stubs.items) |sym| { |
| 2565 | | const proxy = sym.cast(Symbol.Proxy) orelse unreachable; |
| 2570 | const proxy = sym.payload.proxy; |
| 2566 | 2571 | pointers.appendAssumeCapacity(.{ |
| 2567 | 2572 | .offset = base_offset + sym.stubs_index.? * @sizeOf(u64), |
| 2568 | 2573 | .segment_id = segment_id, |
| ... | ... | @@ -2676,7 +2681,8 @@ fn writeExportInfo(self: *Zld) !void { |
| 2676 | 2681 | defer sorted_globals.deinit(); |
| 2677 | 2682 | |
| 2678 | 2683 | for (self.globals.values()) |sym| { |
| 2679 | | const reg = sym.cast(Symbol.Regular) orelse continue; |
| 2684 | if (sym.payload != .regular) continue; |
| 2685 | const reg = sym.payload.regular; |
| 2680 | 2686 | if (reg.linkage != .global) continue; |
| 2681 | 2687 | try sorted_globals.append(sym.name); |
| 2682 | 2688 | } |
| ... | ... | @@ -2685,9 +2691,9 @@ fn writeExportInfo(self: *Zld) !void { |
| 2685 | 2691 | |
| 2686 | 2692 | for (sorted_globals.items) |sym_name| { |
| 2687 | 2693 | const sym = self.globals.get(sym_name) orelse unreachable; |
| 2688 | | const reg = sym.cast(Symbol.Regular) orelse unreachable; |
| 2694 | const reg = sym.payload.regular; |
| 2689 | 2695 | |
| 2690 | | log.debug(" | putting '{s}' defined at 0x{x}", .{ reg.base.name, reg.address }); |
| 2696 | log.debug(" | putting '{s}' defined at 0x{x}", .{ sym.name, reg.address }); |
| 2691 | 2697 | |
| 2692 | 2698 | try trie.put(.{ |
| 2693 | 2699 | .name = sym.name, |
| ... | ... | @@ -2722,50 +2728,33 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2722 | 2728 | |
| 2723 | 2729 | var locals = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2724 | 2730 | defer locals.deinit(); |
| 2731 | try locals.ensureTotalCapacity(self.locals.items.len); |
| 2732 | |
| 2733 | for (self.locals.items) |symbol| { |
| 2734 | if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist |
| 2735 | const nlist = try symbol.asNlist(&self.strtab); |
| 2736 | locals.appendAssumeCapacity(nlist); |
| 2737 | } |
| 2725 | 2738 | |
| 2726 | 2739 | var exports = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2727 | 2740 | defer exports.deinit(); |
| 2728 | 2741 | |
| 2729 | | for (self.objects.items) |object| { |
| 2730 | | for (object.stabs.items) |sym| { |
| 2731 | | const stab = sym.cast(Symbol.Stab) orelse unreachable; |
| 2732 | | |
| 2733 | | const nlists = try stab.asNlists(self.allocator, &self.strtab); |
| 2734 | | defer self.allocator.free(nlists); |
| 2735 | | |
| 2736 | | try locals.appendSlice(nlists); |
| 2737 | | } |
| 2738 | | |
| 2739 | | for (object.symbols.items) |sym| { |
| 2740 | | const final = sym.getTopmostAlias(); |
| 2741 | | if (final.@"type" != .regular) continue; |
| 2742 | | |
| 2743 | | const reg = final.cast(Symbol.Regular) orelse unreachable; |
| 2744 | | if (reg.isTemp()) continue; |
| 2745 | | if (reg.visited) continue; |
| 2746 | | |
| 2747 | | const nlist = try reg.asNlist(&self.strtab); |
| 2748 | | |
| 2749 | | switch (reg.linkage) { |
| 2750 | | .translation_unit => { |
| 2751 | | try locals.append(nlist); |
| 2752 | | }, |
| 2753 | | else => { |
| 2754 | | try exports.append(nlist); |
| 2755 | | }, |
| 2756 | | } |
| 2757 | | |
| 2758 | | reg.visited = true; |
| 2759 | | } |
| 2760 | | } |
| 2761 | | |
| 2762 | 2742 | var undefs = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2763 | 2743 | defer undefs.deinit(); |
| 2744 | var undef_dir = std.StringHashMap(u32).init(self.allocator); |
| 2745 | defer undef_dir.deinit(); |
| 2764 | 2746 | |
| 2765 | | for (self.imports.values()) |sym| { |
| 2766 | | const proxy = sym.cast(Symbol.Proxy) orelse unreachable; |
| 2767 | | const nlist = try proxy.asNlist(&self.strtab); |
| 2768 | | try undefs.append(nlist); |
| 2747 | for (self.globals.values()) |sym| { |
| 2748 | const nlist = try sym.asNlist(&self.strtab); |
| 2749 | switch (sym.payload) { |
| 2750 | .regular => try exports.append(nlist), |
| 2751 | .proxy => { |
| 2752 | const id = @intCast(u32, undefs.items.len); |
| 2753 | try undefs.append(nlist); |
| 2754 | try undef_dir.putNoClobber(sym.name, id); |
| 2755 | }, |
| 2756 | else => unreachable, |
| 2757 | } |
| 2769 | 2758 | } |
| 2770 | 2759 | |
| 2771 | 2760 | const nlocals = locals.items.len; |
| ... | ... | @@ -2827,24 +2816,27 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2827 | 2816 | |
| 2828 | 2817 | stubs.reserved1 = 0; |
| 2829 | 2818 | for (self.stubs.items) |sym| { |
| 2830 | | const id = self.imports.getIndex(sym.name) orelse unreachable; |
| 2831 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id)); |
| 2819 | const id = undef_dir.get(sym.name) orelse unreachable; |
| 2820 | try writer.writeIntLittle(u32, dysymtab.iundefsym + id); |
| 2832 | 2821 | } |
| 2833 | 2822 | |
| 2834 | 2823 | got.reserved1 = nstubs; |
| 2835 | 2824 | for (self.got_entries.items) |sym| { |
| 2836 | | if (sym.@"type" == .proxy) { |
| 2837 | | const id = self.imports.getIndex(sym.name) orelse unreachable; |
| 2838 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id)); |
| 2839 | | } else { |
| 2840 | | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2825 | switch (sym.payload) { |
| 2826 | .proxy => { |
| 2827 | const id = undef_dir.get(sym.name) orelse unreachable; |
| 2828 | try writer.writeIntLittle(u32, dysymtab.iundefsym + id); |
| 2829 | }, |
| 2830 | else => { |
| 2831 | try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL); |
| 2832 | }, |
| 2841 | 2833 | } |
| 2842 | 2834 | } |
| 2843 | 2835 | |
| 2844 | 2836 | la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; |
| 2845 | 2837 | for (self.stubs.items) |sym| { |
| 2846 | | const id = self.imports.getIndex(sym.name) orelse unreachable; |
| 2847 | | try writer.writeIntLittle(u32, dysymtab.iundefsym + @intCast(u32, id)); |
| 2838 | const id = undef_dir.get(sym.name) orelse unreachable; |
| 2839 | try writer.writeIntLittle(u32, dysymtab.iundefsym + id); |
| 2848 | 2840 | } |
| 2849 | 2841 | |
| 2850 | 2842 | try self.file.?.pwriteAll(buf, dysymtab.indirectsymoff); |