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 19:38:31+02:00
log3f4f2c640b187b5f97cf67a3399f4c8c0005e8ff
treedc641c8fb9cdf58cdf2684efb04bd3ce12e7b0b4
parent503b03daa30bfcebbd45f27feff87f74b11b45a6

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 {...@@ -1210,7 +1210,7 @@ const SymbolReloc = struct {
1210 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.1210 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.
1211 target: Symbol.Id,1211 target: Symbol.Id,
1212 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.1212 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.
1213 addend: i64,1213 addend: SymbolReloc.Addend,
1214 /// Specifies how to apply the relocation.1214 /// Specifies how to apply the relocation.
1215 ///1215 ///
1216 /// When emitting a relocatable, this field is `undefined`.1216 /// When emitting a relocatable, this field is `undefined`.
...@@ -1251,6 +1251,18 @@ const SymbolReloc = struct {...@@ -1251,6 +1251,18 @@ const SymbolReloc = struct {
1251 return shndx;1251 return shndx;
1252 }1252 }
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
1254 /// Instead of using the ELF relocation enums, we have our own internal representation for1266 /// Instead of using the ELF relocation enums, we have our own internal representation for
1255 /// relocation types. This representation is more compact (requiring only 16 bits), and allows1267 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
1256 /// sharing a lot of relocation handling between multiple relocs and target architectures.1268 /// sharing a lot of relocation handling between multiple relocs and target architectures.
...@@ -1504,6 +1516,7 @@ const SymbolReloc = struct {...@@ -1504,6 +1516,7 @@ const SymbolReloc = struct {
1504 larch_b26,1516 larch_b26,
1505 larch_call36,1517 larch_call36,
15061518
1519 sparc_olo10,
1507 sparc_hix22,1520 sparc_hix22,
1508 sparc_le_hix22,1521 sparc_le_hix22,
1509 sparc_wdisp10,1522 sparc_wdisp10,
...@@ -1513,13 +1526,14 @@ const SymbolReloc = struct {...@@ -1513,13 +1526,14 @@ const SymbolReloc = struct {
1513 s: Special,1526 s: Special,
1514 elf: *Elf,1527 elf: *Elf,
1515 target: Symbol.Id,1528 target: Symbol.Id,
1516 addend: u64,1529 addend: SymbolReloc.Addend,
1517 dest_vaddr: u64,1530 dest_vaddr: u64,
1518 dest_slice: []u8,1531 dest_slice: []u8,
1519 ) error{ RelocationMisaligned, RelocationOverflow }!void {1532 ) error{ RelocationMisaligned, RelocationOverflow }!void {
1533 const normal_addend: u64 = @bitCast(addend.normal);
1520 switch (s) {1534 switch (s) {
1521 .larch_pcala_hi20 => {1535 .larch_pcala_hi20 => {
1522 const val = target.value(elf) +% addend;1536 const val = target.value(elf) +% normal_addend;
1523 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);1537 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1524 elf.targetStore(inst, .{1538 elf.targetStore(inst, .{
1525 .b0_4 = elf.targetLoad(inst).b0_4,1539 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1528,7 +1542,7 @@ const SymbolReloc = struct {...@@ -1528,7 +1542,7 @@ const SymbolReloc = struct {
1528 });1542 });
1529 },1543 },
1530 .larch_pcala64_lo20 => {1544 .larch_pcala64_lo20 => {
1531 const val = target.value(elf) +% addend;1545 const val = target.value(elf) +% normal_addend;
1532 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);1546 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1533 elf.targetStore(inst, .{1547 elf.targetStore(inst, .{
1534 .b0_4 = elf.targetLoad(inst).b0_4,1548 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1537,7 +1551,7 @@ const SymbolReloc = struct {...@@ -1537,7 +1551,7 @@ const SymbolReloc = struct {
1537 });1551 });
1538 },1552 },
1539 .larch_pcala64_hi12 => {1553 .larch_pcala64_hi12 => {
1540 const val = target.value(elf) +% addend;1554 const val = target.value(elf) +% normal_addend;
1541 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);1555 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1542 elf.targetStore(inst, .{1556 elf.targetStore(inst, .{
1543 .b0_9 = elf.targetLoad(inst).b0_9,1557 .b0_9 = elf.targetLoad(inst).b0_9,
...@@ -1547,7 +1561,7 @@ const SymbolReloc = struct {...@@ -1547,7 +1561,7 @@ const SymbolReloc = struct {
1547 },1561 },
1548 .larch_b21, .larch_b26, .larch_call36 => {1562 .larch_b21, .larch_b26, .larch_call36 => {
1549 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);1563 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);
1551 if ((jump_offset >> 2) << 2 != jump_offset) {1565 if ((jump_offset >> 2) << 2 != jump_offset) {
1552 return error.RelocationMisaligned;1566 return error.RelocationMisaligned;
1553 }1567 }
...@@ -1606,13 +1620,26 @@ const SymbolReloc = struct {...@@ -1606,13 +1620,26 @@ const SymbolReloc = struct {
1606 }1620 }
1607 },1621 },
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 },
1609 .sparc_hix22 => {1636 .sparc_hix22 => {
1610 const dest_ptr: *align(1) packed struct(u32) {1637 const dest_ptr: *align(1) packed struct(u32) {
1611 imm22: u22,1638 imm22: u22,
1612 b22_31: u10,1639 b22_31: u10,
1613 } = @ptrCast(dest_slice);1640 } = @ptrCast(dest_slice);
1614 elf.targetStore(dest_ptr, .{1641 elf.targetStore(dest_ptr, .{
1615 .imm22 = @truncate(~(target.value(elf) +% addend) >> 10),1642 .imm22 = @truncate(~(target.value(elf) +% normal_addend) >> 10),
1616 .b22_31 = elf.targetLoad(dest_ptr).b22_31,1643 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1617 });1644 });
1618 },1645 },
...@@ -1629,13 +1656,13 @@ const SymbolReloc = struct {...@@ -1629,13 +1656,13 @@ const SymbolReloc = struct {
1629 b22_31: u10,1656 b22_31: u10,
1630 } = @ptrCast(dest_slice);1657 } = @ptrCast(dest_slice);
1631 elf.targetStore(dest_ptr, .{1658 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),
1633 .b22_31 = elf.targetLoad(dest_ptr).b22_31,1660 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1634 });1661 });
1635 },1662 },
1636 .sparc_wdisp16, .sparc_wdisp10 => {1663 .sparc_wdisp16, .sparc_wdisp10 => {
1637 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);1664 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);
1639 if ((jump_offset >> 2) << 2 != jump_offset) {1666 if ((jump_offset >> 2) << 2 != jump_offset) {
1640 return error.RelocationMisaligned;1667 return error.RelocationMisaligned;
1641 }1668 }
...@@ -1719,6 +1746,7 @@ const SymbolReloc = struct {...@@ -1719,6 +1746,7 @@ const SymbolReloc = struct {
1719 .larch_b26,1746 .larch_b26,
1720 .larch_call36,1747 .larch_call36,
17211748
1749 .sparc_olo10,
1722 .sparc_hix22,1750 .sparc_hix22,
1723 .sparc_wdisp10,1751 .sparc_wdisp10,
1724 .sparc_wdisp16,1752 .sparc_wdisp16,
...@@ -1815,7 +1843,7 @@ const SymbolReloc = struct {...@@ -1815,7 +1843,7 @@ const SymbolReloc = struct {
1815 .special => return reloc.type.action.special.applyInner(1843 .special => return reloc.type.action.special.applyInner(
1816 elf,1844 elf,
1817 reloc.target,1845 reloc.target,
1818 addend,1846 reloc.addend,
1819 dest_vaddr,1847 dest_vaddr,
1820 dest_slice,1848 dest_slice,
1821 ),1849 ),
...@@ -8986,7 +9014,7 @@ fn addRelocAssumeCapacity(...@@ -8986,7 +9014,7 @@ fn addRelocAssumeCapacity(
8986 .offset = offset,9014 .offset = offset,
8987 .type = undefined,9015 .type = undefined,
8988 .target = target,9016 .target = target,
8989 .addend = addend,9017 .addend = .{ .normal = addend },
8990 .next = next,9018 .next = next,
8991 .prev = .none,9019 .prev = .none,
8992 .rela_index = rela_index.toOptional(),9020 .rela_index = rela_index.toOptional(),
...@@ -9064,7 +9092,8 @@ fn addRelocAssumeCapacity(...@@ -9064,7 +9092,8 @@ fn addRelocAssumeCapacity(
9064 _ => return error.UnknownRelocation,9092 _ => return error.UnknownRelocation,
9065 else => return error.UnimplementedRelocation,9093 else => return error.UnimplementedRelocation,
9066 },9094 },
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)))))) {
9068 .NONE => {},9097 .NONE => {},
9069 _ => return error.UnknownRelocation,9098 _ => return error.UnknownRelocation,
90709099
...@@ -9086,9 +9115,6 @@ fn addRelocAssumeCapacity(...@@ -9086,9 +9115,6 @@ fn addRelocAssumeCapacity(
9086 .PCPLT10,9115 .PCPLT10,
9087 => return error.UnimplementedRelocation,9116 => 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
9092 // Does not patch any bytes. Together with `STT_SPARC_REGISTER`, this is used to indicate that an object9118 // Does not patch any bytes. Together with `STT_SPARC_REGISTER`, this is used to indicate that an object
9093 // file owns a global register and what value it should be initialized to. I don't think this sees any9119 // file owns a global register and what value it should be initialized to. I don't think this sees any
9094 // real-world use.9120 // real-world use.
...@@ -9175,6 +9201,20 @@ fn addRelocAssumeCapacity(...@@ -9175,6 +9201,20 @@ fn addRelocAssumeCapacity(
9175 try elf.addSymbolRelocAssumeCapacity(node, offset, callee_sym, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" }));9201 try elf.addSymbolRelocAssumeCapacity(node, offset, callee_sym, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" }));
9176 },9202 },
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
9178 // The following relocations are all represented by the ABI as writing to a 13 bit9218 // The following relocations are all represented by the ABI as writing to a 13 bit
9179 // field (32[12:0]), but masking out some bits of the value. To simplify our logic9219 // field (32[12:0]), but masking out some bits of the value. To simplify our logic
9180 // for applying relocations, we split this action up: we create a relocation writing9220 // for applying relocations, we split this action up: we create a relocation writing
...@@ -9324,6 +9364,16 @@ fn addSymbolRelocAssumeCapacity(...@@ -9324,6 +9364,16 @@ fn addSymbolRelocAssumeCapacity(
9324 target: Symbol.Id,9364 target: Symbol.Id,
9325 addend: i64,9365 addend: i64,
9326 @"type": SymbolReloc.Type,9366 @"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,
9327) Error!void {9377) Error!void {
9328 assert(elf.ehdrType() != .REL);9378 assert(elf.ehdrType() != .REL);
93299379
...@@ -9353,6 +9403,7 @@ fn addSymbolRelocAssumeCapacity(...@@ -9353,6 +9403,7 @@ fn addSymbolRelocAssumeCapacity(
9353 .larch_pcala64_lo20,9403 .larch_pcala64_lo20,
9354 .larch_pcala64_hi12,9404 .larch_pcala64_hi12,
93559405
9406 .sparc_olo10,
9356 .sparc_hix22,9407 .sparc_hix22,
9357 => true,9408 => true,
93589409
...@@ -9447,7 +9498,7 @@ fn addSymbolRelocAssumeCapacity(...@@ -9447,7 +9498,7 @@ fn addSymbolRelocAssumeCapacity(
9447 .type = dynamic_reloc_type,9498 .type = dynamic_reloc_type,
9448 .offset = node_vaddr + offset,9499 .offset = node_vaddr + offset,
9449 .raw_sym_index = target.unwrap().global.dynsymIndex(elf).?,9500 .raw_sym_index = target.unwrap().global.dynsymIndex(elf).?,
9450 .addend = addend,9501 .addend = addend.normal,
9451 }).toOptional();9502 }).toOptional();
9452 },9503 },
9453 }9504 }