stage2 macho: use RIP-relative for memory-set regs x86_64
parent
59fe3d447d
commit
80b1041c21
|
@ -1683,11 +1683,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||
const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
|
||||
switch (arch) {
|
||||
.x86_64 => {
|
||||
// Here, we store the got address in %rax, and then call %rax
|
||||
// movabsq [addr], %rax
|
||||
try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
|
||||
// callq *%rax
|
||||
try self.code.ensureCapacity(self.code.items.len + 2);
|
||||
self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
|
||||
},
|
||||
.aarch64 => {
|
||||
|
@ -2766,7 +2763,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
|||
self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, R });
|
||||
},
|
||||
.memory => |x| {
|
||||
if (x <= math.maxInt(u32)) {
|
||||
if (self.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
// For MachO, the binary, with the exception of object files, has to be a PIE.
|
||||
// Therefore, we cannot load an absolute address.
|
||||
assert(x > math.maxInt(u32)); // 32bit direct addressing is not supported by MachO.
|
||||
// The plan here is to use RIP-relative addressing, but leaving the actual displacement
|
||||
// information empty (0-padded) and fixing it up later in the linker.
|
||||
try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
|
||||
.address = x,
|
||||
.start = self.code.items.len,
|
||||
.len = 7,
|
||||
});
|
||||
try self.code.ensureCapacity(self.code.items.len + 9);
|
||||
// leaq %r, [rip + disp]
|
||||
self.code.appendSliceAssumeCapacity(&[_]u8{
|
||||
0x48,
|
||||
0x8d,
|
||||
0x05 | (@as(u8, reg.id() & 0b111) << 3), // R
|
||||
0x0,
|
||||
0x0,
|
||||
0x0,
|
||||
0x0,
|
||||
});
|
||||
} else if (x <= math.maxInt(u32)) {
|
||||
// Moving from memory to a register is a variant of `8B /r`.
|
||||
// Since we're using 64-bit moves, we require a REX.
|
||||
// This variant also requires a SIB, as it would otherwise be RIP-relative.
|
||||
|
|
|
@ -214,10 +214,21 @@ pub const TextBlock = struct {
|
|||
/// Unlike in Elf, we need to store the size of this symbol as part of
|
||||
/// the TextBlock since macho.nlist_64 lacks this information.
|
||||
size: u64,
|
||||
/// List of RIP-relative positions in the code
|
||||
/// This is a table of all RIP-relative positions that will need fixups
|
||||
/// after codegen when linker assigns addresses to GOT entries.
|
||||
/// TODO handle freeing, shrinking and re-allocs
|
||||
rip_positions: std.ArrayListUnmanaged(RipPosition) = .{},
|
||||
/// Points to the previous and next neighbours
|
||||
prev: ?*TextBlock,
|
||||
next: ?*TextBlock,
|
||||
|
||||
pub const RipPosition = struct {
|
||||
address: u64,
|
||||
start: usize,
|
||||
len: usize,
|
||||
};
|
||||
|
||||
pub const empty = TextBlock{
|
||||
.local_sym_index = 0,
|
||||
.offset_table_index = undefined,
|
||||
|
@ -226,6 +237,15 @@ pub const TextBlock = struct {
|
|||
.next = null,
|
||||
};
|
||||
|
||||
pub fn addRipPosition(self: *TextBlock, alloc: *Allocator, rip: RipPosition) !void {
|
||||
std.debug.print("text_block={}, rip={}\n", .{ self.local_sym_index, rip });
|
||||
return self.rip_positions.append(alloc, rip);
|
||||
}
|
||||
|
||||
fn deinit(self: *TextBlock, alloc: *Allocator) void {
|
||||
self.rip_positions.deinit(alloc);
|
||||
}
|
||||
|
||||
/// Returns how much room there is to grow in virtual address space.
|
||||
/// File offset relocation happens transparently, so it is not included in
|
||||
/// this calculation.
|
||||
|
@ -993,6 +1013,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
|
|||
try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
|
||||
}
|
||||
|
||||
// Perform RIP-relative fixups (if any)
|
||||
const got_section = self.sections.items[self.got_section_index.?];
|
||||
for (decl.link.macho.rip_positions.items) |rip| {
|
||||
std.debug.print("rip={}\n", .{rip});
|
||||
const target_addr = rip.address;
|
||||
// const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64);
|
||||
const this_addr = symbol.n_value + rip.start;
|
||||
std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{target_addr, this_addr});
|
||||
const displacement = @intCast(u32, target_addr - this_addr + rip.len);
|
||||
std.debug.print("displacement=0x{x}\n", .{displacement});
|
||||
var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)];
|
||||
mem.writeIntSliceLittle(u32, placeholder, displacement);
|
||||
}
|
||||
|
||||
const text_section = self.sections.items[self.text_section_index.?];
|
||||
const section_offset = symbol.n_value - text_section.addr;
|
||||
const file_offset = text_section.offset + section_offset;
|
||||
|
|
Loading…
Reference in New Issue