authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-21 17:58:05+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-21 17:58:05+02:00
log845c906e6a2ed9206840bd189d85bf9525687102
treec0e620efdcf386af5d459aacb05cb4e0183d2d87
parent3bfde76cff60a0d9c70d8e660dd633bed17a314f

macho: add relocations for GOT cells

in self-hosted compiler.

2 files changed, 37 insertions(+), 72 deletions(-)

src/codegen.zig+30-21
...@@ -2506,7 +2506,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2506,7 +2506,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2506 }) orelse unreachable;2506 }) orelse unreachable;
2507 break :blk got.addr + got_index * @sizeOf(u64);2507 break :blk got.addr + got_index * @sizeOf(u64);
2508 };2508 };
2509 log.debug("got_addr = 0x{x}", .{got_addr});
2510 switch (arch) {2509 switch (arch) {
2511 .x86_64 => {2510 .x86_64 => {
2512 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .memory = got_addr });2511 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 {...@@ -3864,19 +3863,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3864 .memory => |addr| {3863 .memory => |addr| {
3865 if (self.bin_file.options.pie) {3864 if (self.bin_file.options.pie) {
3866 // PC-relative displacement to the entry in the GOT table.3865 // PC-relative displacement to the entry in the GOT table.
3867 // TODO we should come up with our own, backend independent relocation types3866 // adrp
3868 // which each backend (Elf, MachO, etc.) would then translate into an actual3867 const offset = @intCast(u32, self.code.items.len);
3869 // fixup when linking.
3870 // adrp reg, pages
3871 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
3872 try macho_file.pie_fixups.append(self.bin_file.allocator, .{
3873 .target_addr = addr,
3874 .offset = self.code.items.len,
3875 .size = 4,
3876 });
3877 } else {
3878 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
3879 }
3880 mem.writeIntLittle(3868 mem.writeIntLittle(
3881 u32,3869 u32,
3882 try self.code.addManyAsArray(4),3870 try self.code.addManyAsArray(4),
...@@ -3889,6 +3877,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3889,6 +3877,26 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3889 .offset = Instruction.LoadStoreOffset.imm(0),3877 .offset = Instruction.LoadStoreOffset.imm(0),
3890 },3878 },
3891 }).toU32());3879 }).toU32());
3880
3881 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
3882 const decl = macho_file.active_decl.?;
3883 // Page reloc for adrp instruction.
3884 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
3885 .offset = offset,
3886 .where = .local,
3887 .where_index = decl.link.macho.local_sym_index,
3888 .payload = .{ .page = .{ .kind = .got } },
3889 });
3890 // Pageoff reloc for adrp instruction.
3891 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
3892 .offset = offset + 4,
3893 .where = .local,
3894 .where_index = decl.link.macho.local_sym_index,
3895 .payload = .{ .page_off = .{ .kind = .got } },
3896 });
3897 } else {
3898 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
3899 }
3892 } else {3900 } else {
3893 // The value is in memory at a hard-coded address.3901 // The value is in memory at a hard-coded address.
3894 // If the type is a pointer, it means the pointer address is at this memory location.3902 // 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 {...@@ -4128,6 +4136,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4128 const abi_size = ty.abiSize(self.target.*);4136 const abi_size = ty.abiSize(self.target.*);
4129 const encoder = try X8664Encoder.init(self.code, 10);4137 const encoder = try X8664Encoder.init(self.code, 10);
41304138
4139 const offset = @intCast(u32, self.code.items.len);
4131 // LEA reg, [<offset>]4140 // LEA reg, [<offset>]
41324141
4133 // We encode the instruction FIRST because prefixes may or may not appear.4142 // 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 {...@@ -4141,14 +4150,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4141 encoder.modRm_RIPDisp32(reg.low_id());4150 encoder.modRm_RIPDisp32(reg.low_id());
4142 encoder.disp32(0);4151 encoder.disp32(0);
41434152
4144 // TODO we should come up with our own, backend independent relocation types
4145 // which each backend (Elf, MachO, etc.) would then translate into an actual
4146 // fixup when linking.
4147 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4153 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4148 try macho_file.pie_fixups.append(self.bin_file.allocator, .{4154 const decl = macho_file.active_decl.?;
4149 .target_addr = x,4155 // Load reloc for LEA instruction.
4150 .offset = self.code.items.len - 4,4156 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4151 .size = 4,4157 .offset = offset,
4158 .where = .local,
4159 .where_index = decl.link.macho.local_sym_index,
4160 .payload = .{ .load = .{ .kind = .got } },
4152 });4161 });
4153 } else {4162 } else {
4154 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});4163 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
src/link/MachO.zig+7-51
...@@ -203,14 +203,11 @@ blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},...@@ -203,14 +203,11 @@ blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
203/// TODO consolidate this.203/// TODO consolidate this.
204decls: std.ArrayListUnmanaged(*Module.Decl) = .{},204decls: std.ArrayListUnmanaged(*Module.Decl) = .{},
205205
206/// A list of all PIE fixups required for this run of the linker.206/// Currently active Module.Decl.
207/// Warning, this is currently NOT thread-safe. See the TODO below.207/// TODO this might not be necessary if we figure out how to pass Module.Decl instance
208/// TODO Move this list inside `updateDecl` where it should be allocated208/// to codegen.genSetReg() or alterntively move PIE displacement for MCValue{ .memory = x }
209/// prior to calling `generateSymbol`, and then immediately deallocated209/// somewhere else in the codegen.
210/// rather than sitting in the global scope.210active_decl: ?*Module.Decl = null,
211/// TODO We should also rewrite this using generic relocations common to all
212/// backends.
213pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},
214211
215const StringIndexContext = struct {212const StringIndexContext = struct {
216 strtab: *std.ArrayListUnmanaged(u8),213 strtab: *std.ArrayListUnmanaged(u8),
...@@ -3279,7 +3276,6 @@ pub fn deinit(self: *MachO) void {...@@ -3279,7 +3276,6 @@ pub fn deinit(self: *MachO) void {
3279 }3276 }
32803277
3281 self.pending_updates.deinit(self.base.allocator);3278 self.pending_updates.deinit(self.base.allocator);
3282 self.pie_fixups.deinit(self.base.allocator);
3283 self.got_entries.deinit(self.base.allocator);3279 self.got_entries.deinit(self.base.allocator);
3284 self.got_entries_map.deinit(self.base.allocator);3280 self.got_entries_map.deinit(self.base.allocator);
3285 self.got_entries_free_list.deinit(self.base.allocator);3281 self.got_entries_free_list.deinit(self.base.allocator);
...@@ -3497,6 +3493,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3497,6 +3493,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3497 }3493 }
3498 }3494 }
34993495
3496 self.active_decl = decl;
3497
3500 const res = if (debug_buffers) |*dbg|3498 const res = if (debug_buffers) |*dbg|
3501 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{3499 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
3502 .ty = decl.ty,3500 .ty = decl.ty,
...@@ -3522,8 +3520,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3522,8 +3520,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3522 break :blk decl.link.macho.code;3520 break :blk decl.link.macho.code;
3523 },3521 },
3524 .fail => |em| {3522 .fail => |em| {
3525 // Clear any PIE fixups for this decl.
3526 self.pie_fixups.shrinkRetainingCapacity(0);
3527 decl.analysis = .codegen_failure;3523 decl.analysis = .codegen_failure;
3528 try module.failed_decls.put(module.gpa, decl, em);3524 try module.failed_decls.put(module.gpa, decl, em);
3529 return;3525 return;
...@@ -3600,46 +3596,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3600,46 +3596,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3600 try self.writeGotEntry(got_index);3596 try self.writeGotEntry(got_index);
3601 }3597 }
36023598
3603 // Calculate displacements to target addr (if any).
3604 while (self.pie_fixups.popOrNull()) |fixup| {
3605 assert(fixup.size == 4);
3606 const this_addr = symbol.n_value + fixup.offset;
3607 const target_addr = fixup.target_addr;
3608
3609 switch (self.base.options.target.cpu.arch) {
3610 .x86_64 => {
3611 const displacement = try math.cast(u32, target_addr - this_addr - 4);
3612 mem.writeIntLittle(u32, decl.link.macho.code[fixup.offset..][0..4], displacement);
3613 },
3614 .aarch64 => {
3615 // TODO optimize instruction based on jump length (use ldr(literal) + nop if possible).
3616 {
3617 const inst = decl.link.macho.code[fixup.offset..][0..4];
3618 var parsed = mem.bytesAsValue(meta.TagPayload(
3619 aarch64.Instruction,
3620 aarch64.Instruction.pc_relative_address,
3621 ), inst);
3622 const this_page = @intCast(i32, this_addr >> 12);
3623 const target_page = @intCast(i32, target_addr >> 12);
3624 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));
3625 parsed.immhi = @truncate(u19, pages >> 2);
3626 parsed.immlo = @truncate(u2, pages);
3627 }
3628 {
3629 const inst = decl.link.macho.code[fixup.offset + 4 ..][0..4];
3630 var parsed = mem.bytesAsValue(meta.TagPayload(
3631 aarch64.Instruction,
3632 aarch64.Instruction.load_store_register,
3633 ), inst);
3634 const narrowed = @truncate(u12, target_addr);
3635 const offset = try math.divExact(u12, narrowed, 8);
3636 parsed.offset = offset;
3637 }
3638 },
3639 else => unreachable, // unsupported target architecture
3640 }
3641 }
3642
3643 // Resolve relocations3599 // Resolve relocations
3644 try decl.link.macho.resolveRelocs(self);3600 try decl.link.macho.resolveRelocs(self);
36453601