aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2020-11-24 18:46:43 +0100
committerJakub Konka <kubkon@jakubkonka.com>2020-11-26 11:50:09 +0100
commitef5132c508f89ed8392143f6e8d03e8a2f121ba9 (patch)
tree350ef2bf4e2a78e2a4ba3c33c644c164d16e88c7 /src/codegen.zig
parent80b1041c21599f5d444373dd35eafe2dc68e3887 (diff)
downloadzig-ef5132c508f89ed8392143f6e8d03e8a2f121ba9.tar.gz
zig-ef5132c508f89ed8392143f6e8d03e8a2f121ba9.zip
stage2 macho: first, rough draft at trampolining
Diffstat (limited to 'src/codegen.zig')
-rw-r--r--src/codegen.zig63
1 files changed, 45 insertions, 18 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index 6cef7d8d0a..85b039069a 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -2767,24 +2767,51 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// 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,
- });
+ // The plan here is to use unconditional relative jump to GOT entry, where we store
+ // pre-calculated and stored effective address to load into the target register.
+ // We leave the actual displacement information empty (0-padded) and fixing it up
+ // later in the linker.
+ if (reg.id() == 0) { // %rax is special-cased
+ try self.code.ensureCapacity(self.code.items.len + 5);
+ try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
+ .address = x,
+ .start = self.code.items.len,
+ .len = 5,
+ });
+ // call [label]
+ self.code.appendSliceAssumeCapacity(&[_]u8{
+ 0xE8,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ });
+ } else {
+ try self.code.ensureCapacity(self.code.items.len + 10);
+ // push %rax
+ self.code.appendSliceAssumeCapacity(&[_]u8{0x50});
+ try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
+ .address = x,
+ .start = self.code.items.len,
+ .len = 5,
+ });
+ // call [label]
+ self.code.appendSliceAssumeCapacity(&[_]u8{
+ 0xE8,
+ 0x0,
+ 0x0,
+ 0x0,
+ 0x0,
+ });
+ // mov %r, %rax
+ self.code.appendSliceAssumeCapacity(&[_]u8{
+ 0x48,
+ 0x89,
+ 0xC0 | @as(u8, reg.id()),
+ });
+ // pop %rax
+ self.code.appendSliceAssumeCapacity(&[_]u8{0x58});
+ }
} 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.