authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-14 09:04:08+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:06+02:00
log17635e4f2ae78e358a7a997b161e64de71a01191
treedc688f054c6a6c1ab7d7e96f3cfc1c3bb127e44e
parentb3d98a4b88514b1e8d2cc07ef05c218f50f5f5d8

x86_64: add -fPIC support targeting ELF


5 files changed, 92 insertions(+), 57 deletions(-)

src/arch/x86_64/CodeGen.zig+55-36
...@@ -9190,14 +9190,19 @@ fn genCall(self: *Self, info: union(enum) {...@@ -9190,14 +9190,19 @@ fn genCall(self: *Self, info: union(enum) {
9190 const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);9190 const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
9191 const sym = elf_file.symbol(sym_index);9191 const sym = elf_file.symbol(sym_index);
9192 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);9192 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
9193 _ = try self.addInst(.{9193 if (self.bin_file.options.pic) {
9194 .tag = .call,9194 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index });
9195 .ops = .direct_got_reloc,9195 try self.asmRegister(.{ ._, .call }, .rax);
9196 .data = .{ .reloc = .{9196 } else {
9197 .atom_index = try self.owner.getSymbolIndex(self),9197 _ = try self.addInst(.{
9198 .sym_index = sym.esym_index,9198 .tag = .call,
9199 } },9199 .ops = .direct_got_reloc,
9200 });9200 .data = .{ .reloc = .{
9201 .atom_index = try self.owner.getSymbolIndex(self),
9202 .sym_index = sym.esym_index,
9203 } },
9204 });
9205 }
9201 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {9206 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
9202 const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);9207 const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);
9203 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;9208 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
...@@ -11637,34 +11642,48 @@ fn genLazySymbolRef(...@@ -11637,34 +11642,48 @@ fn genLazySymbolRef(
11637 return self.fail("{s} creating lazy symbol", .{@errorName(err)});11642 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
11638 const sym = elf_file.symbol(sym_index);11643 const sym = elf_file.symbol(sym_index);
11639 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);11644 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
11640 const reloc = Mir.Reloc{11645
11641 .atom_index = try self.owner.getSymbolIndex(self),11646 if (self.bin_file.options.pic) {
11642 .sym_index = sym.esym_index,11647 switch (tag) {
11643 };11648 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }),
11644 switch (tag) {11649 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }),
11645 .lea, .mov => _ = try self.addInst(.{11650 else => unreachable,
11646 .tag = .mov,11651 }
11647 .ops = .direct_got_reloc,11652 switch (tag) {
11648 .data = .{ .rx = .{11653 .lea, .mov => {},
11649 .r1 = reg.to64(),11654 .call => try self.asmRegister(.{ ._, .call }, reg),
11650 .payload = try self.addExtra(reloc),11655 else => unreachable,
11651 } },11656 }
11652 }),11657 } else {
11653 .call => _ = try self.addInst(.{11658 const reloc = Mir.Reloc{
11654 .tag = .call,11659 .atom_index = try self.owner.getSymbolIndex(self),
11655 .ops = .direct_got_reloc,11660 .sym_index = sym.esym_index,
11656 .data = .{ .reloc = reloc },11661 };
11657 }),11662 switch (tag) {
11658 else => unreachable,11663 .lea, .mov => _ = try self.addInst(.{
11659 }11664 .tag = .mov,
11660 switch (tag) {11665 .ops = .direct_got_reloc,
11661 .lea, .call => {},11666 .data = .{ .rx = .{
11662 .mov => try self.asmRegisterMemory(11667 .r1 = reg.to64(),
11663 .{ ._, tag },11668 .payload = try self.addExtra(reloc),
11664 reg.to64(),11669 } },
11665 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),11670 }),
11666 ),11671 .call => _ = try self.addInst(.{
11667 else => unreachable,11672 .tag = .call,
11673 .ops = .direct_got_reloc,
11674 .data = .{ .reloc = reloc },
11675 }),
11676 else => unreachable,
11677 }
11678 switch (tag) {
11679 .lea, .call => {},
11680 .mov => try self.asmRegisterMemory(
11681 .{ ._, tag },
11682 reg.to64(),
11683 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
11684 ),
11685 else => unreachable,
11686 }
11668 }11687 }
11669 } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {11688 } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {
11670 const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|11689 const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
src/arch/x86_64/Emit.zig+9-2
...@@ -85,14 +85,21 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -85,14 +85,21 @@ pub fn emitMir(emit: *Emit) Error!void {
85 .linker_tlv,85 .linker_tlv,
86 => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {86 => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
87 const r_type: u32 = switch (lowered_relocs[0].target) {87 const r_type: u32 = switch (lowered_relocs[0].target) {
88 .linker_direct_got => std.elf.R_X86_64_GOT32,88 .linker_direct_got => link.File.Elf.R_X86_64_ZIG_GOT32,
89 .linker_got => link.File.Elf.R_X86_64_ZIG_GOTPCREL,
90 .linker_direct => std.elf.R_X86_64_PC32,
91 else => unreachable,
92 };
93 const r_addend: i64 = switch (lowered_relocs[0].target) {
94 .linker_direct_got => 0,
95 .linker_got, .linker_direct => -4,
89 else => unreachable,96 else => unreachable,
90 };97 };
91 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;98 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
92 try atom_ptr.addReloc(elf_file, .{99 try atom_ptr.addReloc(elf_file, .{
93 .r_offset = end_offset - 4,100 .r_offset = end_offset - 4,
94 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,101 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
95 .r_addend = 0,102 .r_addend = r_addend,
96 });103 });
97 } else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {104 } else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
98 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;105 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
src/codegen.zig+11-2
...@@ -890,7 +890,11 @@ fn genDeclRef(...@@ -890,7 +890,11 @@ fn genDeclRef(
890 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);890 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
891 const sym = elf_file.symbol(sym_index);891 const sym = elf_file.symbol(sym_index);
892 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);892 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
893 return GenResult.mcv(.{ .memory = sym.zigGotAddress(elf_file) });893 if (bin_file.options.pic) {
894 return GenResult.mcv(.{ .load_got = sym.esym_index });
895 } else {
896 return GenResult.mcv(.{ .memory = sym.zigGotAddress(elf_file) });
897 }
894 } else if (bin_file.cast(link.File.MachO)) |macho_file| {898 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
895 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);899 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
896 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;900 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
...@@ -925,7 +929,12 @@ fn genUnnamedConst(...@@ -925,7 +929,12 @@ fn genUnnamedConst(
925 return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});929 return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
926 };930 };
927 if (bin_file.cast(link.File.Elf)) |elf_file| {931 if (bin_file.cast(link.File.Elf)) |elf_file| {
928 return GenResult.mcv(.{ .memory = elf_file.symbol(local_sym_index).value });932 const local = elf_file.symbol(local_sym_index);
933 if (bin_file.options.pic) {
934 return GenResult.mcv(.{ .load_direct = local.esym_index });
935 } else {
936 return GenResult.mcv(.{ .memory = local.value });
937 }
929 } else if (bin_file.cast(link.File.MachO)) |_| {938 } else if (bin_file.cast(link.File.MachO)) |_| {
930 return GenResult.mcv(.{ .load_direct = local_sym_index });939 return GenResult.mcv(.{ .load_direct = local_sym_index });
931 } else if (bin_file.cast(link.File.Coff)) |_| {940 } else if (bin_file.cast(link.File.Coff)) |_| {
src/link/Elf.zig+3
...@@ -6074,6 +6074,9 @@ const SystemLib = struct {...@@ -6074,6 +6074,9 @@ const SystemLib = struct {
6074 path: []const u8,6074 path: []const u8,
6075};6075};
60766076
6077pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
6078pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
6079
6077const std = @import("std");6080const std = @import("std");
6078const build_options = @import("build_options");6081const build_options = @import("build_options");
6079const builtin = @import("builtin");6082const builtin = @import("builtin");
src/link/Elf/Atom.zig+14-17
...@@ -370,16 +370,6 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -370,16 +370,6 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
370 try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);370 try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
371 },371 },
372372
373 // TODO I have temporarily repurposed those for handling .zig.got indirection
374 // but we should probably claim unused custom values for incremental linking
375 // that get rewritten to standard relocs when lowering to a relocatable object
376 // file.
377 elf.R_X86_64_GOT32,
378 elf.R_X86_64_GOT64,
379 => {
380 assert(symbol.flags.has_zig_got);
381 },
382
383 elf.R_X86_64_GOTPC32,373 elf.R_X86_64_GOTPC32,
384 elf.R_X86_64_GOTPC64,374 elf.R_X86_64_GOTPC64,
385 elf.R_X86_64_GOTPCREL,375 elf.R_X86_64_GOTPCREL,
...@@ -461,6 +451,13 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype...@@ -461,6 +451,13 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
461 elf.R_X86_64_TLSDESC_CALL,451 elf.R_X86_64_TLSDESC_CALL,
462 => {},452 => {},
463453
454 // Zig custom relocations
455 Elf.R_X86_64_ZIG_GOT32,
456 Elf.R_X86_64_ZIG_GOTPCREL,
457 => {
458 assert(symbol.flags.has_zig_got);
459 },
460
464 else => try self.reportUnhandledRelocError(rel, elf_file),461 else => try self.reportUnhandledRelocError(rel, elf_file),
465 }462 }
466 }463 }
...@@ -813,13 +810,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {...@@ -813,13 +810,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
813 elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))),810 elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))),
814 elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))),811 elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))),
815812
816 // TODO I have temporarily repurposed those for handling .zig.got indirection
817 // but we should probably claim unused custom values for incremental linking
818 // that get rewritten to standard relocs when lowering to a relocatable object
819 // file.
820 elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(ZIG_GOT + A))),
821 elf.R_X86_64_GOT64 => try cwriter.writeIntLittle(u64, @as(u64, @intCast(ZIG_GOT + A))),
822
823 elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))),813 elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))),
824 elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP),814 elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP),
825815
...@@ -888,6 +878,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {...@@ -888,6 +878,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
888 }878 }
889 },879 },
890880
881 // Zig custom relocations
882 Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(ZIG_GOT + A))),
883 Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(ZIG_GOT + A - P))),
884
891 else => {},885 else => {},
892 }886 }
893 }887 }
...@@ -1136,6 +1130,9 @@ fn formatRelocType(...@@ -1136,6 +1130,9 @@ fn formatRelocType(
1136 elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX",1130 elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX",
1137 elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX",1131 elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX",
1138 elf.R_X86_64_NUM => "R_X86_64_NUM",1132 elf.R_X86_64_NUM => "R_X86_64_NUM",
1133 // Zig custom relocations
1134 Elf.R_X86_64_ZIG_GOT32 => "R_X86_64_ZIG_GOT32",
1135 Elf.R_X86_64_ZIG_GOTPCREL => "R_X86_64_ZIG_GOTPCREL",
1139 else => "R_X86_64_UNKNOWN",1136 else => "R_X86_64_UNKNOWN",
1140 };1137 };
1141 try writer.print("{s}", .{str});1138 try writer.print("{s}", .{str});