aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-06-22 11:17:43 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-06-24 18:56:41 +0200
commit1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064 (patch)
treeeeb649e3eaa376a5bc2cf4b10809dd315c042489
parent0736365fa45fe4f3649a98a63fa82ccf8fc70d40 (diff)
downloadzig-1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064.tar.gz
zig-1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064.zip
zld: handle dynamic binding of proxies for objc correctly
-rw-r--r--src/link/MachO/Symbol.zig5
-rw-r--r--src/link/MachO/Zld.zig45
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];