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 {
25232523 } else if (func_value.castTag(.extern_fn)) |func_payload| {
25242524 const decl = func_payload.data;
25252525 const where_index = try macho_file.addExternFn(mem.spanZ(decl.name));
2526 const offset = @intCast(u32, self.code.items.len);
2527 switch (arch) {
2528 .x86_64 => {
2529 // callq
2530 try self.code.ensureCapacity(self.code.items.len + 5);
2531 self.code.appendSliceAssumeCapacity(&[5]u8{ 0xe8, 0x0, 0x0, 0x0, 0x0 });
2532 },
2533 .aarch64 => {
2534 // bl
2535 writeInt(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());
2536 },
2537 else => unreachable, // unsupported architecture on MachO
2538 }
2526 const offset = blk: {
2527 switch (arch) {
2528 .x86_64 => {
2529 // callq
2530 try self.code.ensureCapacity(self.code.items.len + 5);
2531 self.code.appendSliceAssumeCapacity(&[5]u8{ 0xe8, 0x0, 0x0, 0x0, 0x0 });
2532 break :blk @intCast(u32, self.code.items.len) - 4;
2533 },
2534 .aarch64 => {
2535 const offset = @intCast(u32, self.code.items.len);
2536 // bl
2537 writeInt(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());
2538 break :blk offset;
2539 },
2540 else => unreachable, // unsupported architecture on MachO
2541 }
2542 };
25392543 // 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, .{
25412545 .offset = offset,
25422546 .where = .import,
25432547 .where_index = where_index,
......@@ -3879,19 +3883,29 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
38793883 }).toU32());
38803884
38813885 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;
38823896 const decl = macho_file.active_decl.?;
38833897 // Page reloc for adrp instruction.
38843898 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
38853899 .offset = offset,
38863900 .where = .local,
3887 .where_index = decl.link.macho.local_sym_index,
3901 .where_index = where_index,
38883902 .payload = .{ .page = .{ .kind = .got } },
38893903 });
38903904 // Pageoff reloc for adrp instruction.
38913905 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
38923906 .offset = offset + 4,
38933907 .where = .local,
3894 .where_index = decl.link.macho.local_sym_index,
3908 .where_index = where_index,
38953909 .payload = .{ .page_off = .{ .kind = .got } },
38963910 });
38973911 } else {
......@@ -4136,7 +4150,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
41364150 const abi_size = ty.abiSize(self.target.*);
41374151 const encoder = try X8664Encoder.init(self.code, 10);
41384152
4139 const offset = @intCast(u32, self.code.items.len);
41404153 // LEA reg, [<offset>]
41414154
41424155 // 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 {
41504163 encoder.modRm_RIPDisp32(reg.low_id());
41514164 encoder.disp32(0);
41524165
4166 const offset = @intCast(u32, self.code.items.len);
4167
41534168 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;
41544179 const decl = macho_file.active_decl.?;
41554180 // Load reloc for LEA instruction.
41564181 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4157 .offset = offset,
4182 .offset = offset - 4,
41584183 .where = .local,
4159 .where_index = decl.link.macho.local_sym_index,
4184 .where_index = where_index,
41604185 .payload = .{ .load = .{ .kind = .got } },
41614186 });
41624187 } else {