diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-22 11:17:43 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-24 18:56:41 +0200 |
| commit | 1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064 (patch) | |
| tree | eeb649e3eaa376a5bc2cf4b10809dd315c042489 | |
| parent | 0736365fa45fe4f3649a98a63fa82ccf8fc70d40 (diff) | |
| download | zig-1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064.tar.gz zig-1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064.zip | |
zld: handle dynamic binding of proxies for objc correctly
| -rw-r--r-- | src/link/MachO/Symbol.zig | 5 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 45 |
2 files changed, 49 insertions, 1 deletions
diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 2286b1ea93..01fcd15984 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -85,6 +85,11 @@ pub const Regular = struct { pub const Proxy = struct { base: Symbol, + bind_info: std.ArrayListUnmanaged(struct { + segment_id: u16, + address: u64, + }) = .{}, + /// Dylib or stub where to locate this symbol. /// null means self-reference. file: ?union(enum) { diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 8a302ea06c..c229fe9742 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -263,6 +263,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L self.allocateLinkeditSegment(); try self.allocateSymbols(); try self.allocateTentativeSymbols(); + try self.allocateProxiesBindAddresses(); try self.flush(); } @@ -1346,6 +1347,30 @@ fn allocateTentativeSymbols(self: *Zld) !void { } } +fn allocateProxiesBindAddresses(self: *Zld) !void { + for (self.objects.items) |object| { + for (object.sections.items) |sect| { + const relocs = sect.relocs orelse continue; + + for (relocs) |rel| { + if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased + if (rel.target != .symbol) continue; + + const sym = rel.target.symbol.getTopmostAlias(); + if (sym.cast(Symbol.Proxy)) |proxy| { + const target_map = sect.target_map orelse continue; + const target_seg = self.load_commands.items[target_map.segment_id].Segment; + const target_sect = target_seg.sections.items[target_map.section_id]; + try proxy.bind_info.append(self.allocator, .{ + .segment_id = target_map.segment_id, + .address = target_sect.addr + target_map.offset + rel.offset, + }); + } + } + } + } +} + fn writeStubHelperCommon(self: *Zld) !void { const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; @@ -1863,6 +1888,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { const relocs = sect.relocs orelse continue; for (relocs) |rel| { switch (rel.@"type") { + .unsigned => continue, .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { const sym = rel.target.symbol.getTopmostAlias(); if (sym.got_index != null) continue; @@ -2090,7 +2116,10 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stubs = segment.sections.items[self.stubs_section_index.?]; const stubs_index = proxy.base.stubs_index orelse { - log.err("expected stubs index when relocating symbol '{s}'", .{final.name}); + if (proxy.bind_info.items.len > 0) { + break :blk 0; // Dynamically bound by dyld. + } + log.err("expected stubs index or dynamic bind address when relocating symbol '{s}'", .{final.name}); log.err("this is an internal linker error", .{}); return error.FailedToResolveRelocationTarget; }; @@ -2640,6 +2669,20 @@ fn writeBindInfoTable(self: *Zld) !void { } } + for (self.imports.values()) |sym| { + if (sym.cast(Symbol.Proxy)) |proxy| { + for (proxy.bind_info.items) |info| { + const seg = self.load_commands.items[info.segment_id].Segment; + try pointers.append(.{ + .offset = info.address - seg.inner.vmaddr, + .segment_id = info.segment_id, + .dylib_ordinal = proxy.dylibOrdinal(), + .name = proxy.base.name, + }); + } + } + } + if (self.tlv_section_index) |idx| { const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; const sect = seg.sections.items[idx]; |
