authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-22 11:17:43+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 18:56:41+02:00
log1ff3ebffa36a6d8f0b2489b7cbb0aceaf9189064
treeeeb649e3eaa376a5bc2cf4b10809dd315c042489
parent0736365fa45fe4f3649a98a63fa82ccf8fc70d40

zld: handle dynamic binding of proxies for objc correctly


2 files changed, 49 insertions(+), 1 deletions(-)

src/link/MachO/Symbol.zig+5
...@@ -85,6 +85,11 @@ pub const Regular = struct {...@@ -85,6 +85,11 @@ pub const Regular = struct {
85pub const Proxy = struct {85pub const Proxy = struct {
86 base: Symbol,86 base: Symbol,
8787
88 bind_info: std.ArrayListUnmanaged(struct {
89 segment_id: u16,
90 address: u64,
91 }) = .{},
92
88 /// Dylib or stub where to locate this symbol.93 /// Dylib or stub where to locate this symbol.
89 /// null means self-reference.94 /// null means self-reference.
90 file: ?union(enum) {95 file: ?union(enum) {
src/link/MachO/Zld.zig+44-1
...@@ -263,6 +263,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -263,6 +263,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
263 self.allocateLinkeditSegment();263 self.allocateLinkeditSegment();
264 try self.allocateSymbols();264 try self.allocateSymbols();
265 try self.allocateTentativeSymbols();265 try self.allocateTentativeSymbols();
266 try self.allocateProxiesBindAddresses();
266 try self.flush();267 try self.flush();
267}268}
268269
...@@ -1346,6 +1347,30 @@ fn allocateTentativeSymbols(self: *Zld) !void {...@@ -1346,6 +1347,30 @@ fn allocateTentativeSymbols(self: *Zld) !void {
1346 }1347 }
1347}1348}
13481349
1350fn allocateProxiesBindAddresses(self: *Zld) !void {
1351 for (self.objects.items) |object| {
1352 for (object.sections.items) |sect| {
1353 const relocs = sect.relocs orelse continue;
1354
1355 for (relocs) |rel| {
1356 if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased
1357 if (rel.target != .symbol) continue;
1358
1359 const sym = rel.target.symbol.getTopmostAlias();
1360 if (sym.cast(Symbol.Proxy)) |proxy| {
1361 const target_map = sect.target_map orelse continue;
1362 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1363 const target_sect = target_seg.sections.items[target_map.section_id];
1364 try proxy.bind_info.append(self.allocator, .{
1365 .segment_id = target_map.segment_id,
1366 .address = target_sect.addr + target_map.offset + rel.offset,
1367 });
1368 }
1369 }
1370 }
1371 }
1372}
1373
1349fn writeStubHelperCommon(self: *Zld) !void {1374fn writeStubHelperCommon(self: *Zld) !void {
1350 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1375 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1351 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];1376 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
...@@ -1863,6 +1888,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {...@@ -1863,6 +1888,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
1863 const relocs = sect.relocs orelse continue;1888 const relocs = sect.relocs orelse continue;
1864 for (relocs) |rel| {1889 for (relocs) |rel| {
1865 switch (rel.@"type") {1890 switch (rel.@"type") {
1891 .unsigned => continue,
1866 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {1892 .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
1867 const sym = rel.target.symbol.getTopmostAlias();1893 const sym = rel.target.symbol.getTopmostAlias();
1868 if (sym.got_index != null) continue;1894 if (sym.got_index != null) continue;
...@@ -2090,7 +2116,10 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T...@@ -2090,7 +2116,10 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T
2090 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2116 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2091 const stubs = segment.sections.items[self.stubs_section_index.?];2117 const stubs = segment.sections.items[self.stubs_section_index.?];
2092 const stubs_index = proxy.base.stubs_index orelse {2118 const stubs_index = proxy.base.stubs_index orelse {
2093 log.err("expected stubs index when relocating symbol '{s}'", .{final.name});2119 if (proxy.bind_info.items.len > 0) {
2120 break :blk 0; // Dynamically bound by dyld.
2121 }
2122 log.err("expected stubs index or dynamic bind address when relocating symbol '{s}'", .{final.name});
2094 log.err("this is an internal linker error", .{});2123 log.err("this is an internal linker error", .{});
2095 return error.FailedToResolveRelocationTarget;2124 return error.FailedToResolveRelocationTarget;
2096 };2125 };
...@@ -2640,6 +2669,20 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2640,6 +2669,20 @@ fn writeBindInfoTable(self: *Zld) !void {
2640 }2669 }
2641 }2670 }
26422671
2672 for (self.imports.values()) |sym| {
2673 if (sym.cast(Symbol.Proxy)) |proxy| {
2674 for (proxy.bind_info.items) |info| {
2675 const seg = self.load_commands.items[info.segment_id].Segment;
2676 try pointers.append(.{
2677 .offset = info.address - seg.inner.vmaddr,
2678 .segment_id = info.segment_id,
2679 .dylib_ordinal = proxy.dylibOrdinal(),
2680 .name = proxy.base.name,
2681 });
2682 }
2683 }
2684 }
2685
2643 if (self.tlv_section_index) |idx| {2686 if (self.tlv_section_index) |idx| {
2644 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;2687 const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2645 const sect = seg.sections.items[idx];2688 const sect = seg.sections.items[idx];