aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/Relocation.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-04-22 13:39:07 +0200
committerGitHub <noreply@github.com>2023-04-22 13:39:07 +0200
commitc4a63389e4eefb78c1ee2028047447094bb864dc (patch)
tree95edea0e36efa81c2a6ea8d0574feeb5ba90f25e /src/link/MachO/Relocation.zig
parent68e4a5784791f733774e161b72a283b69a75b0de (diff)
parent14dfbbc21365131c7ac85f08f543058f43fca0c2 (diff)
downloadzig-c4a63389e4eefb78c1ee2028047447094bb864dc.tar.gz
zig-c4a63389e4eefb78c1ee2028047447094bb864dc.zip
Merge pull request #15371 from ziglang/better-elf
link: make GOT (and other synthetic sections) handling common across linkers
Diffstat (limited to 'src/link/MachO/Relocation.zig')
-rw-r--r--src/link/MachO/Relocation.zig88
1 files changed, 66 insertions, 22 deletions
diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig
index 81340b1120..e511901009 100644
--- a/src/link/MachO/Relocation.zig
+++ b/src/link/MachO/Relocation.zig
@@ -15,7 +15,7 @@ pub const Type = enum {
got,
/// RIP-relative displacement
signed,
- /// RIP-relative displacement to GOT pointer to TLV thunk
+ /// RIP-relative displacement to a TLV thunk
tlv,
// aarch64
@@ -39,25 +39,35 @@ pub const Type = enum {
/// Returns true if and only if the reloc is dirty AND the target address is available.
pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
- _ = self.getTargetAtomIndex(macho_file) orelse return false;
+ const addr = self.getTargetBaseAddress(macho_file) orelse return false;
+ if (addr == 0) return false;
return self.dirty;
}
-pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
- return switch (self.type) {
- .got, .got_page, .got_pageoff => macho_file.got_table.getAtomIndex(macho_file, self.target),
+pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
+ switch (self.type) {
+ .got, .got_page, .got_pageoff => {
+ const got_index = macho_file.got_table.lookup.get(self.target) orelse return null;
+ const header = macho_file.sections.items(.header)[macho_file.got_section_index.?];
+ return header.addr + got_index * @sizeOf(u64);
+ },
.tlv => {
- const thunk_atom_index = macho_file.tlv_table.getAtomIndex(macho_file, self.target) orelse
- return null;
- const thunk_atom = macho_file.getAtom(thunk_atom_index);
- return macho_file.got_table.getAtomIndex(macho_file, thunk_atom.getSymbolWithLoc());
+ const atom_index = macho_file.tlv_table.get(self.target) orelse return null;
+ const atom = macho_file.getAtom(atom_index);
+ return atom.getSymbol(macho_file).n_value;
},
- .branch => if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index|
- index
- else
- macho_file.getAtomIndexForSymbol(self.target),
- else => macho_file.getAtomIndexForSymbol(self.target),
- };
+ .branch => {
+ if (macho_file.stub_table.lookup.get(self.target)) |index| {
+ const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];
+ return header.addr +
+ index * @import("stubs.zig").calcStubEntrySize(macho_file.base.options.target.cpu.arch);
+ }
+ const atom_index = macho_file.getAtomIndexForSymbol(self.target) orelse return null;
+ const atom = macho_file.getAtom(atom_index);
+ return atom.getSymbol(macho_file).n_value;
+ },
+ else => return macho_file.getSymbol(self.target).n_value,
+ }
}
pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {
@@ -66,17 +76,14 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
const source_sym = atom.getSymbol(macho_file);
const source_addr = source_sym.n_value + self.offset;
- const target_atom_index = self.getTargetAtomIndex(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
- const target_atom = macho_file.getAtom(target_atom_index);
-
+ const target_base_addr = self.getTargetBaseAddress(macho_file).?; // Oops, you didn't check if the relocation can be resolved with isResolvable().
const target_addr: i64 = switch (self.type) {
.tlv_initializer => blk: {
assert(self.addend == 0); // Addend here makes no sense.
const header = macho_file.sections.items(.header)[macho_file.thread_data_section_index.?];
- const target_sym = target_atom.getSymbol(macho_file);
- break :blk @intCast(i64, target_sym.n_value - header.addr);
+ break :blk @intCast(i64, target_base_addr - header.addr);
},
- else => @intCast(i64, target_atom.getSymbol(macho_file).n_value) + self.addend,
+ else => @intCast(i64, target_base_addr) + self.addend,
};
log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
@@ -189,11 +196,48 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
}
}
-inline fn isArithmeticOp(inst: *const [4]u8) bool {
+pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
const group_decode = @truncate(u5, inst[3]);
return ((group_decode >> 2) == 4);
}
+pub fn calcPcRelativeDisplacementX86(source_addr: u64, target_addr: u64, correction: u3) error{Overflow}!i32 {
+ const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr + 4 + correction);
+ return math.cast(i32, disp) orelse error.Overflow;
+}
+
+pub fn calcPcRelativeDisplacementArm64(source_addr: u64, target_addr: u64) error{Overflow}!i28 {
+ const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr);
+ return math.cast(i28, disp) orelse error.Overflow;
+}
+
+pub fn calcNumberOfPages(source_addr: u64, target_addr: u64) i21 {
+ const source_page = @intCast(i32, source_addr >> 12);
+ const target_page = @intCast(i32, target_addr >> 12);
+ const pages = @intCast(i21, target_page - source_page);
+ return pages;
+}
+
+pub const PageOffsetInstKind = enum {
+ arithmetic,
+ load_store_8,
+ load_store_16,
+ load_store_32,
+ load_store_64,
+ load_store_128,
+};
+
+pub fn calcPageOffset(target_addr: u64, kind: PageOffsetInstKind) !u12 {
+ const narrowed = @truncate(u12, target_addr);
+ return switch (kind) {
+ .arithmetic, .load_store_8 => narrowed,
+ .load_store_16 => try math.divExact(u12, narrowed, 2),
+ .load_store_32 => try math.divExact(u12, narrowed, 4),
+ .load_store_64 => try math.divExact(u12, narrowed, 8),
+ .load_store_128 => try math.divExact(u12, narrowed, 16),
+ };
+}
+
const Relocation = @This();
const std = @import("std");