diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-22 10:29:58 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-06-24 18:56:33 +0200 |
| commit | 0736365fa45fe4f3649a98a63fa82ccf8fc70d40 (patch) | |
| tree | eb49de851ace7808d585a9b996f3f6322d8b2a55 /src/link | |
| parent | d1fcb998484c8dec6e931b51a89ce4b2999254f5 (diff) | |
| download | zig-0736365fa45fe4f3649a98a63fa82ccf8fc70d40.tar.gz zig-0736365fa45fe4f3649a98a63fa82ccf8fc70d40.zip | |
zld: fix finding pointers for rebasing
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/MachO/Zld.zig | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 31f1eef303..8a302ea06c 100644 --- a/src/link/MachO/Zld.zig +++ b/src/link/MachO/Zld.zig @@ -1948,29 +1948,52 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { args.source_target_sect_addr = source_sect.inner.addr; } - rebases: { - var hit: bool = false; - if (target_map.segment_id == self.data_segment_cmd_index.?) { - if (self.data_section_index) |index| { - if (index == target_map.section_id) hit = true; + const flags = @truncate(u8, target_sect.flags & 0xff); + const should_rebase = rebase: { + if (!unsigned.is_64bit) break :rebase false; + + // TODO actually, a check similar to what dyld is doing, that is, verifying + // that the segment is writable should be enough here. + const is_right_segment = blk: { + if (self.data_segment_cmd_index) |idx| { + if (target_map.segment_id == idx) { + break :blk true; + } } + if (self.data_const_segment_cmd_index) |idx| { + if (target_map.segment_id == idx) { + break :blk true; + } + } + break :blk false; + }; + + if (!is_right_segment) break :rebase false; + if (flags != macho.S_LITERAL_POINTERS and + flags != macho.S_REGULAR) + { + break :rebase false; } - if (target_map.segment_id == self.data_const_segment_cmd_index.?) { - if (self.data_const_section_index) |index| { - if (index == target_map.section_id) hit = true; + if (rel.target == .symbol) { + const final = rel.target.symbol.getTopmostAlias(); + if (final.cast(Symbol.Proxy)) |_| { + break :rebase false; } } - if (!hit) break :rebases; + break :rebase true; + }; + if (should_rebase) { try self.local_rebases.append(self.allocator, .{ .offset = source_addr - target_seg.inner.vmaddr, .segment_id = target_map.segment_id, }); } + // TLV is handled via a separate offset mechanism. // Calculate the offset to the initializer. - if (target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: { + if (flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: { // TODO we don't want to save offset to tlv_bootstrap if (mem.eql(u8, rel.target.symbol.name, "__tlv_bootstrap")) break :tlv; |
