authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-23 13:49:43+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
log80b1041c21599f5d444373dd35eafe2dc68e3887
treea0f28058948aee386476be3da7e02183b78208dc
parent59fe3d447d8cdd5dda34d7a77459c2c6761857ea

stage2 macho: use RIP-relative for memory-set regs x86_64


2 files changed, 57 insertions(+), 4 deletions(-)

src/codegen.zig+23-4
...@@ -1683,11 +1683,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1683,11 +1683,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1683 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);1683 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
1684 switch (arch) {1684 switch (arch) {
1685 .x86_64 => {1685 .x86_64 => {
1686 // Here, we store the got address in %rax, and then call %rax
1687 // movabsq [addr], %rax
1688 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });1686 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
1689 // callq *%rax1687 // callq *%rax
1690 try self.code.ensureCapacity(self.code.items.len + 2);
1691 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });1688 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
1692 },1689 },
1693 .aarch64 => {1690 .aarch64 => {
...@@ -2766,7 +2763,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2766,7 +2763,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2766 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, R });2763 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, R });
2767 },2764 },
2768 .memory => |x| {2765 .memory => |x| {
2769 if (x <= math.maxInt(u32)) {2766 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
2767 // For MachO, the binary, with the exception of object files, has to be a PIE.
2768 // Therefore, we cannot load an absolute address.
2769 assert(x > math.maxInt(u32)); // 32bit direct addressing is not supported by MachO.
2770 // The plan here is to use RIP-relative addressing, but leaving the actual displacement
2771 // information empty (0-padded) and fixing it up later in the linker.
2772 try self.mod_fn.owner_decl.link.macho.addRipPosition(self.bin_file.allocator, .{
2773 .address = x,
2774 .start = self.code.items.len,
2775 .len = 7,
2776 });
2777 try self.code.ensureCapacity(self.code.items.len + 9);
2778 // leaq %r, [rip + disp]
2779 self.code.appendSliceAssumeCapacity(&[_]u8{
2780 0x48,
2781 0x8d,
2782 0x05 | (@as(u8, reg.id() & 0b111) << 3), // R
2783 0x0,
2784 0x0,
2785 0x0,
2786 0x0,
2787 });
2788 } else if (x <= math.maxInt(u32)) {
2770 // Moving from memory to a register is a variant of `8B /r`.2789 // Moving from memory to a register is a variant of `8B /r`.
2771 // Since we're using 64-bit moves, we require a REX.2790 // Since we're using 64-bit moves, we require a REX.
2772 // This variant also requires a SIB, as it would otherwise be RIP-relative.2791 // This variant also requires a SIB, as it would otherwise be RIP-relative.
src/link/MachO.zig+34
...@@ -214,10 +214,21 @@ pub const TextBlock = struct {...@@ -214,10 +214,21 @@ pub const TextBlock = struct {
214 /// Unlike in Elf, we need to store the size of this symbol as part of214 /// Unlike in Elf, we need to store the size of this symbol as part of
215 /// the TextBlock since macho.nlist_64 lacks this information.215 /// the TextBlock since macho.nlist_64 lacks this information.
216 size: u64,216 size: u64,
217 /// List of RIP-relative positions in the code
218 /// This is a table of all RIP-relative positions that will need fixups
219 /// after codegen when linker assigns addresses to GOT entries.
220 /// TODO handle freeing, shrinking and re-allocs
221 rip_positions: std.ArrayListUnmanaged(RipPosition) = .{},
217 /// Points to the previous and next neighbours222 /// Points to the previous and next neighbours
218 prev: ?*TextBlock,223 prev: ?*TextBlock,
219 next: ?*TextBlock,224 next: ?*TextBlock,
220225
226 pub const RipPosition = struct {
227 address: u64,
228 start: usize,
229 len: usize,
230 };
231
221 pub const empty = TextBlock{232 pub const empty = TextBlock{
222 .local_sym_index = 0,233 .local_sym_index = 0,
223 .offset_table_index = undefined,234 .offset_table_index = undefined,
...@@ -226,6 +237,15 @@ pub const TextBlock = struct {...@@ -226,6 +237,15 @@ pub const TextBlock = struct {
226 .next = null,237 .next = null,
227 };238 };
228239
240 pub fn addRipPosition(self: *TextBlock, alloc: *Allocator, rip: RipPosition) !void {
241 std.debug.print("text_block={}, rip={}\n", .{ self.local_sym_index, rip });
242 return self.rip_positions.append(alloc, rip);
243 }
244
245 fn deinit(self: *TextBlock, alloc: *Allocator) void {
246 self.rip_positions.deinit(alloc);
247 }
248
229 /// Returns how much room there is to grow in virtual address space.249 /// Returns how much room there is to grow in virtual address space.
230 /// File offset relocation happens transparently, so it is not included in250 /// File offset relocation happens transparently, so it is not included in
231 /// this calculation.251 /// this calculation.
...@@ -993,6 +1013,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -993,6 +1013,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
993 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);1013 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
994 }1014 }
9951015
1016 // Perform RIP-relative fixups (if any)
1017 const got_section = self.sections.items[self.got_section_index.?];
1018 for (decl.link.macho.rip_positions.items) |rip| {
1019 std.debug.print("rip={}\n", .{rip});
1020 const target_addr = rip.address;
1021 // const got_addr = got_section.addr + decl.link.macho.offset_table_index * @sizeOf(u64);
1022 const this_addr = symbol.n_value + rip.start;
1023 std.debug.print("target_addr=0x{x},this_addr=0x{x}\n", .{target_addr, this_addr});
1024 const displacement = @intCast(u32, target_addr - this_addr + rip.len);
1025 std.debug.print("displacement=0x{x}\n", .{displacement});
1026 var placeholder = code_buffer.items[rip.start + rip.len - @sizeOf(u32) ..][0..@sizeOf(u32)];
1027 mem.writeIntSliceLittle(u32, placeholder, displacement);
1028 }
1029
996 const text_section = self.sections.items[self.text_section_index.?];1030 const text_section = self.sections.items[self.text_section_index.?];
997 const section_offset = symbol.n_value - text_section.addr;1031 const section_offset = symbol.n_value - text_section.addr;
998 const file_offset = text_section.offset + section_offset;1032 const file_offset = text_section.offset + section_offset;