diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-15 06:47:13 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-15 18:49:47 +0200 |
| commit | ec874a9b2bf24bb37f1e90558153bbf04ac5f22a (patch) | |
| tree | 2b8544cf3422b200cde70f9ced99f2207fa00f75 | |
| parent | 0135b4665988530c0bd6b36ef7cb93ecaf999776 (diff) | |
| download | zig-ec874a9b2bf24bb37f1e90558153bbf04ac5f22a.tar.gz zig-ec874a9b2bf24bb37f1e90558153bbf04ac5f22a.zip | |
zld: move tracking binding for proxies into TextBlock
which is the source of binding rather than its target. That is,
we now track by source.
| -rw-r--r-- | src/link/MachO/Symbol.zig | 21 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 52 | ||||
| -rw-r--r-- | src/link/MachO/reloc.zig | 19 |
3 files changed, 44 insertions, 48 deletions
diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 1c270e8510..28aee6eeb0 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -121,20 +121,11 @@ pub const Tentative = struct { }; pub const Proxy = struct { - /// Dynamic binding info - spots within the final - /// executable where this proxy is referenced from. - bind_info: std.ArrayListUnmanaged(struct { - local_sym_index: u32, - offset: u32, - }) = .{}, - /// Dylib where to locate this symbol. /// null means self-reference. file: ?*Dylib = null, - pub fn deinit(proxy: *Proxy, allocator: *Allocator) void { - proxy.bind_info.deinit(allocator); - } + local_sym_index: u32 = 0, pub fn dylibOrdinal(proxy: Proxy) u16 { const dylib = proxy.file orelse return 0; @@ -145,13 +136,10 @@ pub const Proxy = struct { _ = fmt; _ = options; try std.fmt.format(writer, "Proxy {{ ", .{}); - if (self.bind_info.items.len > 0) { - // TODO - try std.fmt.format(writer, ".bind_info = {}, ", .{self.bind_info.items.len}); - } if (self.file) |file| { try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); } + try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index}); try std.fmt.format(writer, "}}", .{}); } }; @@ -284,11 +272,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { pub fn deinit(symbol: *Symbol, allocator: *Allocator) void { allocator.free(symbol.name); - - switch (symbol.payload) { - .proxy => |*proxy| proxy.deinit(allocator), - else => {}, - } } pub fn isStab(sym: macho.nlist_64) bool { diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index ce08f6d82d..62e34cb6b0 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -136,6 +136,7 @@ pub const TextBlock = struct { size: u64, alignment: u32, rebases: std.ArrayList(u64), + bindings: std.ArrayList(SymbolAtOffset), dices: std.ArrayList(macho.data_in_code_entry), next: ?*TextBlock = null, prev: ?*TextBlock = null, @@ -226,6 +227,7 @@ pub const TextBlock = struct { .size = undefined, .alignment = undefined, .rebases = std.ArrayList(u64).init(allocator), + .bindings = std.ArrayList(SymbolAtOffset).init(allocator), .dices = std.ArrayList(macho.data_in_code_entry).init(allocator), }; } @@ -239,6 +241,7 @@ pub const TextBlock = struct { self.allocator.free(self.code); self.relocs.deinit(); self.rebases.deinit(); + self.bindings.deinit(); self.dices.deinit(); } @@ -293,6 +296,9 @@ pub const TextBlock = struct { if (self.rebases.items.len > 0) { log.warn(" rebases: {any}", .{self.rebases.items}); } + if (self.bindings.items.len > 0) { + log.warn(" bindings: {any}", .{self.bindings.items}); + } if (self.dices.items.len > 0) { log.warn(" dices: {any}", .{self.dices.items}); } @@ -1745,9 +1751,11 @@ fn resolveSymbols(self: *Zld) !void { if (!dylib.symbols.contains(symbol.name)) continue; try referenced.put(dylib, {}); + const index = @intCast(u32, self.imports.items.len); symbol.payload = .{ .proxy = .{ .file = dylib, + .local_sym_index = index, }, }; try self.imports.append(self.allocator, symbol); @@ -2341,23 +2349,37 @@ fn writeBindInfoTable(self: *Zld) !void { } } - for (self.globals.values()) |sym| { - if (sym.payload != .proxy) continue; + { + var it = self.blocks.iterator(); + while (it.next()) |entry| { + const match = entry.key_ptr.*; + var block: *TextBlock = entry.value_ptr.*; - const proxy = sym.payload.proxy; - for (proxy.bind_info.items) |info| { - const bind_sym = self.locals.items[info.local_sym_index]; - assert(bind_sym.payload == .regular); - const reg = bind_sym.payload.regular; - const base_address = self.load_commands.items[reg.segment_id].Segment.inner.vmaddr; - const offset = reg.address + info.offset - base_address; + if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable - try pointers.append(.{ - .offset = offset, - .segment_id = reg.segment_id, - .dylib_ordinal = proxy.dylibOrdinal(), - .name = sym.name, - }); + const seg = self.load_commands.items[match.seg].Segment; + + while (true) { + const sym = self.locals.items[block.local_sym_index]; + assert(sym.payload == .regular); + const base_offset = sym.payload.regular.address - seg.inner.vmaddr; + + for (block.bindings.items) |binding| { + const bind_sym = self.imports.items[binding.local_sym_index]; + const proxy = bind_sym.payload.proxy; + + try pointers.append(.{ + .offset = binding.offset + base_offset, + .segment_id = match.seg, + .dylib_ordinal = proxy.dylibOrdinal(), + .name = bind_sym.name, + }); + } + + if (block.prev) |prev| { + block = prev; + } else break; + } } } diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index d92d047cd9..c8b176c9c2 100644 --- a/src/link/MachO/reloc.zig +++ b/src/link/MachO/reloc.zig @@ -449,22 +449,13 @@ pub const Relocation = struct { .proxy => |proxy| { if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) { break :blk 0; // Dynamically bound by dyld. - // const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; - // const tlv = segment.sections.items[zld.tlv_section_index.?]; - // break :blk tlv.addr; } const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; const stubs = segment.sections.items[zld.stubs_section_index.?]; const stubs_index = self.target.stubs_index orelse { - if (proxy.bind_info.items.len > 0) { - break :blk 0; // Dynamically bound by dyld. - } - log.err("expected stubs index or dynamic bind address for symbol '{s}'", .{ - self.target.name, - }); - log.err(" this is an internal linker error", .{}); - return error.FailedToResolveRelocationTarget; + // TODO verify in TextBlock that the symbol is indeed dynamically bound. + break :blk 0; // Dynamically bound by dyld. }; break :blk stubs.addr + stubs_index * stubs.reserved2; }, @@ -647,9 +638,9 @@ pub const Parser = struct { } else if (out_rel.payload == .unsigned) { const sym = out_rel.target; switch (sym.payload) { - .proxy => { - try sym.payload.proxy.bind_info.append(self.zld.allocator, .{ - .local_sym_index = self.block.local_sym_index, + .proxy => |proxy| { + try self.block.bindings.append(.{ + .local_sym_index = proxy.local_sym_index, .offset = out_rel.offset, }); }, |
