authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-14 15:51:35+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-15 20:13:13+02:00
logb3e2902e1d892204f727083d02937320fbb04e39
tree633342ea3e72511539cfa398b2535e49b02fce2a
parenta0e093bc0f4abb4d75ac75330df5d84466a8ca78
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

Elf2: implement R_SPARC_OLO10

Elf2 now supports all SPARC relocations that are used by real toolchains.

1 files changed, 67 insertions(+), 16 deletions(-)

src/link/Elf2.zig+67-16
......@@ -1210,7 +1210,7 @@ const SymbolReloc = struct {
12101210 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.
12111211 target: Symbol.Id,
12121212 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.
1213 addend: i64,
1213 addend: SymbolReloc.Addend,
12141214 /// Specifies how to apply the relocation.
12151215 ///
12161216 /// When emitting a relocatable, this field is `undefined`.
......@@ -1251,6 +1251,18 @@ const SymbolReloc = struct {
12511251 return shndx;
12521252 }
12531253
1254 const Addend = packed union(u64) {
1255 normal: i64,
1256 /// Only valid for `Type.special(.sparc_olo10)`.
1257 sparc_olo10: packed struct {
1258 /// The first addend from `r_addend`.
1259 a: u10,
1260 /// The second addend from the upper `r_info` type bits.
1261 o: i24,
1262 _pad: u30 = 0,
1263 },
1264 };
1265
12541266 /// Instead of using the ELF relocation enums, we have our own internal representation for
12551267 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
12561268 /// sharing a lot of relocation handling between multiple relocs and target architectures.
......@@ -1504,6 +1516,7 @@ const SymbolReloc = struct {
15041516 larch_b26,
15051517 larch_call36,
15061518
1519 sparc_olo10,
15071520 sparc_hix22,
15081521 sparc_le_hix22,
15091522 sparc_wdisp10,
......@@ -1513,13 +1526,14 @@ const SymbolReloc = struct {
15131526 s: Special,
15141527 elf: *Elf,
15151528 target: Symbol.Id,
1516 addend: u64,
1529 addend: SymbolReloc.Addend,
15171530 dest_vaddr: u64,
15181531 dest_slice: []u8,
15191532 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1533 const normal_addend: u64 = @bitCast(addend.normal);
15201534 switch (s) {
15211535 .larch_pcala_hi20 => {
1522 const val = target.value(elf) +% addend;
1536 const val = target.value(elf) +% normal_addend;
15231537 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
15241538 elf.targetStore(inst, .{
15251539 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1528,7 +1542,7 @@ const SymbolReloc = struct {
15281542 });
15291543 },
15301544 .larch_pcala64_lo20 => {
1531 const val = target.value(elf) +% addend;
1545 const val = target.value(elf) +% normal_addend;
15321546 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
15331547 elf.targetStore(inst, .{
15341548 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1537,7 +1551,7 @@ const SymbolReloc = struct {
15371551 });
15381552 },
15391553 .larch_pcala64_hi12 => {
1540 const val = target.value(elf) +% addend;
1554 const val = target.value(elf) +% normal_addend;
15411555 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
15421556 elf.targetStore(inst, .{
15431557 .b0_9 = elf.targetLoad(inst).b0_9,
......@@ -1547,7 +1561,7 @@ const SymbolReloc = struct {
15471561 },
15481562 .larch_b21, .larch_b26, .larch_call36 => {
15491563 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);
1550 const jump_offset: i64 = @bitCast(target_vaddr +% addend -% dest_vaddr);
1564 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
15511565 if ((jump_offset >> 2) << 2 != jump_offset) {
15521566 return error.RelocationMisaligned;
15531567 }
......@@ -1606,13 +1620,26 @@ const SymbolReloc = struct {
16061620 }
16071621 },
16081622
1623 .sparc_olo10 => {
1624 const addends = addend.sparc_olo10;
1625 const lo10: i64 = @as(u10, @truncate(target.value(elf) +% addends.a));
1626 const simm13 = std.math.cast(i13, lo10 + addends.o) orelse return error.RelocationOverflow;
1627 const dest_ptr: *align(1) packed struct(u32) {
1628 simm13: u13,
1629 b13_31: u19,
1630 } = @ptrCast(dest_slice);
1631 elf.targetStore(dest_ptr, .{
1632 .simm13 = @bitCast(simm13),
1633 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
1634 });
1635 },
16091636 .sparc_hix22 => {
16101637 const dest_ptr: *align(1) packed struct(u32) {
16111638 imm22: u22,
16121639 b22_31: u10,
16131640 } = @ptrCast(dest_slice);
16141641 elf.targetStore(dest_ptr, .{
1615 .imm22 = @truncate(~(target.value(elf) +% addend) >> 10),
1642 .imm22 = @truncate(~(target.value(elf) +% normal_addend) >> 10),
16161643 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
16171644 });
16181645 },
......@@ -1629,13 +1656,13 @@ const SymbolReloc = struct {
16291656 b22_31: u10,
16301657 } = @ptrCast(dest_slice);
16311658 elf.targetStore(dest_ptr, .{
1632 .imm22 = @truncate(~(target.value(elf) +% addend -% tls_size) >> 10),
1659 .imm22 = @truncate(~(target.value(elf) +% normal_addend -% tls_size) >> 10),
16331660 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
16341661 });
16351662 },
16361663 .sparc_wdisp16, .sparc_wdisp10 => {
16371664 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);
1638 const jump_offset: i64 = @bitCast(target_vaddr +% addend -% dest_vaddr);
1665 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
16391666 if ((jump_offset >> 2) << 2 != jump_offset) {
16401667 return error.RelocationMisaligned;
16411668 }
......@@ -1719,6 +1746,7 @@ const SymbolReloc = struct {
17191746 .larch_b26,
17201747 .larch_call36,
17211748
1749 .sparc_olo10,
17221750 .sparc_hix22,
17231751 .sparc_wdisp10,
17241752 .sparc_wdisp16,
......@@ -1815,7 +1843,7 @@ const SymbolReloc = struct {
18151843 .special => return reloc.type.action.special.applyInner(
18161844 elf,
18171845 reloc.target,
1818 addend,
1846 reloc.addend,
18191847 dest_vaddr,
18201848 dest_slice,
18211849 ),
......@@ -8986,7 +9014,7 @@ fn addRelocAssumeCapacity(
89869014 .offset = offset,
89879015 .type = undefined,
89889016 .target = target,
8989 .addend = addend,
9017 .addend = .{ .normal = addend },
89909018 .next = next,
89919019 .prev = .none,
89929020 .rela_index = rela_index.toOptional(),
......@@ -9064,7 +9092,8 @@ fn addRelocAssumeCapacity(
90649092 _ => return error.UnknownRelocation,
90659093 else => return error.UnimplementedRelocation,
90669094 },
9067 .SPARCV9 => switch (@"type".SPARC) {
9095 // For SPARC, only the 8 lower bits represent the type. See the `R_SPARC_OLO10` prong below for more info.
9096 .SPARCV9 => switch (@as(std.elf.R_SPARC, @fromBackingInt(@as(u8, @truncate(@backingInt(@"type".SPARC)))))) {
90689097 .NONE => {},
90699098 _ => return error.UnknownRelocation,
90709099
......@@ -9086,9 +9115,6 @@ fn addRelocAssumeCapacity(
90869115 .PCPLT10,
90879116 => return error.UnimplementedRelocation,
90889117
9089 // Needs to use the second addend in `ELF64_R_TYPE_DATA(reloc.r_info)` which we currently can't model.
9090 .OLO10 => return error.UnimplementedRelocation,
9091
90929118 // Does not patch any bytes. Together with `STT_SPARC_REGISTER`, this is used to indicate that an object
90939119 // file owns a global register and what value it should be initialized to. I don't think this sees any
90949120 // real-world use.
......@@ -9175,6 +9201,20 @@ fn addRelocAssumeCapacity(
91759201 try elf.addSymbolRelocAssumeCapacity(node, offset, callee_sym, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" }));
91769202 },
91779203
9204 // `R_SPARC_OLO10` packs a secondary addend into the upper 24 bits. Conceptually, this relocation is
9205 // just `R_SPARC_LO10` (with `r_addend`) + `R_SPARC_13` (with `r_info` addend) applied in sequence. We
9206 // can neatly fit both into the single `addend` value, to be handled by `SymbolReloc.Special.applyInner`.
9207 .OLO10 => |t| try elf.addSymbolRelocAssumeCapacityInner(
9208 node,
9209 offset,
9210 target,
9211 .{ .sparc_olo10 = .{
9212 .a = @truncate(@as(u64, @bitCast(addend))),
9213 .o = @truncate(@as(i32, @bitCast(@backingInt(t) >> 8))),
9214 } },
9215 .special(.sparc_olo10),
9216 ),
9217
91789218 // The following relocations are all represented by the ABI as writing to a 13 bit
91799219 // field (32[12:0]), but masking out some bits of the value. To simplify our logic
91809220 // for applying relocations, we split this action up: we create a relocation writing
......@@ -9324,6 +9364,16 @@ fn addSymbolRelocAssumeCapacity(
93249364 target: Symbol.Id,
93259365 addend: i64,
93269366 @"type": SymbolReloc.Type,
9367) Error!void {
9368 return elf.addSymbolRelocAssumeCapacityInner(node, offset, target, .{ .normal = addend }, @"type");
9369}
9370fn addSymbolRelocAssumeCapacityInner(
9371 elf: *Elf,
9372 node: MappedFile.Node.Index,
9373 offset: u64,
9374 target: Symbol.Id,
9375 addend: SymbolReloc.Addend,
9376 @"type": SymbolReloc.Type,
93279377) Error!void {
93289378 assert(elf.ehdrType() != .REL);
93299379
......@@ -9353,6 +9403,7 @@ fn addSymbolRelocAssumeCapacity(
93539403 .larch_pcala64_lo20,
93549404 .larch_pcala64_hi12,
93559405
9406 .sparc_olo10,
93569407 .sparc_hix22,
93579408 => true,
93589409
......@@ -9447,7 +9498,7 @@ fn addSymbolRelocAssumeCapacity(
94479498 .type = dynamic_reloc_type,
94489499 .offset = node_vaddr + offset,
94499500 .raw_sym_index = target.unwrap().global.dynsymIndex(elf).?,
9450 .addend = addend,
9501 .addend = addend.normal,
94519502 }).toOptional();
94529503 },
94539504 }