macho: add relocations for GOT cells

in self-hosted compiler.
This commit is contained in:
Jakub Konka 2021-07-21 17:58:05 +02:00
parent 3bfde76cff
commit 845c906e6a
2 changed files with 37 additions and 72 deletions

View File

@ -2506,7 +2506,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
}) orelse unreachable;
break :blk got.addr + got_index * @sizeOf(u64);
};
log.debug("got_addr = 0x{x}", .{got_addr});
switch (arch) {
.x86_64 => {
try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .memory = got_addr });
@ -3864,19 +3863,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.memory => |addr| {
if (self.bin_file.options.pie) {
// PC-relative displacement to the entry in the GOT table.
// TODO we should come up with our own, backend independent relocation types
// which each backend (Elf, MachO, etc.) would then translate into an actual
// fixup when linking.
// adrp reg, pages
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
try macho_file.pie_fixups.append(self.bin_file.allocator, .{
.target_addr = addr,
.offset = self.code.items.len,
.size = 4,
});
} else {
return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
}
// adrp
const offset = @intCast(u32, self.code.items.len);
mem.writeIntLittle(
u32,
try self.code.addManyAsArray(4),
@ -3889,6 +3877,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.offset = Instruction.LoadStoreOffset.imm(0),
},
}).toU32());
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
const decl = macho_file.active_decl.?;
// Page reloc for adrp instruction.
try decl.link.macho.relocs.append(self.bin_file.allocator, .{
.offset = offset,
.where = .local,
.where_index = decl.link.macho.local_sym_index,
.payload = .{ .page = .{ .kind = .got } },
});
// Pageoff reloc for adrp instruction.
try decl.link.macho.relocs.append(self.bin_file.allocator, .{
.offset = offset + 4,
.where = .local,
.where_index = decl.link.macho.local_sym_index,
.payload = .{ .page_off = .{ .kind = .got } },
});
} else {
return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
}
} else {
// The value is in memory at a hard-coded address.
// If the type is a pointer, it means the pointer address is at this memory location.
@ -4128,6 +4136,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
const abi_size = ty.abiSize(self.target.*);
const encoder = try X8664Encoder.init(self.code, 10);
const offset = @intCast(u32, self.code.items.len);
// LEA reg, [<offset>]
// We encode the instruction FIRST because prefixes may or may not appear.
@ -4141,14 +4150,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
encoder.modRm_RIPDisp32(reg.low_id());
encoder.disp32(0);
// TODO we should come up with our own, backend independent relocation types
// which each backend (Elf, MachO, etc.) would then translate into an actual
// fixup when linking.
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
try macho_file.pie_fixups.append(self.bin_file.allocator, .{
.target_addr = x,
.offset = self.code.items.len - 4,
.size = 4,
const decl = macho_file.active_decl.?;
// Load reloc for LEA instruction.
try decl.link.macho.relocs.append(self.bin_file.allocator, .{
.offset = offset,
.where = .local,
.where_index = decl.link.macho.local_sym_index,
.payload = .{ .load = .{ .kind = .got } },
});
} else {
return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});

View File

@ -203,14 +203,11 @@ blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
/// TODO consolidate this.
decls: std.ArrayListUnmanaged(*Module.Decl) = .{},
/// A list of all PIE fixups required for this run of the linker.
/// Warning, this is currently NOT thread-safe. See the TODO below.
/// TODO Move this list inside `updateDecl` where it should be allocated
/// prior to calling `generateSymbol`, and then immediately deallocated
/// rather than sitting in the global scope.
/// TODO We should also rewrite this using generic relocations common to all
/// backends.
pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},
/// Currently active Module.Decl.
/// TODO this might not be necessary if we figure out how to pass Module.Decl instance
/// to codegen.genSetReg() or alterntively move PIE displacement for MCValue{ .memory = x }
/// somewhere else in the codegen.
active_decl: ?*Module.Decl = null,
const StringIndexContext = struct {
strtab: *std.ArrayListUnmanaged(u8),
@ -3279,7 +3276,6 @@ pub fn deinit(self: *MachO) void {
}
self.pending_updates.deinit(self.base.allocator);
self.pie_fixups.deinit(self.base.allocator);
self.got_entries.deinit(self.base.allocator);
self.got_entries_map.deinit(self.base.allocator);
self.got_entries_free_list.deinit(self.base.allocator);
@ -3497,6 +3493,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
}
}
self.active_decl = decl;
const res = if (debug_buffers) |*dbg|
try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
.ty = decl.ty,
@ -3522,8 +3520,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
break :blk decl.link.macho.code;
},
.fail => |em| {
// Clear any PIE fixups for this decl.
self.pie_fixups.shrinkRetainingCapacity(0);
decl.analysis = .codegen_failure;
try module.failed_decls.put(module.gpa, decl, em);
return;
@ -3600,46 +3596,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
try self.writeGotEntry(got_index);
}
// Calculate displacements to target addr (if any).
while (self.pie_fixups.popOrNull()) |fixup| {
assert(fixup.size == 4);
const this_addr = symbol.n_value + fixup.offset;
const target_addr = fixup.target_addr;
switch (self.base.options.target.cpu.arch) {
.x86_64 => {
const displacement = try math.cast(u32, target_addr - this_addr - 4);
mem.writeIntLittle(u32, decl.link.macho.code[fixup.offset..][0..4], displacement);
},
.aarch64 => {
// TODO optimize instruction based on jump length (use ldr(literal) + nop if possible).
{
const inst = decl.link.macho.code[fixup.offset..][0..4];
var parsed = mem.bytesAsValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.pc_relative_address,
), inst);
const this_page = @intCast(i32, this_addr >> 12);
const target_page = @intCast(i32, target_addr >> 12);
const pages = @bitCast(u21, @intCast(i21, target_page - this_page));
parsed.immhi = @truncate(u19, pages >> 2);
parsed.immlo = @truncate(u2, pages);
}
{
const inst = decl.link.macho.code[fixup.offset + 4 ..][0..4];
var parsed = mem.bytesAsValue(meta.TagPayload(
aarch64.Instruction,
aarch64.Instruction.load_store_register,
), inst);
const narrowed = @truncate(u12, target_addr);
const offset = try math.divExact(u12, narrowed, 8);
parsed.offset = offset;
}
},
else => unreachable, // unsupported target architecture
}
}
// Resolve relocations
try decl.link.macho.resolveRelocs(self);