| author | |
| committer | |
| log | ec874a9b2bf24bb37f1e90558153bbf04ac5f22a |
| tree | 2b8544cf3422b200cde70f9ced99f2207fa00f75 |
| parent | 0135b4665988530c0bd6b36ef7cb93ecaf999776 |
which is the source of binding rather than its target. That is,
we now track by source.3 files changed, 44 insertions(+), 48 deletions(-)
src/link/MachO/Symbol.zig+2-19| ... | @@ -121,20 +121,11 @@ pub const Tentative = struct { | ... | @@ -121,20 +121,11 @@ pub const Tentative = struct { |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | pub const Proxy = struct { | 123 | pub const Proxy = struct { |
| 124 | /// Dynamic binding info - spots within the final | ||
| 125 | /// executable where this proxy is referenced from. | ||
| 126 | bind_info: std.ArrayListUnmanaged(struct { | ||
| 127 | local_sym_index: u32, | ||
| 128 | offset: u32, | ||
| 129 | }) = .{}, | ||
| 130 | |||
| 131 | /// Dylib where to locate this symbol. | 124 | /// Dylib where to locate this symbol. |
| 132 | /// null means self-reference. | 125 | /// null means self-reference. |
| 133 | file: ?*Dylib = null, | 126 | file: ?*Dylib = null, |
| 134 | 127 | ||
| 135 | pub fn deinit(proxy: *Proxy, allocator: *Allocator) void { | 128 | local_sym_index: u32 = 0, |
| 136 | proxy.bind_info.deinit(allocator); | ||
| 137 | } | ||
| 138 | 129 | ||
| 139 | pub fn dylibOrdinal(proxy: Proxy) u16 { | 130 | pub fn dylibOrdinal(proxy: Proxy) u16 { |
| 140 | const dylib = proxy.file orelse return 0; | 131 | const dylib = proxy.file orelse return 0; |
| ... | @@ -145,13 +136,10 @@ pub const Proxy = struct { | ... | @@ -145,13 +136,10 @@ pub const Proxy = struct { |
| 145 | _ = fmt; | 136 | _ = fmt; |
| 146 | _ = options; | 137 | _ = options; |
| 147 | try std.fmt.format(writer, "Proxy {{ ", .{}); | 138 | try std.fmt.format(writer, "Proxy {{ ", .{}); |
| 148 | if (self.bind_info.items.len > 0) { | ||
| 149 | // TODO | ||
| 150 | try std.fmt.format(writer, ".bind_info = {}, ", .{self.bind_info.items.len}); | ||
| 151 | } | ||
| 152 | if (self.file) |file| { | 139 | if (self.file) |file| { |
| 153 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); | 140 | try std.fmt.format(writer, ".file = {s}, ", .{file.name.?}); |
| 154 | } | 141 | } |
| 142 | try std.fmt.format(writer, ".local_sym_index = {d}, ", .{self.local_sym_index}); | ||
| 155 | try std.fmt.format(writer, "}}", .{}); | 143 | try std.fmt.format(writer, "}}", .{}); |
| 156 | } | 144 | } |
| 157 | }; | 145 | }; |
| ... | @@ -284,11 +272,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { | ... | @@ -284,11 +272,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 { |
| 284 | 272 | ||
| 285 | pub fn deinit(symbol: *Symbol, allocator: *Allocator) void { | 273 | pub fn deinit(symbol: *Symbol, allocator: *Allocator) void { |
| 286 | allocator.free(symbol.name); | 274 | allocator.free(symbol.name); |
| 287 | |||
| 288 | switch (symbol.payload) { | ||
| 289 | .proxy => |*proxy| proxy.deinit(allocator), | ||
| 290 | else => {}, | ||
| 291 | } | ||
| 292 | } | 275 | } |
| 293 | 276 | ||
| 294 | pub fn isStab(sym: macho.nlist_64) bool { | 277 | pub fn isStab(sym: macho.nlist_64) bool { |
src/link/MachO/Zld.zig+37-15| ... | @@ -136,6 +136,7 @@ pub const TextBlock = struct { | ... | @@ -136,6 +136,7 @@ pub const TextBlock = struct { |
| 136 | size: u64, | 136 | size: u64, |
| 137 | alignment: u32, | 137 | alignment: u32, |
| 138 | rebases: std.ArrayList(u64), | 138 | rebases: std.ArrayList(u64), |
| 139 | bindings: std.ArrayList(SymbolAtOffset), | ||
| 139 | dices: std.ArrayList(macho.data_in_code_entry), | 140 | dices: std.ArrayList(macho.data_in_code_entry), |
| 140 | next: ?*TextBlock = null, | 141 | next: ?*TextBlock = null, |
| 141 | prev: ?*TextBlock = null, | 142 | prev: ?*TextBlock = null, |
| ... | @@ -226,6 +227,7 @@ pub const TextBlock = struct { | ... | @@ -226,6 +227,7 @@ pub const TextBlock = struct { |
| 226 | .size = undefined, | 227 | .size = undefined, |
| 227 | .alignment = undefined, | 228 | .alignment = undefined, |
| 228 | .rebases = std.ArrayList(u64).init(allocator), | 229 | .rebases = std.ArrayList(u64).init(allocator), |
| 230 | .bindings = std.ArrayList(SymbolAtOffset).init(allocator), | ||
| 229 | .dices = std.ArrayList(macho.data_in_code_entry).init(allocator), | 231 | .dices = std.ArrayList(macho.data_in_code_entry).init(allocator), |
| 230 | }; | 232 | }; |
| 231 | } | 233 | } |
| ... | @@ -239,6 +241,7 @@ pub const TextBlock = struct { | ... | @@ -239,6 +241,7 @@ pub const TextBlock = struct { |
| 239 | self.allocator.free(self.code); | 241 | self.allocator.free(self.code); |
| 240 | self.relocs.deinit(); | 242 | self.relocs.deinit(); |
| 241 | self.rebases.deinit(); | 243 | self.rebases.deinit(); |
| 244 | self.bindings.deinit(); | ||
| 242 | self.dices.deinit(); | 245 | self.dices.deinit(); |
| 243 | } | 246 | } |
| 244 | 247 | ||
| ... | @@ -293,6 +296,9 @@ pub const TextBlock = struct { | ... | @@ -293,6 +296,9 @@ pub const TextBlock = struct { |
| 293 | if (self.rebases.items.len > 0) { | 296 | if (self.rebases.items.len > 0) { |
| 294 | log.warn(" rebases: {any}", .{self.rebases.items}); | 297 | log.warn(" rebases: {any}", .{self.rebases.items}); |
| 295 | } | 298 | } |
| 299 | if (self.bindings.items.len > 0) { | ||
| 300 | log.warn(" bindings: {any}", .{self.bindings.items}); | ||
| 301 | } | ||
| 296 | if (self.dices.items.len > 0) { | 302 | if (self.dices.items.len > 0) { |
| 297 | log.warn(" dices: {any}", .{self.dices.items}); | 303 | log.warn(" dices: {any}", .{self.dices.items}); |
| 298 | } | 304 | } |
| ... | @@ -1745,9 +1751,11 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1745,9 +1751,11 @@ fn resolveSymbols(self: *Zld) !void { |
| 1745 | if (!dylib.symbols.contains(symbol.name)) continue; | 1751 | if (!dylib.symbols.contains(symbol.name)) continue; |
| 1746 | 1752 | ||
| 1747 | try referenced.put(dylib, {}); | 1753 | try referenced.put(dylib, {}); |
| 1754 | const index = @intCast(u32, self.imports.items.len); | ||
| 1748 | symbol.payload = .{ | 1755 | symbol.payload = .{ |
| 1749 | .proxy = .{ | 1756 | .proxy = .{ |
| 1750 | .file = dylib, | 1757 | .file = dylib, |
| 1758 | .local_sym_index = index, | ||
| 1751 | }, | 1759 | }, |
| 1752 | }; | 1760 | }; |
| 1753 | try self.imports.append(self.allocator, symbol); | 1761 | try self.imports.append(self.allocator, symbol); |
| ... | @@ -2341,23 +2349,37 @@ fn writeBindInfoTable(self: *Zld) !void { | ... | @@ -2341,23 +2349,37 @@ fn writeBindInfoTable(self: *Zld) !void { |
| 2341 | } | 2349 | } |
| 2342 | } | 2350 | } |
| 2343 | 2351 | ||
| 2344 | for (self.globals.values()) |sym| { | 2352 | { |
| 2345 | if (sym.payload != .proxy) continue; | 2353 | var it = self.blocks.iterator(); |
| 2354 | while (it.next()) |entry| { | ||
| 2355 | const match = entry.key_ptr.*; | ||
| 2356 | var block: *TextBlock = entry.value_ptr.*; | ||
| 2346 | 2357 | ||
| 2347 | const proxy = sym.payload.proxy; | 2358 | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 2348 | for (proxy.bind_info.items) |info| { | ||
| 2349 | const bind_sym = self.locals.items[info.local_sym_index]; | ||
| 2350 | assert(bind_sym.payload == .regular); | ||
| 2351 | const reg = bind_sym.payload.regular; | ||
| 2352 | const base_address = self.load_commands.items[reg.segment_id].Segment.inner.vmaddr; | ||
| 2353 | const offset = reg.address + info.offset - base_address; | ||
| 2354 | 2359 | ||
| 2355 | try pointers.append(.{ | 2360 | const seg = self.load_commands.items[match.seg].Segment; |
| 2356 | .offset = offset, | 2361 | |
| 2357 | .segment_id = reg.segment_id, | 2362 | while (true) { |
| 2358 | .dylib_ordinal = proxy.dylibOrdinal(), | 2363 | const sym = self.locals.items[block.local_sym_index]; |
| 2359 | .name = sym.name, | 2364 | assert(sym.payload == .regular); |
| 2360 | }); | 2365 | const base_offset = sym.payload.regular.address - seg.inner.vmaddr; |
| 2366 | |||
| 2367 | for (block.bindings.items) |binding| { | ||
| 2368 | const bind_sym = self.imports.items[binding.local_sym_index]; | ||
| 2369 | const proxy = bind_sym.payload.proxy; | ||
| 2370 | |||
| 2371 | try pointers.append(.{ | ||
| 2372 | .offset = binding.offset + base_offset, | ||
| 2373 | .segment_id = match.seg, | ||
| 2374 | .dylib_ordinal = proxy.dylibOrdinal(), | ||
| 2375 | .name = bind_sym.name, | ||
| 2376 | }); | ||
| 2377 | } | ||
| 2378 | |||
| 2379 | if (block.prev) |prev| { | ||
| 2380 | block = prev; | ||
| 2381 | } else break; | ||
| 2382 | } | ||
| 2361 | } | 2383 | } |
| 2362 | } | 2384 | } |
| 2363 | 2385 |
src/link/MachO/reloc.zig+5-14| ... | @@ -449,22 +449,13 @@ pub const Relocation = struct { | ... | @@ -449,22 +449,13 @@ pub const Relocation = struct { |
| 449 | .proxy => |proxy| { | 449 | .proxy => |proxy| { |
| 450 | if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) { | 450 | if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) { |
| 451 | break :blk 0; // Dynamically bound by dyld. | 451 | break :blk 0; // Dynamically bound by dyld. |
| 452 | // const segment = zld.load_commands.items[zld.data_segment_cmd_index.?].Segment; | ||
| 453 | // const tlv = segment.sections.items[zld.tlv_section_index.?]; | ||
| 454 | // break :blk tlv.addr; | ||
| 455 | } | 452 | } |
| 456 | 453 | ||
| 457 | const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; | 454 | const segment = zld.load_commands.items[zld.text_segment_cmd_index.?].Segment; |
| 458 | const stubs = segment.sections.items[zld.stubs_section_index.?]; | 455 | const stubs = segment.sections.items[zld.stubs_section_index.?]; |
| 459 | const stubs_index = self.target.stubs_index orelse { | 456 | const stubs_index = self.target.stubs_index orelse { |
| 460 | if (proxy.bind_info.items.len > 0) { | 457 | // TODO verify in TextBlock that the symbol is indeed dynamically bound. |
| 461 | break :blk 0; // Dynamically bound by dyld. | 458 | break :blk 0; // Dynamically bound by dyld. |
| 462 | } | ||
| 463 | log.err("expected stubs index or dynamic bind address for symbol '{s}'", .{ | ||
| 464 | self.target.name, | ||
| 465 | }); | ||
| 466 | log.err(" this is an internal linker error", .{}); | ||
| 467 | return error.FailedToResolveRelocationTarget; | ||
| 468 | }; | 459 | }; |
| 469 | break :blk stubs.addr + stubs_index * stubs.reserved2; | 460 | break :blk stubs.addr + stubs_index * stubs.reserved2; |
| 470 | }, | 461 | }, |
| ... | @@ -647,9 +638,9 @@ pub const Parser = struct { | ... | @@ -647,9 +638,9 @@ pub const Parser = struct { |
| 647 | } else if (out_rel.payload == .unsigned) { | 638 | } else if (out_rel.payload == .unsigned) { |
| 648 | const sym = out_rel.target; | 639 | const sym = out_rel.target; |
| 649 | switch (sym.payload) { | 640 | switch (sym.payload) { |
| 650 | .proxy => { | 641 | .proxy => |proxy| { |
| 651 | try sym.payload.proxy.bind_info.append(self.zld.allocator, .{ | 642 | try self.block.bindings.append(.{ |
| 652 | .local_sym_index = self.block.local_sym_index, | 643 | .local_sym_index = proxy.local_sym_index, |
| 653 | .offset = out_rel.offset, | 644 | .offset = out_rel.offset, |
| 654 | }); | 645 | }); |
| 655 | }, | 646 | }, |