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) {
91909190 const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
91919191 const sym = elf_file.symbol(sym_index);
91929192 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
9193 _ = try self.addInst(.{
9194 .tag = .call,
9195 .ops = .direct_got_reloc,
9196 .data = .{ .reloc = .{
9197 .atom_index = try self.owner.getSymbolIndex(self),
9198 .sym_index = sym.esym_index,
9199 } },
9200 });
9193 if (self.bin_file.options.pic) {
9194 try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index });
9195 try self.asmRegister(.{ ._, .call }, .rax);
9196 } else {
9197 _ = try self.addInst(.{
9198 .tag = .call,
9199 .ops = .direct_got_reloc,
9200 .data = .{ .reloc = .{
9201 .atom_index = try self.owner.getSymbolIndex(self),
9202 .sym_index = sym.esym_index,
9203 } },
9204 });
9205 }
92019206 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
92029207 const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);
92039208 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
......@@ -11637,34 +11642,48 @@ fn genLazySymbolRef(
1163711642 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1163811643 const sym = elf_file.symbol(sym_index);
1163911644 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
11640 const reloc = Mir.Reloc{
11641 .atom_index = try self.owner.getSymbolIndex(self),
11642 .sym_index = sym.esym_index,
11643 };
11644 switch (tag) {
11645 .lea, .mov => _ = try self.addInst(.{
11646 .tag = .mov,
11647 .ops = .direct_got_reloc,
11648 .data = .{ .rx = .{
11649 .r1 = reg.to64(),
11650 .payload = try self.addExtra(reloc),
11651 } },
11652 }),
11653 .call => _ = try self.addInst(.{
11654 .tag = .call,
11655 .ops = .direct_got_reloc,
11656 .data = .{ .reloc = reloc },
11657 }),
11658 else => unreachable,
11659 }
11660 switch (tag) {
11661 .lea, .call => {},
11662 .mov => try self.asmRegisterMemory(
11663 .{ ._, tag },
11664 reg.to64(),
11665 Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }),
11666 ),
11667 else => unreachable,
11645
11646 if (self.bin_file.options.pic) {
11647 switch (tag) {
11648 .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }),
11649 .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }),
11650 else => unreachable,
11651 }
11652 switch (tag) {
11653 .lea, .mov => {},
11654 .call => try self.asmRegister(.{ ._, .call }, reg),
11655 else => unreachable,
11656 }
11657 } else {
11658 const reloc = Mir.Reloc{
11659 .atom_index = try self.owner.getSymbolIndex(self),
11660 .sym_index = sym.esym_index,
11661 };
11662 switch (tag) {
11663 .lea, .mov => _ = try self.addInst(.{
11664 .tag = .mov,
11665 .ops = .direct_got_reloc,
11666 .data = .{ .rx = .{
11667 .r1 = reg.to64(),
11668 .payload = try self.addExtra(reloc),
11669 } },
11670 }),
11671 .call => _ = try self.addInst(.{
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 }
1166811687 }
1166911688 } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| {
1167011689 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 {
8585 .linker_tlv,
8686 => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
8787 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,
8996 else => unreachable,
9097 };
9198 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
9299 try atom_ptr.addReloc(elf_file, .{
93100 .r_offset = end_offset - 4,
94101 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
95 .r_addend = 0,
102 .r_addend = r_addend,
96103 });
97104 } else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
98105 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
src/codegen.zig+11-2
......@@ -890,7 +890,11 @@ fn genDeclRef(
890890 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
891891 const sym = elf_file.symbol(sym_index);
892892 _ = 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 }
894898 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
895899 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
896900 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
......@@ -925,7 +929,12 @@ fn genUnnamedConst(
925929 return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
926930 };
927931 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 }
929938 } else if (bin_file.cast(link.File.MachO)) |_| {
930939 return GenResult.mcv(.{ .load_direct = local_sym_index });
931940 } else if (bin_file.cast(link.File.Coff)) |_| {
src/link/Elf.zig+3
......@@ -6074,6 +6074,9 @@ const SystemLib = struct {
60746074 path: []const u8,
60756075};
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
60776080const std = @import("std");
60786081const build_options = @import("build_options");
60796082const 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
370370 try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
371371 },
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
383373 elf.R_X86_64_GOTPC32,
384374 elf.R_X86_64_GOTPC64,
385375 elf.R_X86_64_GOTPCREL,
......@@ -461,6 +451,13 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
461451 elf.R_X86_64_TLSDESC_CALL,
462452 => {},
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
464461 else => try self.reportUnhandledRelocError(rel, elf_file),
465462 }
466463 }
......@@ -813,13 +810,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
813810 elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))),
814811 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
823813 elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))),
824814 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 {
888878 }
889879 },
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
891885 else => {},
892886 }
893887 }
......@@ -1136,6 +1130,9 @@ fn formatRelocType(
11361130 elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX",
11371131 elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX",
11381132 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",
11391136 else => "R_X86_64_UNKNOWN",
11401137 };
11411138 try writer.print("{s}", .{str});