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");
2626const codegen = @import("codegen.zig");
2727const crash_report = @import("crash_report.zig");
2828
29pub const aarch64 = @import("link/aarch64.zig");
3029pub const LdScript = @import("link/LdScript.zig");
3130pub const Queue = @import("link/Queue.zig");
3231pub const ConstPool = @import("link/ConstPool.zig");
3332
33pub const aarch64 = @import("link/aarch64.zig");
3434pub const loongarch = @import("link/loongarch.zig");
35pub const sparc = @import("link/sparc.zig");
3536
3637pub const Error = Allocator.Error || Io.Cancelable || error{
3738 /// 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),
2828phdrs: std.ArrayList(MappedFile.Node.Index),
2929shndx: struct {
3030 got: Section.Index,
31 /// Always `.UNDEF` on some targets (e.g. SPARC).
3132 got_plt: Section.Index,
3233 plt: Section.Index,
34 /// Only created for x86 targets; `.UNDEF` everywhere else.
3335 plt_sec: Section.Index,
3436 dynsym: Section.Index,
3537 dynstr: Section.Index,
......@@ -897,11 +899,12 @@ const GotReloc = struct {
897899};
898900
899901pub const MachineRelocType = union {
900 X86_64: std.elf.R_X86_64,
901902 AARCH64: std.elf.R_AARCH64,
902903 LOONGARCH: std.elf.R_LARCH,
903 RISCV: std.elf.R_RISCV,
904904 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
906909 pub fn none(elf: *Elf) MachineRelocType {
907910 return switch (elf.ehdrField(.machine)) {
......@@ -910,6 +913,7 @@ pub const MachineRelocType = union {
910913 .LOONGARCH => .{ .LOONGARCH = .NONE },
911914 .PPC64 => .{ .PPC64 = .NONE },
912915 .RISCV => .{ .RISCV = .NONE },
916 .SPARCV9 => .{ .SPARC = .NONE },
913917 .X86_64 => .{ .X86_64 = .NONE },
914918 };
915919 }
......@@ -920,6 +924,7 @@ pub const MachineRelocType = union {
920924 .LOONGARCH => .{ .LOONGARCH = .COPY },
921925 .PPC64 => .{ .PPC64 = .COPY },
922926 .RISCV => .{ .RISCV = .COPY },
927 .SPARCV9 => .{ .SPARC = .COPY },
923928 .X86_64 => .{ .X86_64 = .COPY },
924929 };
925930 }
......@@ -930,43 +935,57 @@ pub const MachineRelocType = union {
930935 .LOONGARCH => .{ .LOONGARCH = .RELATIVE },
931936 .PPC64 => .{ .PPC64 = .RELATIVE },
932937 .RISCV => .{ .RISCV = .RELATIVE },
938 .SPARCV9 => .{ .SPARC = .RELATIVE },
933939 .X86_64 => .{ .X86_64 = .RELATIVE },
934940 };
935941 }
936942 pub fn jumpSlot(elf: *Elf) MachineRelocType {
937943 return switch (elf.ehdrField(.machine)) {
938944 else => unreachable,
939 .X86_64 => .{ .X86_64 = .JUMP_SLOT },
945 .AARCH64 => .{ .AARCH64 = .JUMP_SLOT },
940946 .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 },
941951 };
942952 }
943953 pub fn globDat(elf: *Elf) MachineRelocType {
944954 return switch (elf.ehdrField(.machine)) {
945955 else => unreachable,
946 .X86_64 => .{ .X86_64 = .GLOB_DAT },
956 .AARCH64 => .{ .AARCH64 = .GLOB_DAT },
947957 .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 },
948962 };
949963 }
950964 pub fn dtpOffAddr(elf: *Elf) MachineRelocType {
951965 return switch (elf.ehdrField(.machine)) {
952966 else => unreachable,
953 .X86_64 => .{ .X86_64 = .DTPOFF64 },
954967 .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 },
955972 };
956973 }
957974 pub fn absAddr(elf: *Elf) MachineRelocType {
958975 return switch (elf.ehdrField(.machine)) {
959976 else => unreachable,
960 .AARCH64 => .{ .AARCH64 = .ABS64 },
977 .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 },
961978 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" },
962979 .PPC64 => .{ .PPC64 = .ADDR64 },
963 .RISCV => .{ .RISCV = .@"64" },
964 .X86_64 => .{ .X86_64 = .@"64" },
980 .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" },
981 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" },
982 .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" },
965983 };
966984 }
967985 pub fn sizeAddr(elf: *Elf) MachineRelocType {
968986 return switch (elf.ehdrField(.machine)) {
969987 else => unreachable,
988 .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .SIZE64 else .SIZE32 },
970989 .X86_64 => .{ .X86_64 = .SIZE64 },
971990 };
972991 }
......@@ -974,6 +993,7 @@ pub const MachineRelocType = union {
974993 pub fn wrap(int: u32, elf: *Elf) MachineRelocType {
975994 return switch (elf.ehdrField(.machine)) {
976995 else => unreachable,
996 .SPARCV9 => .{ .SPARC = @enumFromInt(int) },
977997 inline .AARCH64,
978998 .LOONGARCH,
979999 .PPC64,
......@@ -985,6 +1005,7 @@ pub const MachineRelocType = union {
9851005 pub fn unwrap(rt: MachineRelocType, elf: *Elf) u32 {
9861006 return switch (elf.ehdrField(.machine)) {
9871007 else => unreachable,
1008 .SPARCV9 => @intFromEnum(rt.SPARC),
9881009 inline .AARCH64,
9891010 .LOONGARCH,
9901011 .PPC64,
......@@ -1448,10 +1469,7 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
14481469 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14491470
14501471 // Ensure the `.got.plt` section's node is big enough
1451 const got_plt_need_size: usize = switch (elf.identClass()) {
1452 .NONE, _ => unreachable,
1453 inline else => |class| @sizeOf(class.ElfN().Addr) * (3 + need_plt_capacity),
1454 };
1472 const got_plt_need_size: usize = elf.targetPtrSize() * (3 + need_plt_capacity);
14551473 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14561474
14571475 // Ensure the `.plt.sec` section's node is big enough
......@@ -1460,16 +1478,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void {
14601478 },
14611479 .LOONGARCH => {
14621480 // 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);
14641482 try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size);
14651483
14661484 // Ensure the `.got.plt` section's node is big enough
1467 const got_plt_need_size: usize = switch (elf.identClass()) {
1468 .NONE, _ => unreachable,
1469 inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity),
1470 };
1485 const got_plt_need_size: usize = elf.targetPtrSize() * (2 + need_plt_capacity);
14711486 try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size);
14721487 },
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 },
14731493 }
14741494}
14751495/// 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
20902110 .addend = 0,
20912111 }));
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)) {
20942116 else => |machine| @panic(@tagName(machine)),
2095 .X86_64 => 3,
2096 .LOONGARCH => 2,
2117 .LOONGARCH => .{ elf.shndx.got_plt, elf.targetPtrSize() * (2 + plt_index) },
2118 .SPARCV9 => .{ elf.shndx.plt, 32 * (4 + plt_index) },
2119 .X86_64 => .{ elf.shndx.got_plt, elf.targetPtrSize() * (3 + plt_index) },
20972120 };
20982121
20992122 // 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)) {
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);
2123 elf.shndx.rela_plt.relaSetOffset(elf, @enumFromInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset);
21102124
21112125 if (plt_index < elf.plt.count()) {
21122126 // 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
21482162 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
21492163 switch (elf.shdrPtr(elf.shndx.got_plt)) {
21502164 inline else => |shdr, class| {
2151 const ent_size = @sizeOf(class.ElfN().Addr);
2152 const old_size = ent_size * (3 + plt_index);
2153 assert(elf.targetLoad(&shdr.size) == old_size);
2154 elf.targetStore(&shdr.size, old_size + ent_size);
2165 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2166 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr));
21552167 std.mem.writeInt(
21562168 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)],
21582170 @intCast(plt_addr),
21592171 target_endian,
21602172 );
......@@ -2176,7 +2188,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
21762188 i32,
21772189 plt_sec_slice[6..][0..4],
21782190 @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),
21802192 ))),
21812193 target_endian,
21822194 );
......@@ -2212,26 +2224,54 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
22122224 const got_plt_ni = elf.shndx.got_plt.get(elf).ni;
22132225 switch (elf.shdrPtr(elf.shndx.got_plt)) {
22142226 inline else => |shdr, class| {
2215 const ent_size = @sizeOf(class.ElfN().Addr);
2216 const old_size = ent_size * (2 + plt_index);
2217 assert(elf.targetLoad(&shdr.size) == old_size);
2218 elf.targetStore(&shdr.size, old_size + ent_size);
2227 assert(elf.targetLoad(&shdr.size) == got_plt_offset);
2228 elf.targetStore(&shdr.size, got_plt_offset + @sizeOf(shdr.ElfN().Addr));
22192229 std.mem.writeInt(
22202230 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)],
22222232 @intCast(plt_addr),
22232233 target_endian,
22242234 );
2225 assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size));
22262235 },
22272236 }
22282237
22292238 // 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;
22312240 // TODO: handle overflow gracefully
22322241 link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr));
22332242 link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs));
22342243 },
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 },
22352275 }
22362276}
22372277
......@@ -3084,11 +3124,12 @@ fn initHeaders(
30843124 .@"64" => .@"8",
30853125 };
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 =
30883128 switch (machine) {
30893129 else => @panic(@tagName(machine)),
3090 .X86_64 => .{ 16, .@"16", true },
3091 .LOONGARCH => .{ 32, .@"4", false },
3130 .LOONGARCH => .{ 16 * 2, .@"4", true, false },
3131 .SPARCV9 => .{ 32 * 4, .fromByteUnits(256), false, false },
3132 .X86_64 => .{ 16, .@"16", true, true },
30923133 };
30933134
30943135 const shnum: u32 = shnum: {
......@@ -3111,7 +3152,7 @@ fn initHeaders(
31113152 }
31123153 if (@"type" != .REL) {
31133154 shnum += 1; // .got
3114 shnum += 1; // .got.plt
3155 shnum += @intFromBool(got_plt); // .got.plt
31153156 shnum += 1; // .plt
31163157 shnum += @intFromBool(plt_sec); // .plt_sec
31173158 }
......@@ -3212,7 +3253,6 @@ fn initHeaders(
32123253 ehdr.phoff = 0;
32133254 ehdr.shoff = 0;
32143255 ehdr.flags = switch (machine) {
3215 .X86_64 => 0,
32163256 .LOONGARCH => e_flags: {
32173257 const target_cpu = &elf.base.comp.getTarget().cpu;
32183258 const e_flags: std.elf.loongarch.EFlags = .{
......@@ -3227,6 +3267,20 @@ fn initHeaders(
32273267 };
32283268 break :e_flags @bitCast(e_flags);
32293269 },
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,
32303284 else => @panic(@tagName(machine)),
32313285 };
32323286 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
......@@ -3324,8 +3378,8 @@ fn initHeaders(
33243378 .@"386" => 0x400000,
33253379 .AARCH64, .X86_64 => 0x200000,
33263380 .PPC, .PPC64 => 0x10000000,
3327 .S390, .S390_OLD => 0x1000000,
3328 .OLD_SPARCV9, .SPARCV9 => 0x100000,
3381 .S390 => 0x1000000,
3382 .SPARCV9 => 0x100000,
33293383 else => 0x10000,
33303384 },
33313385 };
......@@ -3561,14 +3615,16 @@ fn initHeaders(
35613615 // Reserve space for the reserved words, populated later.
35623616 .size = switch (machine) {
35633617 else => @panic(@tagName(machine)),
3564 .X86_64 => 3 * 8,
3565 .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4,
3618 .X86_64 => 3 * elf.targetPtrSize(),
3619 .LOONGARCH,
3620 .SPARCV9,
3621 => elf.targetPtrSize(),
35663622 },
35673623 .flags = .{ .WRITE = true, .ALLOC = true },
35683624 .addralign = addr_align,
35693625 .entsize = @intCast(addr_align.toByteUnits()),
35703626 });
3571 elf.shndx.got_plt = try elf.addSection(
3627 if (got_plt) elf.shndx.got_plt = try elf.addSection(
35723628 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
35733629 .{
35743630 .name = ".got.plt",
......@@ -3578,7 +3634,7 @@ fn initHeaders(
35783634 else => @panic(@tagName(machine)),
35793635 .@"386" => 3 * 4,
35803636 .X86_64 => 3 * 8,
3581 .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4,
3637 .LOONGARCH => 2 * elf.targetPtrSize(),
35823638 },
35833639 .addralign = addr_align,
35843640 .entsize = @intCast(addr_align.toByteUnits()),
......@@ -3587,7 +3643,14 @@ fn initHeaders(
35873643 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
35883644 .name = ".plt",
35893645 .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 },
35913654 .size = init_plt_size,
35923655 .addralign = plt_align,
35933656 .node_align = elf.mf.flags.block_size,
......@@ -3686,7 +3749,7 @@ fn initHeaders(
36863749 .type = .RELA,
36873750 .flags = .{ .ALLOC = true, .INFO_LINK = true },
36883751 .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().?,
36903753 .addralign = addr_align,
36913754 .entsize = rela_size,
36923755 .node_align = elf.mf.flags.block_size,
......@@ -3758,6 +3821,7 @@ fn initHeaders(
37583821 try elf.addSymbolRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .abs32_lo12);
37593822 try elf.addSymbolRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .abs32_lo12);
37603823 },
3824 .SPARCV9 => {},
37613825 }
37623826 }
37633827 if (comp.config.any_non_single_threaded) {
......@@ -3782,7 +3846,9 @@ fn initHeaders(
37823846 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none);
37833847 elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none);
37843848 },
3785 .LOONGARCH => {
3849 .LOONGARCH,
3850 .SPARCV9,
3851 => {
37863852 try elf.got.ensureUnusedCapacity(gpa, 1);
37873853 elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) {
37883854 true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) },
......@@ -4100,12 +4166,11 @@ fn identData(elf: *const Elf) std.elf.DATA {
41004166 return @enumFromInt(elf.mf.memory_map.memory[std.elf.EI.DATA]);
41014167}
41024168
4169fn targetPtrSize(elf: *const Elf) u32 {
4170 return elf.identClass().size();
4171}
41034172fn targetEndian(elf: *const Elf) std.lang.Endian {
4104 return switch (elf.identData()) {
4105 .NONE, _ => unreachable,
4106 .@"2LSB" => .little,
4107 .@"2MSB" => .big,
4108 };
4173 return elf.identData().endian();
41094174}
41104175fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child {
41114176 const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer;
......@@ -5462,6 +5527,11 @@ fn prelinkInner(elf: *Elf) Error!void {
54625527 };
54635528 }
54645529
5530 const got_plt = switch (elf.ehdrField(.machine)) {
5531 .SPARCV9 => false,
5532 else => true,
5533 };
5534
54655535 if (elf.shndx.dynamic != .UNDEF) switch (elf.identClass()) {
54665536 .NONE, _ => unreachable,
54675537 inline else => |ct_class| {
......@@ -5645,7 +5715,7 @@ fn prelinkInner(elf: *Elf) Error!void {
56455715 if (dynamic_indices.pltgot) |index| try elf.addSymbolRelocAssumeCapacity(
56465716 dynamic_ni,
56475717 @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),
56495719 0,
56505720 dsorel,
56515721 );
......@@ -7370,6 +7440,17 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
73707440 },
73717441 }
73727442 },
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 },
73737454 }
73747455}
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};