authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-06 11:37:19+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-09 10:49:15+02:00
logf51bb018d71da1ab80af59b03eba207e12c231a6
treed9984df184ccc94a7d81304f832f0180b5853086
parentf74b21f0bd6919d4388b65e9cb88009da0a67859
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Elf2: start adding sparc64 support


3 files changed, 343 insertions(+), 64 deletions(-)

src/link.zig+2-1
...@@ -26,12 +26,13 @@ const target_util = @import("target.zig");...@@ -26,12 +26,13 @@ const target_util = @import("target.zig");
26const codegen = @import("codegen.zig");26const codegen = @import("codegen.zig");
27const crash_report = @import("crash_report.zig");27const crash_report = @import("crash_report.zig");
2828
29pub const aarch64 = @import("link/aarch64.zig");
30pub const LdScript = @import("link/LdScript.zig");29pub const LdScript = @import("link/LdScript.zig");
31pub const Queue = @import("link/Queue.zig");30pub const Queue = @import("link/Queue.zig");
32pub const ConstPool = @import("link/ConstPool.zig");31pub const ConstPool = @import("link/ConstPool.zig");
3332
33pub const aarch64 = @import("link/aarch64.zig");
34pub const loongarch = @import("link/loongarch.zig");34pub const loongarch = @import("link/loongarch.zig");
35pub const sparc = @import("link/sparc.zig");
3536
36pub const Error = Allocator.Error || Io.Cancelable || error{37pub const Error = Allocator.Error || Io.Cancelable || error{
37 /// An error message has already been stored in persistent state on `Compilation` or `Zcu`, for38 /// An error message has already been stored in persistent state on `Compilation` or `Zcu`, for
src/link/Elf2.zig+144-63
...@@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section),...@@ -28,8 +28,10 @@ shdrs: std.ArrayList(Section),
28phdrs: std.ArrayList(MappedFile.Node.Index),28phdrs: std.ArrayList(MappedFile.Node.Index),
29shndx: struct {29shndx: struct {
30 got: Section.Index,30 got: Section.Index,
31 /// Always `.UNDEF` on some targets (e.g. SPARC).
31 got_plt: Section.Index,32 got_plt: Section.Index,
32 plt: Section.Index,33 plt: Section.Index,
34 /// Only created for x86 targets; `.UNDEF` everywhere else.
33 plt_sec: Section.Index,35 plt_sec: Section.Index,
34 dynsym: Section.Index,36 dynsym: Section.Index,
35 dynstr: Section.Index,37 dynstr: Section.Index,
...@@ -897,11 +899,12 @@ const GotReloc = struct {...@@ -897,11 +899,12 @@ const GotReloc = struct {
897};899};
898900
899pub const MachineRelocType = union {901pub const MachineRelocType = union {
900 X86_64: std.elf.R_X86_64,
901 AARCH64: std.elf.R_AARCH64,902 AARCH64: std.elf.R_AARCH64,
902 LOONGARCH: std.elf.R_LARCH,903 LOONGARCH: std.elf.R_LARCH,
903 RISCV: std.elf.R_RISCV,
904 PPC64: std.elf.R_PPC64,904 PPC64: std.elf.R_PPC64,
905 RISCV: std.elf.R_RISCV,
906 SPARC: std.elf.R_SPARC,
907 X86_64: std.elf.R_X86_64,
905908
906 pub fn none(elf: *Elf) MachineRelocType {909 pub fn none(elf: *Elf) MachineRelocType {
907 return switch (elf.ehdrField(.machine)) {910 return switch (elf.ehdrField(.machine)) {
...@@ -910,6 +913,7 @@ pub const MachineRelocType = union {...@@ -910,6 +913,7 @@ pub const MachineRelocType = union {
910 .LOONGARCH => .{ .LOONGARCH = .NONE },913 .LOONGARCH => .{ .LOONGARCH = .NONE },
911 .PPC64 => .{ .PPC64 = .NONE },914 .PPC64 => .{ .PPC64 = .NONE },
912 .RISCV => .{ .RISCV = .NONE },915 .RISCV => .{ .RISCV = .NONE },
916 .SPARCV9 => .{ .SPARC = .NONE },
913 .X86_64 => .{ .X86_64 = .NONE },917 .X86_64 => .{ .X86_64 = .NONE },
914 };918 };
915 }919 }
...@@ -920,6 +924,7 @@ pub const MachineRelocType = union {...@@ -920,6 +924,7 @@ pub const MachineRelocType = union {
920 .LOONGARCH => .{ .LOONGARCH = .COPY },924 .LOONGARCH => .{ .LOONGARCH = .COPY },
921 .PPC64 => .{ .PPC64 = .COPY },925 .PPC64 => .{ .PPC64 = .COPY },
922 .RISCV => .{ .RISCV = .COPY },926 .RISCV => .{ .RISCV = .COPY },
927 .SPARCV9 => .{ .SPARC = .COPY },
923 .X86_64 => .{ .X86_64 = .COPY },928 .X86_64 => .{ .X86_64 = .COPY },
924 };929 };
925 }930 }
...@@ -930,43 +935,57 @@ pub const MachineRelocType = union {...@@ -930,43 +935,57 @@ pub const MachineRelocType = union {
930 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },935 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },
931 .PPC64 => .{ .PPC64 = .RELATIVE },936 .PPC64 => .{ .PPC64 = .RELATIVE },
932 .RISCV => .{ .RISCV = .RELATIVE },937 .RISCV => .{ .RISCV = .RELATIVE },
938 .SPARCV9 => .{ .SPARC = .RELATIVE },
933 .X86_64 => .{ .X86_64 = .RELATIVE },939 .X86_64 => .{ .X86_64 = .RELATIVE },
934 };940 };
935 }941 }
936 pub fn jumpSlot(elf: *Elf) MachineRelocType {942 pub fn jumpSlot(elf: *Elf) MachineRelocType {
937 return switch (elf.ehdrField(.machine)) {943 return switch (elf.ehdrField(.machine)) {
938 else => unreachable,944 else => unreachable,
939 .X86_64 => .{ .X86_64 = .JUMP_SLOT },945 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
940 .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT },946 .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT },
947 .PPC64 => .{ .PPC64 = .JMP_SLOT },
948 .RISCV => .{ .RISCV = .JUMP_SLOT },
949 .SPARCV9 => .{ .SPARC = .JMP_SLOT },
950 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
941 };951 };
942 }952 }
943 pub fn globDat(elf: *Elf) MachineRelocType {953 pub fn globDat(elf: *Elf) MachineRelocType {
944 return switch (elf.ehdrField(.machine)) {954 return switch (elf.ehdrField(.machine)) {
945 else => unreachable,955 else => unreachable,
946 .X86_64 => .{ .X86_64 = .GLOB_DAT },956 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
947 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },957 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
958 .PPC64 => .{ .PPC64 = .GLOB_DAT },
959 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
960 .SPARCV9 => .{ .SPARC = .GLOB_DAT },
961 .X86_64 => .{ .X86_64 = .GLOB_DAT },
948 };962 };
949 }963 }
950 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {964 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {
951 return switch (elf.ehdrField(.machine)) {965 return switch (elf.ehdrField(.machine)) {
952 else => unreachable,966 else => unreachable,
953 .X86_64 => .{ .X86_64 = .DTPOFF64 },
954 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },967 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
968 .PPC64 => .{ .PPC64 = .DTPREL64 },
969 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 },
970 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 },
971 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .DTPOFF64 else .DTPOFF32 },
955 };972 };
956 }973 }
957 pub fn absAddr(elf: *Elf) MachineRelocType {974 pub fn absAddr(elf: *Elf) MachineRelocType {
958 return switch (elf.ehdrField(.machine)) {975 return switch (elf.ehdrField(.machine)) {
959 else => unreachable,976 else => unreachable,
960 .AARCH64 => .{ .AARCH64 = .ABS64 },977 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },
961 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },978 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
962 .PPC64 => .{ .PPC64 = .ADDR64 },979 .PPC64 => .{ .PPC64 = .ADDR64 },
963 .RISCV => .{ .RISCV = .@"64" },980 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
964 .X86_64 => .{ .X86_64 = .@"64" },981 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },
982 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },
965 };983 };
966 }984 }
967 pub fn sizeAddr(elf: *Elf) MachineRelocType {985 pub fn sizeAddr(elf: *Elf) MachineRelocType {
968 return switch (elf.ehdrField(.machine)) {986 return switch (elf.ehdrField(.machine)) {
969 else => unreachable,987 else => unreachable,
988 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .SIZE64 else .SIZE32 },
970 .X86_64 => .{ .X86_64 = .SIZE64 },989 .X86_64 => .{ .X86_64 = .SIZE64 },
971 };990 };
972 }991 }
...@@ -974,6 +993,7 @@ pub const MachineRelocType = union {...@@ -974,6 +993,7 @@ pub const MachineRelocType = union {
974 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {993 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {
975 return switch (elf.ehdrField(.machine)) {994 return switch (elf.ehdrField(.machine)) {
976 else => unreachable,995 else => unreachable,
996 .SPARCV9 => .{ .SPARC = @enumFromInt(int) },
977 inline .AARCH64,997 inline .AARCH64,
978 .LOONGARCH,998 .LOONGARCH,
979 .PPC64,999 .PPC64,
...@@ -985,6 +1005,7 @@ pub const MachineRelocType = union {...@@ -985,6 +1005,7 @@ pub const MachineRelocType = union {
985 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {1005 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {
986 return switch (elf.ehdrField(.machine)) {1006 return switch (elf.ehdrField(.machine)) {
987 else => unreachable,1007 else => unreachable,
1008 .SPARCV9 => @intFromEnum(rt.SPARC),
988 inline .AARCH64,1009 inline .AARCH64,
989 .LOONGARCH,1010 .LOONGARCH,
990 .PPC64,1011 .PPC64,
...@@ -1448,10 +1469,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {...@@ -1448,10 +1469,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
1448 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);1469 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14491470
1450 // Ensure the `.got.plt` section's node is big enough1471 // Ensure the `.got.plt` section's node is big enough
1451 const got_plt_need_size: usize = switch (elf.identClass()) {1472 const got_plt_need_size: usize = elf.targetPtrSize() * (3 + need_plt_capacity);
1452 .NONE, _ => unreachable,
1453 inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity),
1454 };
1455 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);1473 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14561474
1457 // Ensure the `.plt.sec` section's node is big enough1475 // Ensure the `.plt.sec` section's node is big enough
...@@ -1460,16 +1478,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {...@@ -1460,16 +1478,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
1460 },1478 },
1461 .LOONGARCH => {1479 .LOONGARCH => {
1462 // Ensure the `.plt` section's node is big enough1480 // Ensure the `.plt` section's node is big enough
1463 const plt_need_size: usize = 32 + 16 * need_plt_capacity;1481 const plt_need_size: usize = 16 * (2 + need_plt_capacity);
1464 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);1482 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14651483
1466 // Ensure the `.got.plt` section's node is big enough1484 // Ensure the `.got.plt` section's node is big enough
1467 const got_plt_need_size: usize = switch (elf.identClass()) {1485 const got_plt_need_size: usize = elf.targetPtrSize() * (2 + need_plt_capacity);
1468 .NONE, _ => unreachable,
1469 inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity),
1470 };
1471 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);1486 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
1472 },1487 },
1488 .SPARCV9 => {
1489 // Ensure the `.plt` section's node is big enough
1490 const plt_need_size: usize = 32 * (4 + need_plt_capacity);
1491 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
1492 },
1473 }1493 }
1474}1494}
1475/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at1495/// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at
...@@ -2090,23 +2110,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2090,23 +2110,17 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2090 .addend = 0,2110 .addend = 0,
2091 }));2111 }));
20922112
2093 const reserved_got_plt_entries: u32 = switch (elf.ehdrField(.machine)) {2113 // Note that some architectures don't have .got.plt (e.g. SPARC), and so
2114 // these values actually refer to .plt.
2115 const got_plt_section, const got_plt_offset = switch (elf.ehdrField(.machine)) {
2094 else => |machine| @panic(@tagName(machine)),2116 else => |machine| @panic(@tagName(machine)),
2095 .X86_64 => 3,2117 .LOONGARCH => .{ elf.shndx.got_plt, elf.targetPtrSize() * (2 + plt_index) },
2096 .LOONGARCH => 2,2118 .SPARCV9 => .{ elf.shndx.plt, 32 * (4 + plt_index) },
2119 .X86_64 => .{ elf.shndx.got_plt, elf.targetPtrSize() * (3 + plt_index) },
2097 };2120 };
20982121
2099 // Now that we know the index, we can set the relocation's offset.2122 // Now that we know the index, we can set the relocation's offset.
2100 const got_plt_addr = switch (elf.shdrPtr(elf.shndx.got_plt)) {2123 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset);
2101 inline else => |shdr, class| got_plt_addr: {
2102 const ent_size = @sizeOf(class.ElfN().Addr);
2103 assert(elf.targetLoad(&shdr.entsize) == ent_size);
2104 const offset = ent_size * @as(u64, reserved_got_plt_entries + plt_index);
2105 assert(offset <= elf.targetLoad(&shdr.size));
2106 break :got_plt_addr elf.targetLoad(&shdr.addr) + offset;
2107 },
2108 };
2109 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_addr);
21102124
2111 if (plt_index < elf.plt.count()) {2125 if (plt_index < elf.plt.count()) {
2112 // We reused a free entry, so we're already done!2126 // We reused a free entry, so we're already done!
...@@ -2148,13 +2162,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2148,13 +2162,11 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2148 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;2162 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
2149 switch (elf.shdrPtr(elf.shndx.got_plt)) {2163 switch (elf.shdrPtr(elf.shndx.got_plt)) {
2150 inline else => |shdr, class| {2164 inline else => |shdr, class| {
2151 const ent_size = @sizeOf(class.ElfN().Addr);2165 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2152 const old_size = ent_size * (3 + plt_index);2166 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr));
2153 assert(elf.targetLoad(&shdr.size) == old_size);
2154 elf.targetStore(&shdr.size, old_size + ent_size);
2155 std.mem.writeInt(2167 std.mem.writeInt(
2156 class.ElfN().Addr,2168 class.ElfN().Addr,
2157 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],2169 got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(shdr.ElfN().Addr)],
2158 @intCast(plt_addr),2170 @intCast(plt_addr),
2159 target_endian,2171 target_endian,
2160 );2172 );
...@@ -2176,7 +2188,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2176,7 +2188,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2176 i32,2188 i32,
2177 plt_sec_slice[6..][0..4],2189 plt_sec_slice[6..][0..4],
2178 @intCast(@as(i64, @bitCast(2190 @intCast(@as(i64, @bitCast(
2179 got_plt_addr -% (elf.targetLoad(&shdr.addr) + old_size + 10),2191 (got_plt_section.vaddr(elf) + got_plt_offset) -% (elf.targetLoad(&shdr.addr) + old_size + 10),
2180 ))),2192 ))),
2181 target_endian,2193 target_endian,
2182 );2194 );
...@@ -2212,26 +2224,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2212,26 +2224,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
2212 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;2224 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
2213 switch (elf.shdrPtr(elf.shndx.got_plt)) {2225 switch (elf.shdrPtr(elf.shndx.got_plt)) {
2214 inline else => |shdr, class| {2226 inline else => |shdr, class| {
2215 const ent_size = @sizeOf(class.ElfN().Addr);2227 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2216 const old_size = ent_size * (2 + plt_index);2228 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr));
2217 assert(elf.targetLoad(&shdr.size) == old_size);
2218 elf.targetStore(&shdr.size, old_size + ent_size);
2219 std.mem.writeInt(2229 std.mem.writeInt(
2220 class.ElfN().Addr,2230 class.ElfN().Addr,
2221 got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size],2231 got_plt_ni.slice(&elf.mf)[got_plt_offset..][0..@sizeOf(shdr.ElfN().Addr)],
2222 @intCast(plt_addr),2232 @intCast(plt_addr),
2223 target_endian,2233 target_endian,
2224 );2234 );
2225 assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size));
2226 },2235 },
2227 }2236 }
22282237
2229 // relocate the PLT entry to point to the .GOT.PLT entry2238 // relocate the PLT entry to point to the .GOT.PLT entry
2230 const got_plt_abs: u64 = @as(u64, got_plt_addr);2239 const got_plt_abs = got_plt_section.vaddr(elf) + got_plt_offset;
2231 // TODO: handle overflow gracefully2240 // TODO: handle overflow gracefully
2232 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));2241 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));
2233 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));2242 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));
2234 },2243 },
2244 .SPARCV9 => {
2245 // add a .PLT entry, writing the template
2246 const plt_ni = elf.shndx.plt.get(elf).ni;
2247 switch (elf.shdrPtr(elf.shndx.plt)) {
2248 inline else => |shdr| {
2249 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2250 elf.targetStore(&shdr.size, got_plt_offset + 32);
2251 const plt_slice: []u32 = @ptrCast(@alignCast(plt_ni.slice(&elf.mf)[got_plt_offset..][0..32]));
2252 // sethi (. - .plt[0]), %g1
2253 // ba,a %xcc, .plt[1]
2254 // nop
2255 // nop
2256 // nop
2257 // nop
2258 // nop
2259 // nop
2260 @memcpy(plt_slice, &([2]u32{
2261 // TODO: handle overflow gracefully
2262 @bitCast(link.sparc.reloc.Imm22{
2263 .imm22 = @truncate(got_plt_offset),
2264 .b22_31 = 0b0000000011,
2265 }),
2266 @bitCast(link.sparc.reloc.Disp19{
2267 .disp19 = @truncate((got_plt_offset + 4 - 32) >> 2),
2268 .b19_31 = 0b1100001101000,
2269 }),
2270 } ++ @as([6]u32, @splat(0x01000000))));
2271 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllElements(u32, plt_slice);
2272 },
2273 }
2274 },
2235 }2275 }
2236}2276}
22372277
...@@ -3084,11 +3124,12 @@ fn initHeaders(...@@ -3084,11 +3124,12 @@ fn initHeaders(
3084 .@"64" => .@"8",3124 .@"64" => .@"8",
3085 };3125 };
30863126
3087 const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec =3127 const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const got_plt, const plt_sec =
3088 switch (machine) {3128 switch (machine) {
3089 else => @panic(@tagName(machine)),3129 else => @panic(@tagName(machine)),
3090 .X86_64 => .{ 16, .@"16", true },3130 .LOONGARCH => .{ 16 * 2, .@"4", true, false },
3091 .LOONGARCH => .{ 32, .@"4", false },3131 .SPARCV9 => .{ 32 * 4, .fromByteUnits(256), false, false },
3132 .X86_64 => .{ 16, .@"16", true, true },
3092 };3133 };
30933134
3094 const shnum: u32 = shnum: {3135 const shnum: u32 = shnum: {
...@@ -3111,7 +3152,7 @@ fn initHeaders(...@@ -3111,7 +3152,7 @@ fn initHeaders(
3111 }3152 }
3112 if (@"type" != .REL) {3153 if (@"type" != .REL) {
3113 shnum += 1; // .got3154 shnum += 1; // .got
3114 shnum += 1; // .got.plt3155 shnum += @intFromBool(got_plt); // .got.plt
3115 shnum += 1; // .plt3156 shnum += 1; // .plt
3116 shnum += @intFromBool(plt_sec); // .plt_sec3157 shnum += @intFromBool(plt_sec); // .plt_sec
3117 }3158 }
...@@ -3212,7 +3253,6 @@ fn initHeaders(...@@ -3212,7 +3253,6 @@ fn initHeaders(
3212 ehdr.phoff = 0;3253 ehdr.phoff = 0;
3213 ehdr.shoff = 0;3254 ehdr.shoff = 0;
3214 ehdr.flags = switch (machine) {3255 ehdr.flags = switch (machine) {
3215 .X86_64 => 0,
3216 .LOONGARCH => e_flags: {3256 .LOONGARCH => e_flags: {
3217 const target_cpu = &elf.base.comp.getTarget().cpu;3257 const target_cpu = &elf.base.comp.getTarget().cpu;
3218 const e_flags: std.elf.loongarch.EFlags = .{3258 const e_flags: std.elf.loongarch.EFlags = .{
...@@ -3227,6 +3267,20 @@ fn initHeaders(...@@ -3227,6 +3267,20 @@ fn initHeaders(
3227 };3267 };
3228 break :e_flags @bitCast(e_flags);3268 break :e_flags @bitCast(e_flags);
3229 },3269 },
3270 .SPARCV9 => e_flags: {
3271 const e_flags: std.elf.sparc.EFlags = .{
3272 .mm = .rmo,
3273 .ext = .{
3274 .@"32plus" = false,
3275 .sun_us1 = false,
3276 .hal_r1 = false,
3277 .sun_us3 = false,
3278 .le_data = false,
3279 },
3280 };
3281 break :e_flags @bitCast(e_flags);
3282 },
3283 .X86_64 => 0,
3230 else => @panic(@tagName(machine)),3284 else => @panic(@tagName(machine)),
3231 };3285 };
3232 ehdr.ehsize = @sizeOf(ElfN.Ehdr);3286 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
...@@ -3324,8 +3378,8 @@ fn initHeaders(...@@ -3324,8 +3378,8 @@ fn initHeaders(
3324 .@"386" => 0x400000,3378 .@"386" => 0x400000,
3325 .AARCH64, .X86_64 => 0x200000,3379 .AARCH64, .X86_64 => 0x200000,
3326 .PPC, .PPC64 => 0x10000000,3380 .PPC, .PPC64 => 0x10000000,
3327 .S390, .S390_OLD => 0x1000000,3381 .S390 => 0x1000000,
3328 .OLD_SPARCV9, .SPARCV9 => 0x100000,3382 .SPARCV9 => 0x100000,
3329 else => 0x10000,3383 else => 0x10000,
3330 },3384 },
3331 };3385 };
...@@ -3561,14 +3615,16 @@ fn initHeaders(...@@ -3561,14 +3615,16 @@ fn initHeaders(
3561 // Reserve space for the reserved words, populated later.3615 // Reserve space for the reserved words, populated later.
3562 .size = switch (machine) {3616 .size = switch (machine) {
3563 else => @panic(@tagName(machine)),3617 else => @panic(@tagName(machine)),
3564 .X86_64 => 3 * 8,3618 .X86_64 => 3 * elf.targetPtrSize(),
3565 .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4,3619 .LOONGARCH,
3620 .SPARCV9,
3621 => elf.targetPtrSize(),
3566 },3622 },
3567 .flags = .{ .WRITE = true, .ALLOC = true },3623 .flags = .{ .WRITE = true, .ALLOC = true },
3568 .addralign = addr_align,3624 .addralign = addr_align,
3569 .entsize = @intCast(addr_align.toByteUnits()),3625 .entsize = @intCast(addr_align.toByteUnits()),
3570 });3626 });
3571 elf.shndx.got_plt = try elf.addSection(3627 if (got_plt) elf.shndx.got_plt = try elf.addSection(
3572 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,3628 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
3573 .{3629 .{
3574 .name = ".got.plt",3630 .name = ".got.plt",
...@@ -3578,7 +3634,7 @@ fn initHeaders(...@@ -3578,7 +3634,7 @@ fn initHeaders(
3578 else => @panic(@tagName(machine)),3634 else => @panic(@tagName(machine)),
3579 .@"386" => 3 * 4,3635 .@"386" => 3 * 4,
3580 .X86_64 => 3 * 8,3636 .X86_64 => 3 * 8,
3581 .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4,3637 .LOONGARCH => 2 * elf.targetPtrSize(),
3582 },3638 },
3583 .addralign = addr_align,3639 .addralign = addr_align,
3584 .entsize = @intCast(addr_align.toByteUnits()),3640 .entsize = @intCast(addr_align.toByteUnits()),
...@@ -3587,7 +3643,14 @@ fn initHeaders(...@@ -3587,7 +3643,14 @@ fn initHeaders(
3587 elf.shndx.plt = try elf.addSection(elf.ni.text, .{3643 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
3588 .name = ".plt",3644 .name = ".plt",
3589 .type = .PROGBITS,3645 .type = .PROGBITS,
3590 .flags = .{ .ALLOC = true, .EXECINSTR = true },3646 .flags = .{
3647 .ALLOC = true,
3648 .EXECINSTR = true,
3649 .WRITE = switch (machine) {
3650 .SPARCV9 => true,
3651 else => false,
3652 },
3653 },
3591 .size = init_plt_size,3654 .size = init_plt_size,
3592 .addralign = plt_align,3655 .addralign = plt_align,
3593 .node_align = elf.mf.flags.block_size,3656 .node_align = elf.mf.flags.block_size,
...@@ -3686,7 +3749,7 @@ fn initHeaders(...@@ -3686,7 +3749,7 @@ fn initHeaders(
3686 .type = .RELA,3749 .type = .RELA,
3687 .flags = .{ .ALLOC = true, .INFO_LINK = true },3750 .flags = .{ .ALLOC = true, .INFO_LINK = true },
3688 .link = elf.shndx.dynsym.toSection().?,3751 .link = elf.shndx.dynsym.toSection().?,
3689 .info = elf.shndx.got_plt.toSection().?,3752 .info = (if (got_plt) elf.shndx.got_plt else elf.shndx.plt).toSection().?,
3690 .addralign = addr_align,3753 .addralign = addr_align,
3691 .entsize = rela_size,3754 .entsize = rela_size,
3692 .node_align = elf.mf.flags.block_size,3755 .node_align = elf.mf.flags.block_size,
...@@ -3758,6 +3821,7 @@ fn initHeaders(...@@ -3758,6 +3821,7 @@ fn initHeaders(
3758 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12);3821 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12);
3759 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12);3822 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12);
3760 },3823 },
3824 .SPARCV9 => {},
3761 }3825 }
3762 }3826 }
3763 if (comp.config.any_non_single_threaded) {3827 if (comp.config.any_non_single_threaded) {
...@@ -3782,7 +3846,9 @@ fn initHeaders(...@@ -3782,7 +3846,9 @@ fn initHeaders(
3782 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);3846 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);
3783 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);3847 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);
3784 },3848 },
3785 .LOONGARCH => {3849 .LOONGARCH,
3850 .SPARCV9,
3851 => {
3786 try elf.got.ensureUnusedCapacity(gpa, 1);3852 try elf.got.ensureUnusedCapacity(gpa, 1);
3787 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {3853 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
3788 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },3854 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
...@@ -4100,12 +4166,11 @@ fn identData(elf: *const Elf) std.elf.DATA {...@@ -4100,12 +4166,11 @@ fn identData(elf: *const Elf) std.elf.DATA {
4100 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);4166 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
4101}4167}
41024168
4169fn targetPtrSize(elf: *const Elf) u32 {
4170 return elf.identClass().size();
4171}
4103fn targetEndian(elf: *const Elf) std.lang.Endian {4172fn targetEndian(elf: *const Elf) std.lang.Endian {
4104 return switch (elf.identData()) {4173 return elf.identData().endian();
4105 .NONE, _ => unreachable,
4106 .@"2LSB" => .little,
4107 .@"2MSB" => .big,
4108 };
4109}4174}
4110fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child {4175fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child {
4111 const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer;4176 const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer;
...@@ -5462,6 +5527,11 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -5462,6 +5527,11 @@ fn prelinkInner(elf: *Elf) Error!void {
5462 };5527 };
5463 }5528 }
54645529
5530 const got_plt = switch (elf.ehdrField(.machine)) {
5531 .SPARCV9 => false,
5532 else => true,
5533 };
5534
5465 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {5535 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
5466 .NONE, _ => unreachable,5536 .NONE, _ => unreachable,
5467 inline else => |ct_class| {5537 inline else => |ct_class| {
...@@ -5645,7 +5715,7 @@ fn prelinkInner(elf: *Elf) Error!void {...@@ -5645,7 +5715,7 @@ fn prelinkInner(elf: *Elf) Error!void {
5645 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(5715 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(
5646 dynamic_ni,5716 dynamic_ni,
5647 @sizeOf(ElfN.Addr) * (2 * index + 1),5717 @sizeOf(ElfN.Addr) * (2 * index + 1),
5648 .local(elf.shndx.got_plt.get(elf).lsi),5718 .local((if (got_plt) elf.shndx.got_plt else elf.shndx.plt).get(elf).lsi),
5649 0,5719 0,
5650 dsorel,5720 dsorel,
5651 );5721 );
...@@ -7370,6 +7440,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad...@@ -7370,6 +7440,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
7370 },7440 },
7371 }7441 }
7372 },7442 },
7443 .SPARCV9 => switch (which) {
7444 .plt => {
7445 // Update the offsets of the relocation entries in `.rela.plt`.
7446 const rela_plt_shndx = elf.shndx.rela_plt;
7447 for (0..elf.plt.count()) |plt_index| {
7448 if (elf.pltEntryIsDead(plt_index)) continue;
7449 rela_plt_shndx.relaAdjustOffset(elf, @enumFromInt(plt_index), old_addr, addr);
7450 }
7451 },
7452 .plt_sec, .got_plt => unreachable,
7453 },
7373 }7454 }
7374}7455}
73757456
src/link/sparc.zig created+197
...@@ -0,0 +1,197 @@
1const std = @import("std");
2
3/// Calculation operands:
4///
5/// * `A`: relocation addend
6/// * `G`: symbol GOT slot offset
7/// * `GOT`: GOT base address (`_GLOBAL_OFFSET_TABLE_` value)
8/// * `L`: symbol PLT slot address
9/// * `O`: secondary relocation addend
10/// * `P`: relocation address
11/// * `S`: symbol value
12/// * `Z`: symbol size
13///
14/// Field semantics:
15///
16/// * `T-*`: truncate (don't check for overflow)
17/// * `V-*`: verify (check for overflow)
18pub const reloc = struct {
19 /// R_SPARC_8 (V-byte8) = S + A
20 /// R_SPARC_DISP8 (V-byte8) = S + A - P
21 pub const Byte8 = packed struct(u8) {
22 byte8: u8,
23 };
24
25 /// R_SPARC_16 (V-half16) = S + A
26 /// R_SPARC_DISP16 (V-half16) = S + A - P
27 /// R_SPARC_UA16 (V-half16) = S + A
28 pub const Half16 = packed struct(u16) {
29 half16: u16,
30 };
31
32 /// R_SPARC_32 (V-word32) = S + A
33 /// R_SPARC_GLOB_DAT (V-word32) = S + A [32-bit only]
34 /// R_SPARC_UA32 (V-word32) = S + A
35 /// R_SPARC_PCPLT32 (V-word32) = L + A - P
36 /// R_SPARC_REGISTER (V-word32) = S + A [32-bit only]
37 /// R_SPARC_TLS_DTPMOD32 (V-word32) = @dtpmod(S + A)
38 /// R_SPARC_TLS_DTPOFF32 (V-word32) = @dtpoff(S + A)
39 /// R_SPARC_TLS_TPOFF32 (V-word32) = @tpoff(S + A)
40 /// R_SPARC_SIZE32 (V-word32) = Z + A
41 pub const Word32 = packed struct(u32) {
42 word32: u32,
43 };
44
45 /// R_SPARC_GLOB_DAT (V-word64) = S + A [64-bit only]
46 /// R_SPARC_64 (V-word64) = S + A
47 /// R_SPARC_DISP64 (V-word64) = S + A - P
48 /// R_SPARC_PLT64 (V-word64) = L + A
49 /// R_SPARC_REGISTER (V-word64) = S + A [64-bit only]
50 /// R_SPARC_UA64 (V-word64) = S + A
51 /// R_SPARC_TLS_DTPMOD64 (V-word64) = @dtpmod(S + A)
52 /// R_SPARC_TLS_DTPOFF64 (V-word64) = @dtpoff(S + A)
53 /// R_SPARC_TLS_TPOFF64 (V-word64) = @tpoff(S + A)
54 /// R_SPARC_SIZE64 (V-word64) = Z + A
55 pub const Word64 = packed struct(u64) {
56 word64: u64,
57 };
58
59 /// R_SPARC_5 (V-imm5) = S + A
60 pub const Imm5 = packed struct(u32) {
61 imm5: u5,
62 b5_31: u27,
63 };
64
65 /// R_SPARC_6 (V-imm6) = S + A
66 pub const Imm6 = packed struct(u32) {
67 imm6: u6,
68 b6_31: u26,
69 };
70
71 /// R_SPARC_7 (V-imm7) = S + A
72 pub const Imm7 = packed struct(u32) {
73 imm7: u7,
74 b7_31: u25,
75 };
76
77 /// R_SPARC_M44 (T-imm10) = ((S + A) >> 12) & 0x3ff
78 pub const Imm10 = packed struct(u32) {
79 imm10: u10,
80 b10_31: u22,
81 };
82
83 /// R_SPARC_10 (V-simm10) = S + A
84 pub const Simm10 = packed struct(u32) {
85 simm10: u10,
86 b10_31: u22,
87 };
88
89 /// R_SPARC_11 (V-simm11) = S + A
90 pub const Simm11 = packed struct(u32) {
91 simm11: u11,
92 b11_31: u21,
93 };
94
95 /// R_SPARC_L44 (T-imm13) = (S + A) & 0xfff
96 /// R_SPARC_GOTDATA_LOX10 (T-imm13) = ((S + A - GOT) & 0x3ff) | (((S + A - GOT) >> 31) & 0x1c00)
97 /// R_SPARC_GOTDATA_OP_LOX10 (T-imm13) = (G & 0x3ff) | ((G >> 31) & 0x1c00)
98 pub const Imm13 = packed struct(u32) {
99 imm13: u13,
100 b13_31: u19,
101 };
102
103 /// R_SPARC_13 (V-simm13) = S + A
104 /// R_SPARC_LO10 (T-simm13) = (S + A) & 0x3ff
105 /// R_SPARC_GOT10 (T-simm13) = G & 0x3ff
106 /// R_SPARC_GOT13 (V-simm13) = G
107 /// R_SPARC_PC10 (T-simm13) = (S + A - P) & 0x3ff
108 /// R_SPARC_LOPLT10 (T-simm13) = (L + A) & 0x3ff
109 /// R_SPARC_PCPLT10 (V-simm13) = (L + A - P) & 0x3ff
110 /// R_SPARC_OLO10 (V-simm13) = ((S + A) & 0x3ff) + O
111 /// R_SPARC_HM10 (T-simm13) = ((S + A) >> 32) & 0x3ff
112 /// R_SPARC_PC_HM10 (T-simm13) = ((S + A - P) >> 32) & 0x3ff
113 /// R_SPARC_LOX10 (T-simm13) = ((S + A) & 0x3ff) | 0x1c00
114 /// R_SPARC_TLS_GD_LO10 (T-simm13) = @dtlndx(S + A) & 0x3ff
115 /// R_SPARC_TLS_LDM_LO10 (T-simm13) = @tmndx(S + A) & 0x3ff
116 /// R_SPARC_TLS_LDO_LOX10 (T-simm13) = @dtpoff(S + A) & 0x3ff
117 /// R_SPARC_TLS_IE_LO10 (T-simm13) = @got(@tpoff(S + A)) & 0x3ff
118 /// R_SPARC_TLS_LE_LOX10 (T-simm13) = (@tpoff(S + A) & 0x3ff) | 0x1c00
119 pub const Simm13 = packed struct(u32) {
120 simm13: u13,
121 b13_31: u19,
122 };
123
124 /// R_SPARC_HI22 (T-imm22) = (S + A) >> 10 [32-bit only]
125 /// R_SPARC_HI22 (V-imm22) = (S + A) >> 10 [64-bit only]
126 /// R_SPARC_22 (V-imm22) = S + A
127 /// R_SPARC_HIPLT22 (T-imm22) = (L + A) >> 10
128 /// R_SPARC_HH22 (V-imm22) = (S + A) >> 42
129 /// R_SPARC_LM22 (T-imm22) = (S + A) >> 10
130 /// R_SPARC_PC_HH22 (V-imm22) = (S + A - P) >> 42
131 /// R_SPARC_PC_LM22 (T-imm22) = (S + A - P) >> 10
132 /// R_SPARC_HIX22 (V-imm22) = ((S + A) ^ 0xffffffffffffffff) >> 10
133 /// R_SPARC_H44 (V-imm22) = (S + A) >> 22
134 /// R_SPARC_TLS_LE_HIX22 (T-imm22) = (@tpoff(S + A) ^ 0xffffffffffffffff) >> 10
135 /// R_SPARC_GOTDATA_HIX22 (V-imm22) = ((S + A - GOT) >> 10) ^ ((S + A - GOT) >> 31)
136 /// R_SPARC_GOTDATA_OP_HIX22 (T-imm22) = (G >> 10) ^ (G >> 31)
137 /// R_SPARC_H34 (V-imm22) = (S + A) >> 12
138 pub const Imm22 = packed struct(u32) {
139 imm22: u22,
140 b22_31: u10,
141 };
142
143 /// R_SPARC_GOT22 (T-simm22) = G >> 10
144 /// R_SPARC_TLS_GD_HI22 (T-simm22) = @dtlndx(S + A) >> 10
145 /// R_SPARC_TLS_LDM_HI22 (T-simm22) = @tmndx(S + A) >> 10
146 /// R_SPARC_TLS_LDO_HIX22 (T-simm22) = @dtpoff(S + A) >> 10
147 /// R_SPARC_TLS_IE_HI22 (T-simm22) = @got(@tpoff(S + A)) >> 10
148 pub const Simm22 = packed struct(u32) {
149 simm22: u22,
150 b22_31: u10,
151 };
152
153 /// R_SPARC_WDISP19 (V-disp19) = (S + A - P) >> 2
154 pub const Disp19 = packed struct(u32) {
155 disp19: u19,
156 b19_31: u13,
157 };
158
159 /// R_SPARC_WDISP22 (V-disp22) = (S + A - P) >> 2
160 /// R_SPARC_PC22 (V-disp22) = (S + A - P) >> 10
161 /// R_SPARC_PCPLT22 (V-disp22) = (L + A - P) >> 10
162 pub const Disp22 = packed struct(u32) {
163 disp22: u22,
164 b22_31: u10,
165 };
166
167 /// R_SPARC_WDISP30 (V-disp30) = (S + A - P) >> 2
168 /// R_SPARC_WPLT30 (V-disp30) = (L + A - P) >> 2
169 /// R_SPARC_TLS_GD_CALL (V-disp30) = (L + A - P) >> 2
170 /// R_SPARC_TLS_LDM_CALL (V-disp30) = (L + A - P) >> 2
171 pub const Disp30 = packed struct(u32) {
172 disp30: u30,
173 b30_31: u2,
174 };
175
176 /// R_SPARC_DISP32 (V-disp32) = S + A - P
177 pub const Disp32 = packed struct(u32) {
178 disp32: u32,
179 };
180
181 /// R_SPARC_WDISP10 (V-d2/disp8) = (S + A - P) >> 2
182 pub const D2Disp8 = packed struct(u32) {
183 b0_3: u4,
184 disp8: u8,
185 b12_17: u6,
186 d2: u2,
187 b20_31: u12,
188 };
189
190 /// R_SPARC_WDISP16 (V-d2/disp14) = (S + A - P) >> 2
191 pub const D2Disp14 = packed struct(u32) {
192 disp14: u14,
193 b14_19: u6,
194 d2: u2,
195 b22_31: u10,
196 };
197};