authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-21 23:05:03+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-21 23:05:03+02:00
loge05b1e0e07708ca16c1a90e51a668faf51d883f4
treedd82931a6fe2b3095c174c260a1e0e589e6ef967
parent845c906e6a2ed9206840bd189d85bf9525687102

macho: fix reloc generation for stubs and GOT entries

The current approach is somewhat hacky, however, works well for one-off self-hosted linking.

1 files changed, 44 insertions(+), 19 deletions(-)

src/codegen.zig+44-19
...@@ -2523,21 +2523,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2523,21 +2523,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2523 } else if (func_value.castTag(.extern_fn)) |func_payload| {2523 } else if (func_value.castTag(.extern_fn)) |func_payload| {
2524 const decl = func_payload.data;2524 const decl = func_payload.data;
2525 const where_index = try macho_file.addExternFn(mem.spanZ(decl.name));2525 const where_index = try macho_file.addExternFn(mem.spanZ(decl.name));
2526 const offset = @intCast(u32, self.code.items.len);2526 const offset = blk: {
2527 switch (arch) {2527 switch (arch) {
2528 .x86_64 => {2528 .x86_64 => {
2529 // callq2529 // callq
2530 try self.code.ensureCapacity(self.code.items.len + 5);2530 try self.code.ensureCapacity(self.code.items.len + 5);
2531 self.code.appendSliceAssumeCapacity(&[5]u8{ 0xe8, 0x0, 0x0, 0x0, 0x0 });2531 self.code.appendSliceAssumeCapacity(&[5]u8{ 0xe8, 0x0, 0x0, 0x0, 0x0 });
2532 },2532 break :blk @intCast(u32, self.code.items.len) - 4;
2533 .aarch64 => {2533 },
2534 // bl2534 .aarch64 => {
2535 writeInt(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());2535 const offset = @intCast(u32, self.code.items.len);
2536 },2536 // bl
2537 else => unreachable, // unsupported architecture on MachO2537 writeInt(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());
2538 }2538 break :blk offset;
2539 },
2540 else => unreachable, // unsupported architecture on MachO
2541 }
2542 };
2539 // Add relocation to the decl.2543 // Add relocation to the decl.
2540 try decl.link.macho.relocs.append(self.bin_file.allocator, .{2544 try macho_file.active_decl.?.link.macho.relocs.append(self.bin_file.allocator, .{
2541 .offset = offset,2545 .offset = offset,
2542 .where = .import,2546 .where = .import,
2543 .where_index = where_index,2547 .where_index = where_index,
...@@ -3879,19 +3883,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3879,19 +3883,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3879 }).toU32());3883 }).toU32());
38803884
3881 if (self.bin_file.cast(link.File.MachO)) |macho_file| {3885 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
3886 // TODO this is super awkward. We are reversing the address of the GOT entry here.
3887 // We should probably have it cached or move the reloc adding somewhere else.
3888 const got_addr = blk: {
3889 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
3890 const got = seg.sections.items[macho_file.got_section_index.?];
3891 break :blk got.addr;
3892 };
3893 const where_index = blk: for (macho_file.got_entries.items) |key, id| {
3894 if (got_addr + id * @sizeOf(u64) == addr) break :blk key.where_index;
3895 } else unreachable;
3882 const decl = macho_file.active_decl.?;3896 const decl = macho_file.active_decl.?;
3883 // Page reloc for adrp instruction.3897 // Page reloc for adrp instruction.
3884 try decl.link.macho.relocs.append(self.bin_file.allocator, .{3898 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
3885 .offset = offset,3899 .offset = offset,
3886 .where = .local,3900 .where = .local,
3887 .where_index = decl.link.macho.local_sym_index,3901 .where_index = where_index,
3888 .payload = .{ .page = .{ .kind = .got } },3902 .payload = .{ .page = .{ .kind = .got } },
3889 });3903 });
3890 // Pageoff reloc for adrp instruction.3904 // Pageoff reloc for adrp instruction.
3891 try decl.link.macho.relocs.append(self.bin_file.allocator, .{3905 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
3892 .offset = offset + 4,3906 .offset = offset + 4,
3893 .where = .local,3907 .where = .local,
3894 .where_index = decl.link.macho.local_sym_index,3908 .where_index = where_index,
3895 .payload = .{ .page_off = .{ .kind = .got } },3909 .payload = .{ .page_off = .{ .kind = .got } },
3896 });3910 });
3897 } else {3911 } else {
...@@ -4136,7 +4150,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4136,7 +4150,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4136 const abi_size = ty.abiSize(self.target.*);4150 const abi_size = ty.abiSize(self.target.*);
4137 const encoder = try X8664Encoder.init(self.code, 10);4151 const encoder = try X8664Encoder.init(self.code, 10);
41384152
4139 const offset = @intCast(u32, self.code.items.len);
4140 // LEA reg, [<offset>]4153 // LEA reg, [<offset>]
41414154
4142 // We encode the instruction FIRST because prefixes may or may not appear.4155 // We encode the instruction FIRST because prefixes may or may not appear.
...@@ -4150,13 +4163,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4150,13 +4163,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4150 encoder.modRm_RIPDisp32(reg.low_id());4163 encoder.modRm_RIPDisp32(reg.low_id());
4151 encoder.disp32(0);4164 encoder.disp32(0);
41524165
4166 const offset = @intCast(u32, self.code.items.len);
4167
4153 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4168 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4169 // TODO this is super awkward. We are reversing the address of the GOT entry here.
4170 // We should probably have it cached or move the reloc adding somewhere else.
4171 const got_addr = blk: {
4172 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4173 const got = seg.sections.items[macho_file.got_section_index.?];
4174 break :blk got.addr;
4175 };
4176 const where_index = blk: for (macho_file.got_entries.items) |key, id| {
4177 if (got_addr + id * @sizeOf(u64) == x) break :blk key.where_index;
4178 } else unreachable;
4154 const decl = macho_file.active_decl.?;4179 const decl = macho_file.active_decl.?;
4155 // Load reloc for LEA instruction.4180 // Load reloc for LEA instruction.
4156 try decl.link.macho.relocs.append(self.bin_file.allocator, .{4181 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4157 .offset = offset,4182 .offset = offset - 4,
4158 .where = .local,4183 .where = .local,
4159 .where_index = decl.link.macho.local_sym_index,4184 .where_index = where_index,
4160 .payload = .{ .load = .{ .kind = .got } },4185 .payload = .{ .load = .{ .kind = .got } },
4161 });4186 });
4162 } else {4187 } else {