authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-20 23:39:09+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-25 00:21:53+01:00
log7cc50a4fb3f8184742abe7a6939ae920c648ebab
treed0cb12e723ed15018bb7166ac974a7eb883fa765
parent720939f8c9cee80963a0089645e42ebbb4545906
signature Commit is signed but in an unrecognized format.

Elf2: absorb `GotReloc` into `SymbolReloc`


1 files changed, 468 insertions(+), 498 deletions(-)

src/link/Elf2.zig+468-498
...@@ -208,29 +208,24 @@ navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct {...@@ -208,29 +208,24 @@ navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct {
208 lsi: Symbol.LocalIndex,208 lsi: Symbol.LocalIndex,
209 /// The start index of the contiguous sequence of symbol relocations in this NAV.209 /// The start index of the contiguous sequence of symbol relocations in this NAV.
210 first_symbol_reloc: SymbolReloc.Index,210 first_symbol_reloc: SymbolReloc.Index,
211 /// The start index of the contiguous sequence of GOT relocations in this NAV.
212 first_got_reloc: GotReloc.Index,
213}),211}),
214uavs: std.array_hash_map.Auto(InternPool.Index, struct {212uavs: std.array_hash_map.Auto(InternPool.Index, struct {
215 lsi: Symbol.LocalIndex,213 lsi: Symbol.LocalIndex,
216 /// The start index of the contiguous sequence of symbol relocations in this UAV.214 /// The start index of the contiguous sequence of symbol relocations in this UAV.
217 first_symbol_reloc: SymbolReloc.Index,215 first_symbol_reloc: SymbolReloc.Index,
218 // No `first_got_reloc` field because a UAV never contains GOT relocations.
219}),216}),
220lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {217lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
221 map: std.array_hash_map.Auto(InternPool.Index, struct {218 map: std.array_hash_map.Auto(InternPool.Index, struct {
222 lsi: Symbol.LocalIndex,219 lsi: Symbol.LocalIndex,
223 /// The start index of the contiguous sequence of symbol relocations in this lazy code/data.220 /// The start index of the contiguous sequence of symbol relocations in this lazy code/data.
224 first_symbol_reloc: SymbolReloc.Index,221 first_symbol_reloc: SymbolReloc.Index,
225 /// The start index of the contiguous sequence of GOT relocations in this lazy code/data.
226 first_got_reloc: GotReloc.Index,
227 }),222 }),
228 pending_index: u32,223 pending_index: u32,
229}),224}),
230pending_uavs: std.ArrayList(Node.UavMapIndex),225pending_uavs: std.ArrayList(Node.UavMapIndex),
231symbol_relocs: std.ArrayList(SymbolReloc),226symbol_relocs: std.ArrayList(SymbolReloc),
232node_relocs: std.ArrayList(NodeReloc),227node_relocs: std.ArrayList(NodeReloc),
233got_relocs: std.ArrayList(GotReloc),228got_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
234/// Set of relocations which must be re-applied if the size of the TLS segment changes.229/// Set of relocations which must be re-applied if the size of the TLS segment changes.
235tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),230tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
236/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.231/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.
...@@ -388,9 +383,6 @@ const Node = union(enum) {...@@ -388,9 +383,6 @@ const Node = union(enum) {
388 fn firstSymbolReloc(nmi: NavMapIndex, elf: *const Elf) SymbolReloc.Index {383 fn firstSymbolReloc(nmi: NavMapIndex, elf: *const Elf) SymbolReloc.Index {
389 return elf.navs.values()[@backingInt(nmi)].first_symbol_reloc;384 return elf.navs.values()[@backingInt(nmi)].first_symbol_reloc;
390 }385 }
391 fn firstGotReloc(nmi: NavMapIndex, elf: *const Elf) GotReloc.Index {
392 return elf.navs.values()[@backingInt(nmi)].first_got_reloc;
393 }
394 };386 };
395387
396 pub const UavMapIndex = enum(u32) {388 pub const UavMapIndex = enum(u32) {
...@@ -407,11 +399,6 @@ const Node = union(enum) {...@@ -407,11 +399,6 @@ const Node = union(enum) {
407 fn firstSymbolReloc(umi: UavMapIndex, elf: *const Elf) SymbolReloc.Index {399 fn firstSymbolReloc(umi: UavMapIndex, elf: *const Elf) SymbolReloc.Index {
408 return elf.uavs.values()[@backingInt(umi)].first_symbol_reloc;400 return elf.uavs.values()[@backingInt(umi)].first_symbol_reloc;
409 }401 }
410 fn firstGotReloc(umi: UavMapIndex, elf: *const Elf) GotReloc.Index {
411 _ = umi;
412 _ = elf;
413 return .none;
414 }
415 };402 };
416403
417 pub const LazyMapRef = struct {404 pub const LazyMapRef = struct {
...@@ -437,9 +424,6 @@ const Node = union(enum) {...@@ -437,9 +424,6 @@ const Node = union(enum) {
437 fn firstSymbolReloc(lmi: @This(), elf: *const Elf) SymbolReloc.Index {424 fn firstSymbolReloc(lmi: @This(), elf: *const Elf) SymbolReloc.Index {
438 return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_symbol_reloc;425 return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_symbol_reloc;
439 }426 }
440 fn firstGotReloc(lmi: @This(), elf: *const Elf) GotReloc.Index {
441 return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_got_reloc;
442 }
443 };427 };
444 }428 }
445429
...@@ -603,8 +587,6 @@ const InputSection = struct {...@@ -603,8 +587,6 @@ const InputSection = struct {
603 node: MappedFile.Node.Index,587 node: MappedFile.Node.Index,
604 /// The start index of the contiguous sequence of symbol relocations in this input section.588 /// The start index of the contiguous sequence of symbol relocations in this input section.
605 first_symbol_reloc: SymbolReloc.Index,589 first_symbol_reloc: SymbolReloc.Index,
606 /// The start index of the contiguous sequence of GOT relocations in this input section.
607 first_got_reloc: GotReloc.Index,
608590
609 const Index = enum(u32) {591 const Index = enum(u32) {
610 _,592 _,
...@@ -1387,14 +1369,29 @@ const SymbolReloc = struct {...@@ -1387,14 +1369,29 @@ const SymbolReloc = struct {
1387 node: MappedFile.Node.Index.Optional,1369 node: MappedFile.Node.Index.Optional,
1388 /// The offset of the relocation inside of `node`.1370 /// The offset of the relocation inside of `node`.
1389 offset: u64,1371 offset: u64,
1390 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.1372 /// A symbol used to compute the relocated value. Precise meaning depends on `bits.@"type"`.
1391 target: Symbol.Id,1373 target_symbol: Symbol.Id,
1392 /// A signed constant used to compute the relocated value. Precise meaning depends on `@"type"`.1374 /// A signed constant used to compute the relocated value. Precise meaning depends on `bits.@"type"`.
1393 addend: SymbolReloc.Addend,1375 addend: SymbolReloc.Addend,
1394 /// Specifies how to apply the relocation.1376 bits: packed struct(u32) {
1395 ///1377 /// Specifies how to apply the relocation.
1396 /// When emitting a relocatable, this field is `undefined`.1378 ///
1397 type: SymbolReloc.Type,1379 /// When emitting a relocatable, this field is `undefined`.
1380 type: SymbolReloc.Type,
1381
1382 result: enum(u3) {
1383 ok,
1384 overflowed,
1385 misaligned,
1386 illegal_dynamic_type,
1387 illegal_dynamic_section,
1388 },
1389
1390 /// ~~mystery bits~~
1391 /// what will MLUGG use them for?
1392 /// nobody knows
1393 _: u11 = 0,
1394 },
1398 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so1395 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so
1399 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.1396 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.
1400 /// Doubly-linked so that relocations can be removed.1397 /// Doubly-linked so that relocations can be removed.
...@@ -1412,13 +1409,6 @@ const SymbolReloc = struct {...@@ -1412,13 +1409,6 @@ const SymbolReloc = struct {
1412 /// relocation entry. The entry will be removed if we discover a definition which allows us to1409 /// relocation entry. The entry will be removed if we discover a definition which allows us to
1413 /// statically resolve the relocation.1410 /// statically resolve the relocation.
1414 rela_index: Section.RelaIndex.Optional,1411 rela_index: Section.RelaIndex.Optional,
1415 result: enum(u8) {
1416 ok,
1417 overflowed,
1418 misaligned,
1419 illegal_dynamic_type,
1420 illegal_dynamic_section,
1421 },
14221412
1423 /// Determines the section in which this relocation will be placed if it is outstanding.1413 /// Determines the section in which this relocation will be placed if it is outstanding.
1424 ///1414 ///
...@@ -1464,7 +1454,7 @@ const SymbolReloc = struct {...@@ -1464,7 +1454,7 @@ const SymbolReloc = struct {
1464 /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on1454 /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on
1465 /// a symbol value. The representation is simply a big enum containing all of these exceptional1455 /// a symbol value. The representation is simply a big enum containing all of these exceptional
1466 /// cases---see `Special`. This representation is in use when `Type.target == .special`.1456 /// cases---see `Special`. This representation is in use when `Type.target == .special`.
1467 const Type = packed struct(u16) {1457 const Type = packed struct(u18) {
1468 /// Helper function for constructing a "simple" relocation type. This mainly exists to1458 /// Helper function for constructing a "simple" relocation type. This mainly exists to
1469 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.1459 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
1470 fn simple(target: Target, action: Simple) SymbolReloc.Type {1460 fn simple(target: Target, action: Simple) SymbolReloc.Type {
...@@ -1493,7 +1483,7 @@ const SymbolReloc = struct {...@@ -1493,7 +1483,7 @@ const SymbolReloc = struct {
1493 /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the1483 /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the
1494 /// relocation---whether we care about the target symbol's absolute address, its PC-relative1484 /// relocation---whether we care about the target symbol's absolute address, its PC-relative
1495 /// address, its PLT entry, etc.1485 /// address, its PLT entry, etc.
1496 const Target = enum(u3) {1486 const Target = enum(u5) {
1497 /// This is a "special" relocation whose specific type is in the `action.special` field.1487 /// This is a "special" relocation whose specific type is in the `action.special` field.
1498 special,1488 special,
14991489
...@@ -1501,6 +1491,7 @@ const SymbolReloc = struct {...@@ -1501,6 +1491,7 @@ const SymbolReloc = struct {
1501 abs,1491 abs,
1502 /// Offset from the relocation itself to the target symbol ("PC-relative").1492 /// Offset from the relocation itself to the target symbol ("PC-relative").
1503 rel,1493 rel,
1494
1504 /// Address of the target symbol's PLT entry.1495 /// Address of the target symbol's PLT entry.
1505 ///1496 ///
1506 /// If the target symbol does not have a PLT entry, equivalent to `.abs`.1497 /// If the target symbol does not have a PLT entry, equivalent to `.abs`.
...@@ -1509,12 +1500,35 @@ const SymbolReloc = struct {...@@ -1509,12 +1500,35 @@ const SymbolReloc = struct {
1509 ///1500 ///
1510 /// If the target symbol does not have a PLT entry, equivalent to `.rel`.1501 /// If the target symbol does not have a PLT entry, equivalent to `.rel`.
1511 pltrel,1502 pltrel,
1503
1512 /// Offset of the target TLS symbol from the base of this DSO's own TLS region.1504 /// Offset of the target TLS symbol from the base of this DSO's own TLS region.
1513 dtpoff,1505 dtpoff,
1514 /// Offset of the target TLS symbol from the raw thread pointer.1506 /// Offset of the target TLS symbol from the raw thread pointer.
1515 tpoff,1507 tpoff,
1508
1516 /// Size of the target symbol.1509 /// Size of the target symbol.
1517 size,1510 size,
1511
1512 /// Address of the GOT entry with key `.{ .symbol = target_symbol }`.
1513 gotabs_symbol,
1514 /// Offset from the relocation to the GOT entry with key `.{ .symbol = target_symbol }`.
1515 gotrel_symbol,
1516 /// Offset from the GOT base to the GOT entry with key `.{ .symbol = target_symbol }`.
1517 gotoff_symbol,
1518
1519 /// Address of the GOT entry with key `.{ .tpoff = target_symbol }`.
1520 gotabs_tpoff,
1521 /// Offset from the relocation to the GOT entry with key `.{ .tpoff = target_symbol }`.
1522 gotrel_tpoff,
1523 /// Offset from the GOT base to the GOT entry with key `.{ .tpoff = target_symbol }`.
1524 gotoff_tpoff,
1525
1526 /// Address of the GOT entry with key `.{ .tlsgd0 = target_symbol }`.
1527 gotabs_tlsgd,
1528 /// Offset from the relocation to the GOT entry with key `.{ .tlsgd0 = target_symbol }`.
1529 gotrel_tlsgd,
1530 /// Offset from the GOT base to the GOT entry with key `.{ .tlsgd0 = target_symbol }`.
1531 gotoff_tlsgd,
1518 };1532 };
15191533
1520 /// For a "simple" relocation, after the initial value is computed according to `Target`, a1534 /// For a "simple" relocation, after the initial value is computed according to `Target`, a
...@@ -1701,17 +1715,22 @@ const SymbolReloc = struct {...@@ -1701,17 +1715,22 @@ const SymbolReloc = struct {
1701 larch_b21,1715 larch_b21,
1702 larch_b26,1716 larch_b26,
1703 larch_call36,1717 larch_call36,
1718 larch_got_pcala_hi20,
1719 larch_got_pcala64_lo20,
1720 larch_got_pcala64_hi12,
17041721
1705 sparc_olo10,1722 sparc_olo10,
1706 sparc_hix22,1723 sparc_hix22,
1707 sparc_le_hix22,1724 sparc_le_hix22,
1708 sparc_wdisp10,1725 sparc_wdisp10,
1709 sparc_wdisp16,1726 sparc_wdisp16,
1727 sparc_got_op_lox10,
1728 sparc_got_op_hix22,
17101729
1711 fn applyInner(1730 fn applyInner(
1712 s: Special,1731 s: Special,
1713 elf: *Elf,1732 elf: *Elf,
1714 target: Symbol.Id,1733 target_sym: Symbol.Id,
1715 addend: SymbolReloc.Addend,1734 addend: SymbolReloc.Addend,
1716 dest_vaddr: u64,1735 dest_vaddr: u64,
1717 dest_slice: []u8,1736 dest_slice: []u8,
...@@ -1719,7 +1738,7 @@ const SymbolReloc = struct {...@@ -1719,7 +1738,7 @@ const SymbolReloc = struct {
1719 const normal_addend: u64 = @bitCast(addend.normal);1738 const normal_addend: u64 = @bitCast(addend.normal);
1720 switch (s) {1739 switch (s) {
1721 .larch_pcala_hi20 => {1740 .larch_pcala_hi20 => {
1722 const val = target.value(elf) +% normal_addend;1741 const val = target_sym.value(elf) +% normal_addend;
1723 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);1742 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1724 elf.targetStore(inst, .{1743 elf.targetStore(inst, .{
1725 .b0_4 = elf.targetLoad(inst).b0_4,1744 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1728,7 +1747,7 @@ const SymbolReloc = struct {...@@ -1728,7 +1747,7 @@ const SymbolReloc = struct {
1728 });1747 });
1729 },1748 },
1730 .larch_pcala64_lo20 => {1749 .larch_pcala64_lo20 => {
1731 const val = target.value(elf) +% normal_addend;1750 const val = target_sym.value(elf) +% normal_addend;
1732 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);1751 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1733 elf.targetStore(inst, .{1752 elf.targetStore(inst, .{
1734 .b0_4 = elf.targetLoad(inst).b0_4,1753 .b0_4 = elf.targetLoad(inst).b0_4,
...@@ -1737,7 +1756,7 @@ const SymbolReloc = struct {...@@ -1737,7 +1756,7 @@ const SymbolReloc = struct {
1737 });1756 });
1738 },1757 },
1739 .larch_pcala64_hi12 => {1758 .larch_pcala64_hi12 => {
1740 const val = target.value(elf) +% normal_addend;1759 const val = target_sym.value(elf) +% normal_addend;
1741 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);1760 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1742 elf.targetStore(inst, .{1761 elf.targetStore(inst, .{
1743 .b0_9 = elf.targetLoad(inst).b0_9,1762 .b0_9 = elf.targetLoad(inst).b0_9,
...@@ -1746,7 +1765,7 @@ const SymbolReloc = struct {...@@ -1746,7 +1765,7 @@ const SymbolReloc = struct {
1746 });1765 });
1747 },1766 },
1748 .larch_b21, .larch_b26, .larch_call36 => {1767 .larch_b21, .larch_b26, .larch_call36 => {
1749 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);1768 const target_vaddr: u64 = elf.pltEntryTargetAddr(target_sym) orelse target_sym.value(elf);
1750 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);1769 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
1751 if ((jump_offset >> 2) << 2 != jump_offset) {1770 if ((jump_offset >> 2) << 2 != jump_offset) {
1752 return error.RelocationMisaligned;1771 return error.RelocationMisaligned;
...@@ -1806,9 +1825,43 @@ const SymbolReloc = struct {...@@ -1806,9 +1825,43 @@ const SymbolReloc = struct {
1806 }1825 }
1807 },1826 },
18081827
1828 .larch_got_pcala_hi20 => {
1829 const got_vaddr = elf.shndx.got.vaddr(elf);
1830 const got_offset = elf.got.getIndex(.{ .symbol = target_sym }).? * elf.targetPtrSize();
1831 const val = got_vaddr +% got_offset +% normal_addend;
1832 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1833 elf.targetStore(inst, .{
1834 .b0_4 = elf.targetLoad(inst).b0_4,
1835 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
1836 .b25_31 = elf.targetLoad(inst).b25_31,
1837 });
1838 },
1839 .larch_got_pcala64_lo20 => {
1840 const got_vaddr = elf.shndx.got.vaddr(elf);
1841 const got_offset = elf.got.getIndex(.{ .symbol = target_sym }).? * elf.targetPtrSize();
1842 const val = got_vaddr +% got_offset +% normal_addend;
1843 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
1844 elf.targetStore(inst, .{
1845 .b0_4 = elf.targetLoad(inst).b0_4,
1846 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
1847 .b25_31 = elf.targetLoad(inst).b25_31,
1848 });
1849 },
1850 .larch_got_pcala64_hi12 => {
1851 const got_vaddr = elf.shndx.got.vaddr(elf);
1852 const got_offset = elf.got.getIndex(.{ .symbol = target_sym }).? * elf.targetPtrSize();
1853 const val = got_vaddr +% got_offset +% normal_addend;
1854 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
1855 elf.targetStore(inst, .{
1856 .b0_9 = elf.targetLoad(inst).b0_9,
1857 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
1858 .b22_31 = elf.targetLoad(inst).b22_31,
1859 });
1860 },
1861
1809 .sparc_olo10 => {1862 .sparc_olo10 => {
1810 const addends = addend.sparc_olo10;1863 const addends = addend.sparc_olo10;
1811 const lo10: i64 = @as(u10, @truncate(target.value(elf) +% addends.a));1864 const lo10: i64 = @as(u10, @truncate(target_sym.value(elf) +% addends.a));
1812 const simm13 = std.math.cast(i13, lo10 + addends.o) orelse return error.RelocationOverflow;1865 const simm13 = std.math.cast(i13, lo10 + addends.o) orelse return error.RelocationOverflow;
1813 const dest_ptr: *align(1) packed struct(u32) {1866 const dest_ptr: *align(1) packed struct(u32) {
1814 simm13: u13,1867 simm13: u13,
...@@ -1825,7 +1878,7 @@ const SymbolReloc = struct {...@@ -1825,7 +1878,7 @@ const SymbolReloc = struct {
1825 b22_31: u10,1878 b22_31: u10,
1826 } = @ptrCast(dest_slice);1879 } = @ptrCast(dest_slice);
1827 elf.targetStore(dest_ptr, .{1880 elf.targetStore(dest_ptr, .{
1828 .imm22 = @truncate(~(target.value(elf) +% normal_addend) >> 10),1881 .imm22 = @truncate(~(target_sym.value(elf) +% normal_addend) >> 10),
1829 .b22_31 = elf.targetLoad(dest_ptr).b22_31,1882 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1830 });1883 });
1831 },1884 },
...@@ -1842,12 +1895,12 @@ const SymbolReloc = struct {...@@ -1842,12 +1895,12 @@ const SymbolReloc = struct {
1842 b22_31: u10,1895 b22_31: u10,
1843 } = @ptrCast(dest_slice);1896 } = @ptrCast(dest_slice);
1844 elf.targetStore(dest_ptr, .{1897 elf.targetStore(dest_ptr, .{
1845 .imm22 = @truncate(~(target.value(elf) +% normal_addend -% tls_size) >> 10),1898 .imm22 = @truncate(~(target_sym.value(elf) +% normal_addend -% tls_size) >> 10),
1846 .b22_31 = elf.targetLoad(dest_ptr).b22_31,1899 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1847 });1900 });
1848 },1901 },
1849 .sparc_wdisp16, .sparc_wdisp10 => {1902 .sparc_wdisp16, .sparc_wdisp10 => {
1850 const target_vaddr: u64 = elf.pltEntryTargetAddr(target) orelse target.value(elf);1903 const target_vaddr: u64 = elf.pltEntryTargetAddr(target_sym) orelse target_sym.value(elf);
1851 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);1904 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
1852 if ((jump_offset >> 2) << 2 != jump_offset) {1905 if ((jump_offset >> 2) << 2 != jump_offset) {
1853 return error.RelocationMisaligned;1906 return error.RelocationMisaligned;
...@@ -1897,10 +1950,120 @@ const SymbolReloc = struct {...@@ -1897,10 +1950,120 @@ const SymbolReloc = struct {
1897 else => unreachable,1950 else => unreachable,
1898 }1951 }
1899 },1952 },
1953
1954 .sparc_got_op_lox10 => {
1955 const got_offset = elf.got.getIndex(.{ .symbol = target_sym }).? * elf.targetPtrSize();
1956 const dest_ptr: *align(1) packed struct(u32) {
1957 imm13: u13,
1958 b13_31: u19,
1959 } = @ptrCast(dest_slice);
1960 elf.targetStore(dest_ptr, .{
1961 .imm13 = @as(u10, @truncate(got_offset)),
1962 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
1963 });
1964 },
1965 .sparc_got_op_hix22 => {
1966 const got_offset = elf.got.getIndex(.{ .symbol = target_sym }).? * elf.targetPtrSize();
1967 const dest_ptr: *align(1) packed struct(u32) {
1968 imm22: u22,
1969 b22_31: u10,
1970 } = @ptrCast(dest_slice);
1971 elf.targetStore(dest_ptr, .{
1972 .imm22 = @truncate(got_offset >> 10),
1973 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
1974 });
1975 },
1900 }1976 }
1901 }1977 }
1902 };1978 };
19031979
1980 fn needsGotEntry(t: SymbolReloc.Type) ?enum { symbol, tpoff, tlsgd } {
1981 return switch (t.target) {
1982 .abs,
1983 .rel,
1984 .pltabs,
1985 .pltrel,
1986 .dtpoff,
1987 .tpoff,
1988 .size,
1989 => null,
1990
1991 .gotabs_symbol, .gotrel_symbol, .gotoff_symbol => .symbol,
1992 .gotabs_tpoff, .gotrel_tpoff, .gotoff_tpoff => .tpoff,
1993 .gotabs_tlsgd, .gotrel_tlsgd, .gotoff_tlsgd => .tlsgd,
1994
1995 .special => switch (t.action.special) {
1996 .larch_pcala_hi20,
1997 .larch_pcala64_lo20,
1998 .larch_pcala64_hi12,
1999 .larch_b21,
2000 .larch_b26,
2001 .larch_call36,
2002 .sparc_olo10,
2003 .sparc_hix22,
2004 .sparc_le_hix22,
2005 .sparc_wdisp10,
2006 .sparc_wdisp16,
2007 => null,
2008
2009 .larch_got_pcala_hi20,
2010 .larch_got_pcala64_lo20,
2011 .larch_got_pcala64_hi12,
2012 .sparc_got_op_lox10,
2013 .sparc_got_op_hix22,
2014 => .symbol,
2015 },
2016 };
2017 }
2018
2019 fn dependsOnGotAddress(t: SymbolReloc.Type) bool {
2020 return switch (t.target) {
2021 .abs,
2022 .rel,
2023 .pltabs,
2024 .pltrel,
2025 .dtpoff,
2026 .tpoff,
2027 .size,
2028 => false,
2029
2030 .gotabs_symbol,
2031 .gotrel_symbol,
2032 .gotabs_tpoff,
2033 .gotrel_tpoff,
2034 .gotabs_tlsgd,
2035 .gotrel_tlsgd,
2036 => true,
2037
2038 .gotoff_symbol,
2039 .gotoff_tpoff,
2040 .gotoff_tlsgd,
2041 => false,
2042
2043 .special => switch (t.action.special) {
2044 .larch_pcala_hi20,
2045 .larch_pcala64_lo20,
2046 .larch_pcala64_hi12,
2047 .larch_b21,
2048 .larch_b26,
2049 .larch_call36,
2050 .sparc_olo10,
2051 .sparc_hix22,
2052 .sparc_le_hix22,
2053 .sparc_wdisp10,
2054 .sparc_wdisp16,
2055 => false,
2056
2057 .larch_got_pcala_hi20,
2058 .larch_got_pcala64_lo20,
2059 .larch_got_pcala64_hi12,
2060 .sparc_got_op_lox10,
2061 .sparc_got_op_hix22,
2062 => true,
2063 },
2064 };
2065 }
2066
1904 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {2067 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {
1905 return switch (elf.targetTlsVariant()) {2068 return switch (elf.targetTlsVariant()) {
1906 // In TLS variant I, the executable's TLS block starts at a fixed offset from the2069 // In TLS variant I, the executable's TLS block starts at a fixed offset from the
...@@ -1917,6 +2080,15 @@ const SymbolReloc = struct {...@@ -1917,6 +2080,15 @@ const SymbolReloc = struct {
1917 .pltrel,2080 .pltrel,
1918 .dtpoff,2081 .dtpoff,
1919 .size,2082 .size,
2083 .gotabs_symbol,
2084 .gotrel_symbol,
2085 .gotoff_symbol,
2086 .gotabs_tpoff,
2087 .gotrel_tpoff,
2088 .gotoff_tpoff,
2089 .gotabs_tlsgd,
2090 .gotrel_tlsgd,
2091 .gotoff_tlsgd,
1920 => false,2092 => false,
19212093
1922 .tpoff => true,2094 .tpoff => true,
...@@ -1931,11 +2103,16 @@ const SymbolReloc = struct {...@@ -1931,11 +2103,16 @@ const SymbolReloc = struct {
1931 .larch_b21,2103 .larch_b21,
1932 .larch_b26,2104 .larch_b26,
1933 .larch_call36,2105 .larch_call36,
2106 .larch_got_pcala_hi20,
2107 .larch_got_pcala64_lo20,
2108 .larch_got_pcala64_hi12,
19342109
1935 .sparc_olo10,2110 .sparc_olo10,
1936 .sparc_hix22,2111 .sparc_hix22,
1937 .sparc_wdisp10,2112 .sparc_wdisp10,
1938 .sparc_wdisp16,2113 .sparc_wdisp16,
2114 .sparc_got_op_lox10,
2115 .sparc_got_op_hix22,
1939 => false,2116 => false,
1940 },2117 },
1941 },2118 },
...@@ -1954,7 +2131,7 @@ const SymbolReloc = struct {...@@ -1954,7 +2131,7 @@ const SymbolReloc = struct {
19542131
1955 fn apply(reloc: *SymbolReloc, elf: *Elf) void {2132 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
1956 const node = reloc.node.unwrap() orelse return; // deleted2133 const node = reloc.node.unwrap() orelse return; // deleted
1957 if (node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) {2134 if (node.hasMoved(&elf.mf) or reloc.target_symbol.hasMoved(elf)) {
1958 // There's no point applying the relocation now, because it will be re-applied by2135 // There's no point applying the relocation now, because it will be re-applied by
1959 // `flushMoved` at some point anyway.2136 // `flushMoved` at some point anyway.
1960 return;2137 return;
...@@ -1966,7 +2143,7 @@ const SymbolReloc = struct {...@@ -1966,7 +2143,7 @@ const SymbolReloc = struct {
1966 reloc.relaSection(elf).relaSetOffset(elf, rela_index, reloc_addr);2143 reloc.relaSection(elf).relaSetOffset(elf, rela_index, reloc_addr);
1967 return;2144 return;
1968 }2145 }
1969 switch (reloc.result) {2146 switch (reloc.bits.result) {
1970 .ok => {},2147 .ok => {},
1971 .overflowed => elf.overflowed_reloc_count -= 1,2148 .overflowed => elf.overflowed_reloc_count -= 1,
1972 .misaligned => elf.misaligned_reloc_count -= 1,2149 .misaligned => elf.misaligned_reloc_count -= 1,
...@@ -1977,14 +2154,14 @@ const SymbolReloc = struct {...@@ -1977,14 +2154,14 @@ const SymbolReloc = struct {
1977 }2154 }
1978 if (reloc.applyInner(elf)) {2155 if (reloc.applyInner(elf)) {
1979 @branchHint(.likely);2156 @branchHint(.likely);
1980 reloc.result = .ok;2157 reloc.bits.result = .ok;
1981 } else |err| switch (err) {2158 } else |err| switch (err) {
1982 error.RelocationOverflow => {2159 error.RelocationOverflow => {
1983 reloc.result = .overflowed;2160 reloc.bits.result = .overflowed;
1984 elf.overflowed_reloc_count += 1;2161 elf.overflowed_reloc_count += 1;
1985 },2162 },
1986 error.RelocationMisaligned => {2163 error.RelocationMisaligned => {
1987 reloc.result = .misaligned;2164 reloc.bits.result = .misaligned;
1988 elf.misaligned_reloc_count += 1;2165 elf.misaligned_reloc_count += 1;
1989 },2166 },
1990 }2167 }
...@@ -1995,21 +2172,21 @@ const SymbolReloc = struct {...@@ -1995,21 +2172,21 @@ const SymbolReloc = struct {
1995 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];2172 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
19962173
1997 const addend: u64 = @bitCast(reloc.addend);2174 const addend: u64 = @bitCast(reloc.addend);
1998 const target_val: u64 = type: switch (reloc.type.target) {2175 const target_val: u64 = type: switch (reloc.bits.type.target) {
1999 .abs => reloc.target.value(elf) +% addend,2176 .abs => reloc.target_symbol.value(elf) +% addend,
2000 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,2177 .rel => reloc.target_symbol.value(elf) +% addend -% dest_vaddr,
2001 .pltabs => {2178 .pltabs => {
2002 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs;2179 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target_symbol) orelse continue :type .abs;
2003 break :type plt_entry_addr +% addend;2180 break :type plt_entry_addr +% addend;
2004 },2181 },
2005 .pltrel => {2182 .pltrel => {
2006 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel;2183 const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target_symbol) orelse continue :type .rel;
2007 break :type plt_entry_addr +% addend -% dest_vaddr;2184 break :type plt_entry_addr +% addend -% dest_vaddr;
2008 },2185 },
2009 .dtpoff => reloc.target.value(elf) +% addend,2186 .dtpoff => reloc.target_symbol.value(elf) +% addend,
2010 .tpoff => switch (elf.targetTlsVariant()) {2187 .tpoff => switch (elf.targetTlsVariant()) {
2011 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,2188 .I_original => |tls| tls.tcb_size +% reloc.target_symbol.value(elf) +% addend,
2012 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,2189 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target_symbol.value(elf) +% addend,
2013 .II => {2190 .II => {
2014 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;2191 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
2015 const tls_size: u64 = switch (elf.phdrSlice()) {2192 const tls_size: u64 = switch (elf.phdrSlice()) {
...@@ -2018,13 +2195,57 @@ const SymbolReloc = struct {...@@ -2018,13 +2195,57 @@ const SymbolReloc = struct {
2018 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);2195 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
2019 },2196 },
2020 };2197 };
2021 break :type reloc.target.value(elf) +% addend -% tls_size;2198 break :type reloc.target_symbol.value(elf) +% addend -% tls_size;
2022 },2199 },
2023 },2200 },
2024 .size => reloc.target.size(elf),2201 .size => reloc.target_symbol.size(elf),
2025 .special => return reloc.type.action.special.applyInner(2202
2203 .gotabs_symbol => {
2204 const got_vaddr = elf.shndx.got.vaddr(elf);
2205 const got_offset = elf.got.getIndex(.{ .symbol = reloc.target_symbol }).? * elf.targetPtrSize();
2206 break :type (got_vaddr + got_offset) +% addend;
2207 },
2208 .gotrel_symbol => {
2209 const got_vaddr = elf.shndx.got.vaddr(elf);
2210 const got_offset = elf.got.getIndex(.{ .symbol = reloc.target_symbol }).? * elf.targetPtrSize();
2211 break :type (got_vaddr + got_offset) +% addend -% dest_vaddr;
2212 },
2213 .gotoff_symbol => {
2214 const got_offset = elf.got.getIndex(.{ .symbol = reloc.target_symbol }).? * elf.targetPtrSize();
2215 break :type got_offset +% addend;
2216 },
2217 .gotabs_tpoff => {
2218 const got_vaddr = elf.shndx.got.vaddr(elf);
2219 const got_offset = elf.got.getIndex(.{ .tpoff = reloc.target_symbol }).? * elf.targetPtrSize();
2220 break :type (got_vaddr + got_offset) +% addend;
2221 },
2222 .gotrel_tpoff => {
2223 const got_vaddr = elf.shndx.got.vaddr(elf);
2224 const got_offset = elf.got.getIndex(.{ .tpoff = reloc.target_symbol }).? * elf.targetPtrSize();
2225 break :type (got_vaddr + got_offset) +% addend -% dest_vaddr;
2226 },
2227 .gotoff_tpoff => {
2228 const got_offset = elf.got.getIndex(.{ .tpoff = reloc.target_symbol }).? * elf.targetPtrSize();
2229 break :type got_offset +% addend;
2230 },
2231 .gotabs_tlsgd => {
2232 const got_vaddr = elf.shndx.got.vaddr(elf);
2233 const got_offset = elf.got.getIndex(.{ .tlsgd0 = reloc.target_symbol }).? * elf.targetPtrSize();
2234 break :type (got_vaddr + got_offset) +% addend;
2235 },
2236 .gotrel_tlsgd => {
2237 const got_vaddr = elf.shndx.got.vaddr(elf);
2238 const got_offset = elf.got.getIndex(.{ .tlsgd0 = reloc.target_symbol }).? * elf.targetPtrSize();
2239 break :type (got_vaddr + got_offset) +% addend -% dest_vaddr;
2240 },
2241 .gotoff_tlsgd => {
2242 const got_offset = elf.got.getIndex(.{ .tlsgd0 = reloc.target_symbol }).? * elf.targetPtrSize();
2243 break :type got_offset +% addend;
2244 },
2245
2246 .special => return reloc.bits.type.action.special.applyInner(
2026 elf,2247 elf,
2027 reloc.target,2248 reloc.target_symbol,
2028 reloc.addend,2249 reloc.addend,
2029 dest_vaddr,2250 dest_vaddr,
2030 dest_slice,2251 dest_slice,
...@@ -2033,7 +2254,7 @@ const SymbolReloc = struct {...@@ -2033,7 +2254,7 @@ const SymbolReloc = struct {
20332254
2034 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast2255 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
2035 // is required, meaning we can handle it now and return early.2256 // is required, meaning we can handle it now and return early.
2036 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) {2257 if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target_symbol)) {
2037 .static => unreachable,2258 .static => unreachable,
2038 .dynamic => {2259 .dynamic => {
2039 // The relocation happens at runtime; we just need to update its offset.2260 // The relocation happens at runtime; we just need to update its offset.
...@@ -2046,31 +2267,34 @@ const SymbolReloc = struct {...@@ -2046,31 +2267,34 @@ const SymbolReloc = struct {
2046 // destination slice, we actually want to write it to the runtime relocation entry.2267 // destination slice, we actually want to write it to the runtime relocation entry.
2047 switch (elf.identClass()) {2268 switch (elf.identClass()) {
2048 .NONE, _ => unreachable,2269 .NONE, _ => unreachable,
2049 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),2270 .@"32" => assert(reloc.bits.type.action.simple.dest == .@"32"),
2050 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),2271 .@"64" => assert(reloc.bits.type.action.simple.dest == .@"64"),
2051 }2272 }
2052 assert(reloc.type.action.simple.cast == .unsigned);2273 assert(reloc.bits.type.action.simple.cast == .unsigned);
2053 assert(reloc.type.action.simple.shift == .@"0");2274 assert(reloc.bits.type.action.simple.shift == .@"0");
2054 elf.shndx.rela_dyn.relaSetOffset(elf, rela_index, dest_vaddr);2275 elf.shndx.rela_dyn.relaSetOffset(elf, rela_index, dest_vaddr);
2055 elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val);2276 elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val);
2056 return;2277 return;
2057 },2278 },
2058 };2279 };
20592280
2060 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());2281 try reloc.bits.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
2061 }2282 }
20622283
2063 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {2284 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
2064 assert(index.get(elf) == reloc);2285 assert(index.get(elf) == reloc);
20652286
2066 reloc.deleteOutputRel(elf);2287 reloc.deleteOutputRel(elf);
2067 if (reloc.type.dependsOnTlsSize(elf)) {2288 if (reloc.bits.type.dependsOnTlsSize(elf)) {
2068 assert(elf.tls_size_symbol_relocs.swapRemove(index));2289 assert(elf.tls_size_symbol_relocs.swapRemove(index));
2069 }2290 }
2291 if (reloc.bits.type.dependsOnGotAddress()) {
2292 assert(elf.got_relocs.swapRemove(index));
2293 }
20702294
2071 switch (reloc.prev) {2295 switch (reloc.prev) {
2072 .none => {2296 .none => {
2073 const first_target_reloc = &reloc.target.index(elf).ptr(elf).first_target_reloc;2297 const first_target_reloc = &reloc.target_symbol.index(elf).ptr(elf).first_target_reloc;
2074 assert(first_target_reloc.* == index);2298 assert(first_target_reloc.* == index);
2075 first_target_reloc.* = reloc.next;2299 first_target_reloc.* = reloc.next;
2076 },2300 },
...@@ -2080,7 +2304,7 @@ const SymbolReloc = struct {...@@ -2080,7 +2304,7 @@ const SymbolReloc = struct {
2080 .none => {},2304 .none => {},
2081 else => |next| next.get(elf).prev = reloc.prev,2305 else => |next| next.get(elf).prev = reloc.prev,
2082 }2306 }
2083 switch (reloc.result) {2307 switch (reloc.bits.result) {
2084 .ok => {},2308 .ok => {},
2085 .overflowed => elf.overflowed_reloc_count -= 1,2309 .overflowed => elf.overflowed_reloc_count -= 1,
2086 .misaligned => elf.misaligned_reloc_count -= 1,2310 .misaligned => elf.misaligned_reloc_count -= 1,
...@@ -2113,25 +2337,25 @@ const SymbolReloc = struct {...@@ -2113,25 +2337,25 @@ const SymbolReloc = struct {
2113 const reloc_node = reloc.node.unwrap().?; // deleted2337 const reloc_node = reloc.node.unwrap().?; // deleted
21142338
2115 // Delete any current output relocation or error.2339 // Delete any current output relocation or error.
2116 switch (reloc.result) {2340 switch (reloc.bits.result) {
2117 .ok, .overflowed, .misaligned => {2341 .ok, .overflowed, .misaligned => {
2118 reloc.deleteOutputRel(elf);2342 reloc.deleteOutputRel(elf);
2119 },2343 },
2120 .illegal_dynamic_type => {2344 .illegal_dynamic_type => {
2121 elf.illegal_dynamic_type_reloc_count -= 1;2345 elf.illegal_dynamic_type_reloc_count -= 1;
2122 reloc.result = .ok;2346 reloc.bits.result = .ok;
2123 },2347 },
2124 .illegal_dynamic_section => {2348 .illegal_dynamic_section => {
2125 elf.illegal_dynamic_section_reloc_count -= 1;2349 elf.illegal_dynamic_section_reloc_count -= 1;
2126 reloc.result = .ok;2350 reloc.bits.result = .ok;
2127 },2351 },
2128 }2352 }
21292353
2130 assert(reloc.rela_index == .none);2354 assert(reloc.rela_index == .none);
21312355
2132 const symbol_class = elf.classifySymbolValue(reloc.target);2356 const symbol_class = elf.classifySymbolValue(reloc.target_symbol);
21332357
2134 switch (reloc.target.unwrap()) {2358 switch (reloc.target_symbol.unwrap()) {
2135 .local => {},2359 .local => {},
2136 .global => |gsi| switch (symbol_class) {2360 .global => |gsi| switch (symbol_class) {
2137 .static => gsi.ptr(elf).status.any_static_target_relocs = true,2361 .static => gsi.ptr(elf).status.any_static_target_relocs = true,
...@@ -2152,25 +2376,36 @@ const SymbolReloc = struct {...@@ -2152,25 +2376,36 @@ const SymbolReloc = struct {
2152 } = switch (symbol_class) {2376 } = switch (symbol_class) {
2153 .static => return,2377 .static => return,
21542378
2155 .static_relative => switch (reloc.type.target) {2379 .static_relative => switch (reloc.bits.type.target) {
2156 // We need a runtime relocation if the relocation depends on our load address, which2380 // We need a runtime relocation if the relocation depends on our load address, which
2157 // is the case iff the relocation resolves to the absolute value of a symbol. Relocs2381 // is the case iff the relocation resolves to the absolute value of a symbol. Relocs
2158 // which are PC-relative, or which resolve to something other than a symbol address2382 // which are PC-relative, or which resolve to something other than a symbol address
2159 // (e.g. a symbol's size), are fine.2383 // (e.g. a symbol's size), are fine.
21602384
2161 .pltrel,2385 .pltrel,
2386 .gotrel_symbol,
2387 .gotoff_symbol,
2388 .gotrel_tpoff,
2389 .gotoff_tpoff,
2390 .gotrel_tlsgd,
2391 .gotoff_tlsgd,
2162 .rel,2392 .rel,
2163 .size,2393 .size,
2164 .dtpoff,2394 .dtpoff,
2165 .tpoff,2395 .tpoff,
2166 => return,2396 => return,
21672397
2168 .abs, .pltabs => switch (reloc.type.action.simple.dest.isAddr(elf)) {2398 .abs,
2399 .pltabs,
2400 .gotabs_symbol,
2401 .gotabs_tpoff,
2402 .gotabs_tlsgd,
2403 => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
2169 true => .relative,2404 true => .relative,
2170 false => .illegal,2405 false => .illegal,
2171 },2406 },
21722407
2173 .special => switch (reloc.type.action.special) {2408 .special => switch (reloc.bits.type.action.special) {
2174 .larch_pcala_hi20,2409 .larch_pcala_hi20,
2175 .larch_pcala64_lo20,2410 .larch_pcala64_lo20,
2176 .larch_pcala64_hi12,2411 .larch_pcala64_hi12,
...@@ -2180,6 +2415,11 @@ const SymbolReloc = struct {...@@ -2180,6 +2415,11 @@ const SymbolReloc = struct {
2180 .sparc_wdisp10,2415 .sparc_wdisp10,
2181 .sparc_wdisp16,2416 .sparc_wdisp16,
2182 .sparc_le_hix22,2417 .sparc_le_hix22,
2418 .larch_got_pcala_hi20,
2419 .larch_got_pcala64_lo20,
2420 .larch_got_pcala64_hi12,
2421 .sparc_got_op_lox10,
2422 .sparc_got_op_hix22,
2183 => return,2423 => return,
21842424
2185 .sparc_olo10,2425 .sparc_olo10,
...@@ -2188,44 +2428,60 @@ const SymbolReloc = struct {...@@ -2188,44 +2428,60 @@ const SymbolReloc = struct {
2188 },2428 },
2189 },2429 },
21902430
2191 .dynamic => switch (reloc.type.target) {2431 .dynamic => switch (reloc.bits.type.target) {
2192 // PLT relocations targeting dynamic symbols actually target that symbol's PLT2432 // PLT/GOT relocations targeting dynamic symbols actually target that symbol's PLT
2193 // entry, so we should emit an `R_*_RELATIVE` relocation instead.2433 // or GOT entry, so we should emit an `R_*_RELATIVE` relocation instead.
2194 .pltabs => switch (reloc.type.action.simple.dest.isAddr(elf)) {2434 .pltabs,
2435 .gotabs_symbol,
2436 .gotabs_tpoff,
2437 .gotabs_tlsgd,
2438 => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
2195 true => .relative,2439 true => .relative,
2196 false => .illegal,2440 false => .illegal,
2197 },2441 },
2198 // ...although PC-relative PLT relocations don't even need that that!2442 // ...although PC-relative PLT/GOT relocations don't even need that that!
2199 .pltrel => return,2443 .pltrel,
2444 .gotrel_symbol,
2445 .gotoff_symbol,
2446 .gotrel_tpoff,
2447 .gotoff_tpoff,
2448 .gotrel_tlsgd,
2449 .gotoff_tlsgd,
2450 => return,
2200 // PC-relative relocations are not valid dynamic relocations.2451 // PC-relative relocations are not valid dynamic relocations.
2201 .rel => .illegal,2452 .rel => .illegal,
2202 // On the few targets supporting size relocations, they are valid at runtime.2453 // On the few targets supporting size relocations, they are valid at runtime.
2203 .size => switch (reloc.type.action.simple.dest) {2454 .size => switch (reloc.bits.type.action.simple.dest) {
2204 .@"32" => .size32,2455 .@"32" => .size32,
2205 .@"64" => .size64,2456 .@"64" => .size64,
2206 else => .illegal,2457 else => .illegal,
2207 },2458 },
2208 // Absolute addresses and TLS offsets can be lowered at runtime provided they2459 // Absolute addresses and TLS offsets can be lowered at runtime provided they
2209 // are address-sized.2460 // are address-sized.
2210 .dtpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) {2461 .dtpoff => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
2211 true => .dtp_off,2462 true => .dtp_off,
2212 false => .illegal,2463 false => .illegal,
2213 },2464 },
2214 .tpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) {2465 .tpoff => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
2215 true => .tp_off,2466 true => .tp_off,
2216 false => .illegal,2467 false => .illegal,
2217 },2468 },
2218 .abs => switch (reloc.type.action.simple.dest.isAddr(elf)) {2469 .abs => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
2219 true => .abs_addr,2470 true => .abs_addr,
2220 false => .illegal,2471 false => .illegal,
2221 },2472 },
22222473
2223 .special => switch (reloc.type.action.special) {2474 .special => switch (reloc.bits.type.action.special) {
2224 .larch_b21,2475 .larch_b21,
2225 .larch_b26,2476 .larch_b26,
2226 .larch_call36,2477 .larch_call36,
2227 .sparc_wdisp10,2478 .sparc_wdisp10,
2228 .sparc_wdisp16,2479 .sparc_wdisp16,
2480 .larch_got_pcala_hi20,
2481 .larch_got_pcala64_lo20,
2482 .larch_got_pcala64_hi12,
2483 .sparc_got_op_lox10,
2484 .sparc_got_op_hix22,
2229 => return,2485 => return,
22302486
2231 .larch_pcala_hi20,2487 .larch_pcala_hi20,
...@@ -2255,7 +2511,7 @@ const SymbolReloc = struct {...@@ -2255,7 +2511,7 @@ const SymbolReloc = struct {
2255 .abs_addr,2511 .abs_addr,
2256 .dtp_off,2512 .dtp_off,
2257 .tp_off,2513 .tp_off,
2258 => switch (reloc.target.unwrap()) {2514 => switch (reloc.target_symbol.unwrap()) {
2259 .local => true,2515 .local => true,
2260 .global => |gsi| gsi.resolveAlias(elf).defined(elf),2516 .global => |gsi| gsi.resolveAlias(elf).defined(elf),
2261 },2517 },
...@@ -2267,7 +2523,7 @@ const SymbolReloc = struct {...@@ -2267,7 +2523,7 @@ const SymbolReloc = struct {
2267 };2523 };
2268 if (!allow) {2524 if (!allow) {
2269 // ...but in this case we actually do need to trigger an error.2525 // ...but in this case we actually do need to trigger an error.
2270 reloc.result = .illegal_dynamic_section;2526 reloc.bits.result = .illegal_dynamic_section;
2271 elf.illegal_dynamic_section_reloc_count += 1;2527 elf.illegal_dynamic_section_reloc_count += 1;
2272 }2528 }
2273 return;2529 return;
...@@ -2278,7 +2534,7 @@ const SymbolReloc = struct {...@@ -2278,7 +2534,7 @@ const SymbolReloc = struct {
22782534
2279 const rel_type: MachineRelocType = rel: switch (want_dynamic_reloc) {2535 const rel_type: MachineRelocType = rel: switch (want_dynamic_reloc) {
2280 .illegal => {2536 .illegal => {
2281 reloc.result = .illegal_dynamic_type;2537 reloc.bits.result = .illegal_dynamic_type;
2282 elf.illegal_dynamic_type_reloc_count += 1;2538 elf.illegal_dynamic_type_reloc_count += 1;
2283 return;2539 return;
2284 },2540 },
...@@ -2292,7 +2548,7 @@ const SymbolReloc = struct {...@@ -2292,7 +2548,7 @@ const SymbolReloc = struct {
2292 const target_dynsym: u32 = switch (want_dynamic_reloc) {2548 const target_dynsym: u32 = switch (want_dynamic_reloc) {
2293 .illegal => unreachable, // handled above2549 .illegal => unreachable, // handled above
2294 .relative => 0,2550 .relative => 0,
2295 else => reloc.target.unwrap().global.dynsymIndex(elf).?,2551 else => reloc.target_symbol.unwrap().global.dynsymIndex(elf).?,
2296 };2552 };
22972553
2298 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, 1);2554 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, 1);
...@@ -2435,227 +2691,20 @@ const GotKey = union(enum) {...@@ -2435,227 +2691,20 @@ const GotKey = union(enum) {
2435 /// Value is the signed offset of the given symbol from the TLS pointer.2691 /// Value is the signed offset of the given symbol from the TLS pointer.
2436 tpoff: Symbol.Id,2692 tpoff: Symbol.Id,
24372693
2438 /// Value is the TLS module ID of the DSO we are creating.2694 /// Value is the TLS module ID for the given STT_TLS symbol. Alternatively, it may be set to
2439 ///2695 /// `Symbol.Id.null` to resolve to the TLS module ID of this module (for TLSLD relocations).
2440 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
2441 tlsld0,
2442 /// Value is always 0.
2443 ///2696 ///
2444 /// Used for the second of the two GOT entries generated by a TLSLD relocation.2697 /// Alternative
2445 tlsld1,
2446
2447 /// Value is the TLS module ID for the given STT_TLS symbol.
2448 ///2698 ///
2449 /// Used for the first of the two GOT entries generated by a TLSGD relocation.2699 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
2450 tlsgd0: Symbol.Id,2700 tlsgd0: Symbol.Id,
2451 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.2701 /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area.
2702 /// Alternatively, it may be set to `Symbol.Id.null` to resolve to 0 (for TLSLD relocations).
2452 ///2703 ///
2453 /// Used for the second of the two GOT entries generated by a TLSGD relocation.2704 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
2454 tlsgd1: Symbol.Id,2705 tlsgd1: Symbol.Id,
2455};2706};
24562707
2457/// A relocation targeting a particular GOT entry.
2458const GotReloc = struct {
2459 /// The node containing this relocation. Possible values are:
2460 /// * An input section
2461 /// * A section
2462 /// * A NAV, UAV, or lazy code/data
2463 /// * `.none`, if this relocation was deleted (in which case it should be ignored)
2464 node: MappedFile.Node.Index.Optional,
2465 /// The offset of the relocation inside of `node`.
2466 offset: u64,
2467 target: GotKey,
2468 addend: i64,
2469 type: GotReloc.Type,
2470 result: enum(u8) { ok, overflowed, misaligned },
2471
2472 /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target`
2473 /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview.
2474 const Type = packed struct(u16) {
2475 fn simple(target: Target, action: Simple) GotReloc.Type {
2476 assert(target != .special);
2477 return .{ .target = target, .action = .{ .simple = action } };
2478 }
2479
2480 fn special(s: Special) GotReloc.Type {
2481 return .{ .target = .special, .action = .{ .special = s } };
2482 }
2483
2484 target: Target,
2485 action: packed union {
2486 simple: Simple,
2487 special: Special,
2488 },
2489
2490 /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there
2491 /// are fewer different kinds of GOT relocation.
2492 const Target = enum(u3) {
2493 /// This is a "special" relocation whose specific type is in the `action.special` field.
2494 special,
2495
2496 /// Absolute address of the GOT entry.
2497 abs,
2498 /// Offset from the relocation itself to the GOT entry ("PC-relative").
2499 rel,
2500 /// Offset from the base of the GOT to the GOT entry.
2501 offset,
2502 };
2503
2504 const Simple = SymbolReloc.Type.Simple;
2505
2506 /// Like `SymbolReloc.Special`, but for GOT relocations.
2507 const Special = enum(u13) {
2508 larch_pcala_hi20,
2509 larch_pcala64_lo20,
2510 larch_pcala64_hi12,
2511
2512 sparc_op_lox10,
2513 sparc_op_hix22,
2514
2515 fn applyInner(
2516 s: Special,
2517 elf: *Elf,
2518 got_vaddr: u64,
2519 got_offset: u64,
2520 addend: u64,
2521 dest_vaddr: u64,
2522 dest_slice: []u8,
2523 ) error{ RelocationMisaligned, RelocationOverflow }!void {
2524 switch (s) {
2525 .larch_pcala_hi20 => {
2526 const val = got_vaddr +% got_offset +% addend;
2527 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
2528 elf.targetStore(inst, .{
2529 .b0_4 = elf.targetLoad(inst).b0_4,
2530 .j20 = link.loongarch.pcalaHi20(val, dest_vaddr),
2531 .b25_31 = elf.targetLoad(inst).b25_31,
2532 });
2533 },
2534 .larch_pcala64_lo20 => {
2535 const val = got_vaddr +% got_offset +% addend;
2536 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
2537 elf.targetStore(inst, .{
2538 .b0_4 = elf.targetLoad(inst).b0_4,
2539 .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr),
2540 .b25_31 = elf.targetLoad(inst).b25_31,
2541 });
2542 },
2543 .larch_pcala64_hi12 => {
2544 const val = got_vaddr +% got_offset +% addend;
2545 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
2546 elf.targetStore(inst, .{
2547 .b0_9 = elf.targetLoad(inst).b0_9,
2548 .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr),
2549 .b22_31 = elf.targetLoad(inst).b22_31,
2550 });
2551 },
2552 .sparc_op_lox10 => {
2553 const dest_ptr: *align(1) packed struct(u32) {
2554 imm13: u13,
2555 b13_31: u19,
2556 } = @ptrCast(dest_slice);
2557 elf.targetStore(dest_ptr, .{
2558 .imm13 = @as(u10, @truncate(got_offset)),
2559 .b13_31 = elf.targetLoad(dest_ptr).b13_31,
2560 });
2561 },
2562 .sparc_op_hix22 => {
2563 const dest_ptr: *align(1) packed struct(u32) {
2564 imm22: u22,
2565 b22_31: u10,
2566 } = @ptrCast(dest_slice);
2567 elf.targetStore(dest_ptr, .{
2568 .imm22 = @truncate(got_offset >> 10),
2569 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
2570 });
2571 },
2572 }
2573 }
2574 };
2575 };
2576
2577 const Index = enum(u32) {
2578 none = std.math.maxInt(u32),
2579 _,
2580
2581 fn get(index: GotReloc.Index, elf: *Elf) *GotReloc {
2582 return &elf.got_relocs.items[@backingInt(index)];
2583 }
2584 };
2585
2586 fn apply(reloc: *GotReloc, elf: *Elf) void {
2587 assert(elf.ehdrType() != .REL);
2588 const node = reloc.node.unwrap() orelse return; // deleted
2589 if (node.hasMoved(&elf.mf) or elf.shndx.got.node(elf).hasMoved(&elf.mf)) {
2590 // There's no point applying the relocation now, because it will be re-applied by
2591 // `flushMoved` at some point anyway.
2592 return;
2593 }
2594 switch (reloc.result) {
2595 .ok => {},
2596 .overflowed => elf.overflowed_reloc_count -= 1,
2597 .misaligned => elf.misaligned_reloc_count -= 1,
2598 }
2599 if (reloc.applyInner(elf)) {
2600 @branchHint(.likely);
2601 reloc.result = .ok;
2602 } else |err| switch (err) {
2603 error.RelocationOverflow => {
2604 reloc.result = .overflowed;
2605 elf.overflowed_reloc_count += 1;
2606 },
2607 error.RelocationMisaligned => {
2608 reloc.result = .misaligned;
2609 elf.misaligned_reloc_count += 1;
2610 },
2611 }
2612 }
2613 fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void {
2614 const node = reloc.node.unwrap().?;
2615 const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset;
2616 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
2617
2618 const got_vaddr = elf.shndx.got.vaddr(elf);
2619 const got_index: u64 = elf.got.getIndex(reloc.target).?;
2620 const got_offset: u64 = switch (elf.identClass()) {
2621 .NONE, _ => unreachable,
2622 inline else => |class| @sizeOf(class.ElfN().Addr) * got_index,
2623 };
2624 const addend: u64 = @bitCast(reloc.addend);
2625
2626 const target_val: u64 = switch (reloc.type.target) {
2627 .abs => got_vaddr +% got_offset +% addend,
2628 .rel => got_vaddr +% got_offset +% addend -% dest_vaddr,
2629 .offset => got_offset +% addend,
2630 .special => return reloc.type.action.special.applyInner(
2631 elf,
2632 got_vaddr,
2633 got_offset,
2634 addend,
2635 dest_vaddr,
2636 dest_slice,
2637 ),
2638 };
2639 try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian());
2640 }
2641
2642 fn delete(reloc: *GotReloc, elf: *Elf) void {
2643 switch (reloc.result) {
2644 .ok => {},
2645 .overflowed => elf.overflowed_reloc_count -= 1,
2646 .misaligned => elf.misaligned_reloc_count -= 1,
2647 }
2648 reloc.* = .{
2649 .node = .none,
2650 .offset = undefined,
2651 .target = undefined,
2652 .addend = undefined,
2653 .type = undefined,
2654 .result = undefined,
2655 };
2656 }
2657};
2658
2659/// Records all global symbols defined in any DSO we depend on. For each symbol, its name, version,2708/// Records all global symbols defined in any DSO we depend on. For each symbol, its name, version,
2660/// type, size, and alignment are all stored, as well as the soname of the DSO defining it. If one2709/// type, size, and alignment are all stored, as well as the soname of the DSO defining it. If one
2661/// of these symbols ends up being referenced by the ELF module we are producing, we need this2710/// of these symbols ends up being referenced by the ELF module we are producing, we need this
...@@ -3000,6 +3049,8 @@ const AddLocalSymbolOptions = struct {...@@ -3000,6 +3049,8 @@ const AddLocalSymbolOptions = struct {
3000fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalIndex {3049fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalIndex {
3001 const gpa = elf.base.comp.gpa;3050 const gpa = elf.base.comp.gpa;
30023051
3052 assert(opts.shndx != .UNDEF);
3053
3003 try elf.symtab.ensureUnusedCapacity(gpa, 1);3054 try elf.symtab.ensureUnusedCapacity(gpa, 1);
3004 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1);3055 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1);
3005 try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) {3056 try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) {
...@@ -4293,7 +4344,7 @@ const Symbol = struct {...@@ -4293,7 +4344,7 @@ const Symbol = struct {
4293 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;4344 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;
4294 while (ri != .none) {4345 while (ri != .none) {
4295 const reloc = ri.get(elf);4346 const reloc = ri.get(elf);
4296 assert(reloc.target == sym_id);4347 assert(reloc.target_symbol == sym_id);
4297 try reloc.updateDynamicReloc(elf);4348 try reloc.updateDynamicReloc(elf);
4298 ri = reloc.next;4349 ri = reloc.next;
4299 }4350 }
...@@ -4470,7 +4521,7 @@ const Symbol = struct {...@@ -4470,7 +4521,7 @@ const Symbol = struct {
4470 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;4521 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;
4471 while (ri != .none) {4522 while (ri != .none) {
4472 const reloc = ri.get(elf);4523 const reloc = ri.get(elf);
4473 assert(reloc.target == sym_id);4524 assert(reloc.target_symbol == sym_id);
4474 reloc.apply(elf);4525 reloc.apply(elf);
4475 ri = reloc.next;4526 ri = reloc.next;
4476 }4527 }
...@@ -4563,7 +4614,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {...@@ -4563,7 +4614,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {
45634614
4564 const shndx: Section.Index = switch (resolved_sym.unwrap()) {4615 const shndx: Section.Index = switch (resolved_sym.unwrap()) {
4565 .local => shndx: {4616 .local => shndx: {
4566 assert(symtab_shndx != .UNDEF);4617 assert(sym == Symbol.Id.null or symtab_shndx != .UNDEF);
4567 assert(visibility == .DEFAULT);4618 assert(visibility == .DEFAULT);
4568 break :shndx symtab_shndx;4619 break :shndx symtab_shndx;
4569 },4620 },
...@@ -4683,7 +4734,6 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol...@@ -4683,7 +4734,6 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
4683 .shndx = shndx,4734 .shndx = shndx,
4684 }),4735 }),
4685 .first_symbol_reloc = .none,4736 .first_symbol_reloc = .none,
4686 .first_got_reloc = .none,
4687 };4737 };
4688 elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1);4738 elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1);
4689 }4739 }
...@@ -6787,7 +6837,6 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -6787,7 +6837,6 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
6787 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,6837 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
6788 first_node_reloc: ?*NodeReloc.Index = null,6838 first_node_reloc: ?*NodeReloc.Index = null,
6789 skip_node_relocs: MappedFile.Node.Index.Optional = .none,6839 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
6790 first_got_reloc: ?*GotReloc.Index = null,
6791 } = switch (elf.getNode(ni)) {6840 } = switch (elf.getNode(ni)) {
6792 .deleted,6841 .deleted,
6793 .archive,6842 .archive,
...@@ -6814,18 +6863,15 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -6814,18 +6863,15 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
6814 => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported)6863 => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported)
6815 .input_section => |isi| .{6864 .input_section => |isi| .{
6816 .first_symbol_reloc = &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,6865 .first_symbol_reloc = &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc,
6817 .first_got_reloc = &elf.input_sections.items[@backingInt(isi)].first_got_reloc,
6818 },6866 },
6819 .nav => |nmi| .{6867 .nav => |nmi| .{
6820 .first_symbol_reloc = &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,6868 .first_symbol_reloc = &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
6821 .first_got_reloc = &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
6822 },6869 },
6823 .uav => |umi| .{6870 .uav => |umi| .{
6824 .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,6871 .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
6825 },6872 },
6826 inline .lazy_code, .lazy_const_data => |lmi| .{6873 inline .lazy_code, .lazy_const_data => |lmi| .{
6827 .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,6874 .first_symbol_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc,
6828 .first_got_reloc = &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc,
6829 },6875 },
6830 .unit_debug_info_header => |ui| .{6876 .unit_debug_info_header => |ui| .{
6831 .first_node_reloc = &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_node_reloc,6877 .first_node_reloc = &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_node_reloc,
...@@ -6893,19 +6939,6 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {...@@ -6893,19 +6939,6 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
6893 }6939 }
6894 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));6940 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));
6895 }6941 }
6896
6897 if (opts.first_got_reloc) |ptr| {
6898 if (ptr.* != .none) {
6899 for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| {
6900 if (reloc.node != ni.toOptional()) {
6901 if (reloc.node == .none) continue;
6902 break;
6903 }
6904 reloc.delete(elf);
6905 }
6906 }
6907 ptr.* = @fromBackingInt(@intCast(elf.got_relocs.items.len));
6908 }
6909}6942}
69106943
6911/// Given that `node` has moved, updates all relocations in `node` as needed. In relocatables, this6944/// Given that `node` has moved, updates all relocations in `node` as needed. In relocatables, this
...@@ -6918,7 +6951,6 @@ fn flushMovedNodeRelocs(...@@ -6918,7 +6951,6 @@ fn flushMovedNodeRelocs(
6918 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,6951 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
6919 first_node_reloc: NodeReloc.Index = .none,6952 first_node_reloc: NodeReloc.Index = .none,
6920 skip_node_relocs: MappedFile.Node.Index.Optional = .none,6953 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
6921 first_got_reloc: GotReloc.Index = .none,
6922 },6954 },
6923) void {6955) void {
6924 if (opts.first_symbol_reloc != .none) {6956 if (opts.first_symbol_reloc != .none) {
...@@ -6942,16 +6974,6 @@ fn flushMovedNodeRelocs(...@@ -6942,16 +6974,6 @@ fn flushMovedNodeRelocs(
6942 reloc.apply(elf);6974 reloc.apply(elf);
6943 }6975 }
6944 }6976 }
6945
6946 if (opts.first_got_reloc != .none) {
6947 for (elf.got_relocs.items[@backingInt(opts.first_got_reloc)..]) |*reloc| {
6948 if (reloc.node != node.toOptional()) {
6949 if (reloc.node == .none) continue;
6950 break;
6951 }
6952 reloc.apply(elf);
6953 }
6954 }
6955}6977}
69566978
6957fn identClass(elf: *const Elf) std.elf.CLASS {6979fn identClass(elf: *const Elf) std.elf.CLASS {
...@@ -7496,7 +7518,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node...@@ -7496,7 +7518,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
7496 .shndx = shndx,7518 .shndx = shndx,
7497 }),7519 }),
7498 .first_symbol_reloc = .none,7520 .first_symbol_reloc = .none,
7499 .first_got_reloc = .none,
7500 };7521 };
7501 }7522 }
7502 return nmi;7523 return nmi;
...@@ -8064,7 +8085,6 @@ fn loadObject(...@@ -8064,7 +8085,6 @@ fn loadObject(
8064 .vaddr = 0,8085 .vaddr = 0,
8065 .node = ni,8086 .node = ni,
8066 .first_symbol_reloc = .none,8087 .first_symbol_reloc = .none,
8067 .first_got_reloc = .none,
8068 };8088 };
8069 elf.input_prog_node.increaseEstimatedTotalItems(1);8089 elf.input_prog_node.increaseEstimatedTotalItems(1);
8070 }8090 }
...@@ -9422,7 +9442,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -9422,7 +9442,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
9422 const gpa = elf.base.comp.gpa;9442 const gpa = elf.base.comp.gpa;
9423 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);9443 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);
9424 try elf.node_relocs.ensureUnusedCapacity(gpa, len);9444 try elf.node_relocs.ensureUnusedCapacity(gpa, len);
9425 try elf.got_relocs.ensureUnusedCapacity(gpa, len);
9426 const class = elf.identClass();9445 const class = elf.identClass();
9427 switch (elf.ehdrType()) {9446 switch (elf.ehdrType()) {
9428 .REL => {9447 .REL => {
...@@ -9460,7 +9479,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)...@@ -9460,7 +9479,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
9460 try shndx.get(elf).rela.shndx.relaEnsureAdditionalCapacity(elf, len);9479 try shndx.get(elf).rela.shndx.relaEnsureAdditionalCapacity(elf, len);
9461 },9480 },
9462 .EXEC, .DYN => {9481 .EXEC, .DYN => {
9463 try elf.tls_size_symbol_relocs.ensureUnusedCapacity(gpa, len);
9464 const new_got_entries = len * 2; // at worst, every reloc is a new TLSGD9482 const new_got_entries = len * 2; // at worst, every reloc is a new TLSGD
9465 try elf.got.ensureUnusedCapacity(gpa, new_got_entries);9483 try elf.got.ensureUnusedCapacity(gpa, new_got_entries);
9466 const need_got_size = switch (class) {9484 const need_got_size = switch (class) {
...@@ -9506,13 +9524,12 @@ fn addRelocAssumeCapacity(...@@ -9506,13 +9524,12 @@ fn addRelocAssumeCapacity(
9506 elf.symbol_relocs.appendAssumeCapacity(.{9524 elf.symbol_relocs.appendAssumeCapacity(.{
9507 .node = node.toOptional(),9525 .node = node.toOptional(),
9508 .offset = offset,9526 .offset = offset,
9509 .type = undefined,9527 .bits = undefined,
9510 .target = target,9528 .target_symbol = target,
9511 .addend = .{ .normal = addend },9529 .addend = .{ .normal = addend },
9512 .next = next,9530 .next = next,
9513 .prev = .none,9531 .prev = .none,
9514 .rela_index = rela_index.toOptional(),9532 .rela_index = rela_index.toOptional(),
9515 .result = .ok,
9516 });9533 });
9517 ri.get(elf).apply(elf);9534 ri.get(elf).apply(elf);
9518 },9535 },
...@@ -9567,14 +9584,14 @@ fn addRelocAssumeCapacity(...@@ -9567,14 +9584,14 @@ fn addRelocAssumeCapacity(
9567 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),9584 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),
9568 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })),9585 .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })),
95699586
9570 .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),9587 .GOT_PC_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),
9571 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala_hi20)),9588 .GOT_PC_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala_hi20)),
9572 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala64_lo20)),9589 .GOT64_PC_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala64_lo20)),
9573 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala64_hi12)),9590 .GOT64_PC_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala64_hi12)),
9574 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),9591 .GOT_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),
9575 .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"12" })),9592 .GOT_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"12" })),
9576 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),9593 .GOT64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),
9577 .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })),9594 .GOT64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })),
9578 // zig fmt: on9595 // zig fmt: on
9579 },9596 },
9580 .PPC64 => switch (@"type".PPC64) {9597 .PPC64 => switch (@"type".PPC64) {
...@@ -9678,13 +9695,13 @@ fn addRelocAssumeCapacity(...@@ -9678,13 +9695,13 @@ fn addRelocAssumeCapacity(
9678 .TLS_DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),9695 .TLS_DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),
9679 .TLS_DTPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),9696 .TLS_DTPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),
96809697
9681 .GOT13 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[12:0]", .cast = .unsigned, .shift = .@"0" })),9698 .GOT13 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32[12:0]", .cast = .unsigned, .shift = .@"0" })),
9682 .GOT22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),9699 .GOT22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9683 .GOTDATA_OP_LOX10 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.sparc_op_lox10)),9700 .GOTDATA_OP_LOX10 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.sparc_got_op_lox10)),
9684 .GOTDATA_OP_HIX22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.sparc_op_hix22)),9701 .GOTDATA_OP_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.sparc_got_op_hix22)),
9685 .TLS_GD_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),9702 .TLS_GD_HI22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tlsgd, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9686 .TLS_LDM_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),9703 .TLS_LDM_HI22 => try elf.addSymbolRelocAssumeCapacity(node, offset, .null, addend, .simple(.gotoff_tlsgd, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9687 .TLS_IE_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),9704 .TLS_IE_HI22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tpoff, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9688 // zig fmt: on9705 // zig fmt: on
96899706
9690 .TLS_GD_CALL, .TLS_LDM_CALL => {9707 .TLS_GD_CALL, .TLS_LDM_CALL => {
...@@ -9750,19 +9767,19 @@ fn addRelocAssumeCapacity(...@@ -9750,19 +9767,19 @@ fn addRelocAssumeCapacity(
9750 },9767 },
9751 .GOT10 => {9768 .GOT10 => {
9752 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });9769 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
9753 elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));9770 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
9754 },9771 },
9755 .TLS_GD_LO10 => {9772 .TLS_GD_LO10 => {
9756 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });9773 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
9757 elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));9774 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tlsgd, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
9758 },9775 },
9759 .TLS_LDM_LO10 => {9776 .TLS_LDM_LO10 => {
9760 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });9777 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
9761 elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));9778 try elf.addSymbolRelocAssumeCapacity(node, offset, .null, addend, .simple(.gotoff_tlsgd, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
9762 },9779 },
9763 .TLS_IE_LO10 => {9780 .TLS_IE_LO10 => {
9764 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });9781 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
9765 elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));9782 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
9766 },9783 },
9767 },9784 },
9768 .X86_64 => rel_type: switch (@"type".X86_64) {9785 .X86_64 => rel_type: switch (@"type".X86_64) {
...@@ -9790,12 +9807,7 @@ fn addRelocAssumeCapacity(...@@ -9790,12 +9807,7 @@ fn addRelocAssumeCapacity(
9790 .GOTOFF64 => return error.UnimplementedRelocation, // offset of symbol from GOT base9807 .GOTOFF64 => return error.UnimplementedRelocation, // offset of symbol from GOT base
9791 .PLTOFF64 => return error.UnimplementedRelocation, // offset of PLT entry from GOT base (yes, I know, the name is stupid)9808 .PLTOFF64 => return error.UnimplementedRelocation, // offset of PLT entry from GOT base (yes, I know, the name is stupid)
97929809
9793 // TODO: figure out how to do relaxations. Perhaps we want to remove a `GotReloc`9810 // TODO: figure out how to do relaxations
9794 // and replace it with a `SymbolReloc` when a relaxation becomes possible, but we'd
9795 // need to bear in mind whether incremental updates might make a relaxation
9796 // impossible again or something like that. Relaxations seem kind of hostile to
9797 // incremental compilation, so perhaps we just only support them in non-incremental
9798 // compilations and just apply them in flush or something.
97999811
9800 // Relaxable versions of other relocations. Since we don't yet implement relaxation,9812 // Relaxable versions of other relocations. Since we don't yet implement relaxation,
9801 // just use the handling for the non-relaxable versions.9813 // just use the handling for the non-relaxable versions.
...@@ -9831,13 +9843,13 @@ fn addRelocAssumeCapacity(...@@ -9831,13 +9843,13 @@ fn addRelocAssumeCapacity(
9831 .TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),9843 .TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9832 .TPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),9844 .TPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),
98339845
9834 .GOT32 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),9846 .GOT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),
9835 .GOT64 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),9847 .GOT64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),
9836 .GOTPCREL => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),9848 .GOTPCREL => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_symbol, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9837 .GOTPCREL64 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.rel, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),9849 .GOTPCREL64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_symbol, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),
9838 .TLSGD => elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),9850 .TLSGD => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_tlsgd, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9839 .TLSLD => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),9851 .TLSLD => try elf.addSymbolRelocAssumeCapacity(node, offset, .null, addend, .simple(.gotrel_tlsgd, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9840 .GOTTPOFF => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),9852 .GOTTPOFF => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9841 // zig fmt: on9853 // zig fmt: on
98429854
9843 .GOTPC64 => {9855 .GOTPC64 => {
...@@ -9872,6 +9884,8 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -9872,6 +9884,8 @@ fn addSymbolRelocAssumeCapacityInner(
9872) Error!void {9884) Error!void {
9873 assert(elf.ehdrType() != .REL);9885 assert(elf.ehdrType() != .REL);
98749886
9887 const gpa = elf.base.comp.gpa;
9888
9875 request_static_target: {9889 request_static_target: {
9876 if (elf.shndx.dynamic == .UNDEF) break :request_static_target;9890 if (elf.shndx.dynamic == .UNDEF) break :request_static_target;
9877 const gsi: Symbol.Global.Index = switch (target.unwrap()) {9891 const gsi: Symbol.Global.Index = switch (target.unwrap()) {
...@@ -9894,6 +9908,15 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -9894,6 +9908,15 @@ fn addSymbolRelocAssumeCapacityInner(
9894 .dtpoff,9908 .dtpoff,
9895 .tpoff,9909 .tpoff,
9896 .size,9910 .size,
9911 .gotabs_symbol,
9912 .gotrel_symbol,
9913 .gotoff_symbol,
9914 .gotabs_tpoff,
9915 .gotrel_tpoff,
9916 .gotoff_tpoff,
9917 .gotabs_tlsgd,
9918 .gotrel_tlsgd,
9919 .gotoff_tlsgd,
9897 => false,9920 => false,
98989921
9899 .special => switch (@"type".action.special) {9922 .special => switch (@"type".action.special) {
...@@ -9908,10 +9931,15 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -9908,10 +9931,15 @@ fn addSymbolRelocAssumeCapacityInner(
9908 .larch_b21,9931 .larch_b21,
9909 .larch_b26,9932 .larch_b26,
9910 .larch_call36,9933 .larch_call36,
9934 .larch_got_pcala_hi20,
9935 .larch_got_pcala64_lo20,
9936 .larch_got_pcala64_hi12,
99119937
9912 .sparc_le_hix22,9938 .sparc_le_hix22,
9913 .sparc_wdisp10,9939 .sparc_wdisp10,
9914 .sparc_wdisp16,9940 .sparc_wdisp16,
9941 .sparc_got_op_lox10,
9942 .sparc_got_op_hix22,
9915 => false,9943 => false,
9916 },9944 },
9917 };9945 };
...@@ -9923,6 +9951,42 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -9923,6 +9951,42 @@ fn addSymbolRelocAssumeCapacityInner(
9923 }9951 }
9924 }9952 }
99259953
9954 if (@"type".needsGotEntry()) |got_kind| {
9955 const new_index: usize, const new_len: u32 = switch (got_kind) {
9956 .symbol => new: {
9957 const gop = try elf.got.getOrPut(gpa, .{ .symbol = target });
9958 if (gop.found_existing) break :new .{ 0, 0 };
9959 gop.value_ptr.* = .none;
9960 break :new .{ gop.index, 1 };
9961 },
9962 .tpoff => new: {
9963 const gop = try elf.got.getOrPut(gpa, .{ .tpoff = target });
9964 if (gop.found_existing) break :new .{ 0, 0 };
9965 gop.value_ptr.* = .none;
9966 break :new .{ gop.index, 1 };
9967 },
9968 .tlsgd => new: {
9969 try elf.got.ensureUnusedCapacity(gpa, 2);
9970 const gop = elf.got.getOrPutAssumeCapacity(.{ .tlsgd0 = target });
9971 if (gop.found_existing) break :new .{ 0, 0 };
9972 gop.value_ptr.* = .none;
9973 elf.got.putAssumeCapacityNoClobber(.{ .tlsgd1 = target }, .none);
9974 break :new .{ gop.index, 1 };
9975 },
9976 };
9977
9978 switch (elf.shdrPtr(elf.shndx.got)) {
9979 inline else => |got_shdr, class| {
9980 const new_size = elf.targetLoad(&got_shdr.size) + new_len * @sizeOf(class.ElfN().Addr);
9981 elf.targetStore(&got_shdr.size, new_size);
9982 try elf.shndx.got.node(elf).ensureMinimumSize(gpa, &elf.mf, new_size);
9983 },
9984 }
9985 for (new_index..new_index + new_len) |got_index| {
9986 elf.updateGotEntry(got_index);
9987 }
9988 }
9989
9926 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));9990 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
9927 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;9991 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
9928 const next = first_target_reloc.*;9992 const next = first_target_reloc.*;
...@@ -9931,16 +9995,21 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -9931,16 +9995,21 @@ fn addSymbolRelocAssumeCapacityInner(
9931 elf.symbol_relocs.appendAssumeCapacity(.{9995 elf.symbol_relocs.appendAssumeCapacity(.{
9932 .node = node.toOptional(),9996 .node = node.toOptional(),
9933 .offset = offset,9997 .offset = offset,
9934 .target = target,9998 .target_symbol = target,
9935 .addend = addend,9999 .addend = addend,
9936 .type = @"type",10000 .bits = .{
10001 .type = @"type",
10002 .result = .ok,
10003 },
9937 .next = next,10004 .next = next,
9938 .prev = .none,10005 .prev = .none,
9939 .rela_index = .none,10006 .rela_index = .none,
9940 .result = .ok,
9941 });10007 });
9942 if (@"type".dependsOnTlsSize(elf)) {10008 if (@"type".dependsOnTlsSize(elf)) {
9943 elf.tls_size_symbol_relocs.putAssumeCapacityNoClobber(ri, {});10009 try elf.tls_size_symbol_relocs.putNoClobber(gpa, ri, {});
10010 }
10011 if (@"type".dependsOnGotAddress()) {
10012 try elf.got_relocs.put(gpa, ri, {});
9944 }10013 }
9945 try ri.get(elf).updateDynamicReloc(elf);10014 try ri.get(elf).updateDynamicReloc(elf);
994610015
...@@ -10046,95 +10115,6 @@ fn addNodeRelocAssumeCapacity(...@@ -10046,95 +10115,6 @@ fn addNodeRelocAssumeCapacity(
10046 },10115 },
10047 }10116 }
10048}10117}
10049fn addGotRelocAssumeCapacity(
10050 elf: *Elf,
10051 node: MappedFile.Node.Index,
10052 offset: u64,
10053 target: GotKey,
10054 addend: i64,
10055 @"type": GotReloc.Type,
10056) void {
10057 assert(elf.ehdrType() != .REL);
10058 switch (elf.getNode(node)) {
10059 .deleted,
10060 .archive,
10061 .archive_header,
10062 .archive_input_member,
10063 .archive_elf_member_header,
10064 .elf,
10065 .ehdr,
10066 .shdr,
10067 .segment,
10068 .copied_global,
10069 .debug_shared,
10070 .debug_addr,
10071 .eh_frame_footer,
10072 .debug_str_offsets,
10073 .unit_padding,
10074 .unit_frame,
10075 .unit_frame_cie,
10076 .unit_debug_info,
10077 .unit_debug_info_header,
10078 .unit_debug_info_footer,
10079 .unit_debug_line,
10080 .unit_debug_line_header,
10081 .unit_debug_rnglists,
10082 .const_debug_info,
10083 .global_debug_info,
10084 .func_frame_fde,
10085 .func_debug_info,
10086 .func_debug_line,
10087 .decl_debug_info,
10088 => unreachable, // cannot contain relocs,
10089 .section,
10090 .section_manual_size,
10091 .uav,
10092 => unreachable, // cannot contain GOT relocs
10093 .input_section,
10094 .nav,
10095 .lazy_code,
10096 .lazy_const_data,
10097 => {},
10098 }
10099
10100 const gop = elf.got.getOrPutAssumeCapacity(target);
10101 if (!gop.found_existing) {
10102 gop.value_ptr.* = .none;
10103 const maybe_next_key: ?GotKey = switch (target) {
10104 .reserved => null,
10105 .tpoff => null,
10106 .symbol => null,
10107 .tlsld0 => .tlsld1,
10108 .tlsgd0 => |sym| .{ .tlsgd1 = sym },
10109 .tlsld1 => unreachable,
10110 .tlsgd1 => unreachable,
10111 };
10112 switch (elf.shdrPtr(elf.shndx.got)) {
10113 inline else => |got_shdr, class| {
10114 const Addr = class.ElfN().Addr;
10115 const old_size = elf.targetLoad(&got_shdr.size);
10116 const new_entry_count = @as(u32, 1) + @intFromBool(maybe_next_key != null);
10117 elf.targetStore(&got_shdr.size, @intCast(old_size + @sizeOf(Addr) * new_entry_count));
10118 },
10119 }
10120 if (maybe_next_key) |next_key| {
10121 elf.got.putAssumeCapacityNoClobber(next_key, .none);
10122 elf.updateGotEntry(gop.index);
10123 elf.updateGotEntry(gop.index + 1);
10124 } else {
10125 elf.updateGotEntry(gop.index);
10126 }
10127 }
10128
10129 elf.got_relocs.appendAssumeCapacity(.{
10130 .node = .wrap(node),
10131 .offset = offset,
10132 .target = target,
10133 .addend = addend,
10134 .type = @"type",
10135 .result = .ok,
10136 });
10137}
10138fn updateGotEntry(elf: *Elf, got_index: usize) void {10118fn updateGotEntry(elf: *Elf, got_index: usize) void {
10139 assert(elf.ehdrType() != .REL);10119 assert(elf.ehdrType() != .REL);
10140 const entry_value: union(enum) {10120 const entry_value: union(enum) {
...@@ -10193,15 +10173,6 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -10193,15 +10173,6 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
10193 .addend = 0,10173 .addend = 0,
10194 } },10174 } },
10195 },10175 },
10196 .tlsgd1 => |sym| switch (elf.classifySymbolValue(sym)) {
10197 .static => .{ .unsigned = sym.value(elf) },
10198 .static_relative => unreachable, // TLS variables should be in TLS sections, which do not return `.static_relative`
10199 .dynamic => .{ .reloc = .{
10200 .type = .dtpOff(elf),
10201 .dynsym_index = sym.unwrap().global.dynsymIndex(elf).?,
10202 .addend = 0,
10203 } },
10204 },
10205 .tlsgd0 => |sym| switch (elf.base.comp.config.link_mode) {10176 .tlsgd0 => |sym| switch (elf.base.comp.config.link_mode) {
10206 .static => val: {10177 .static => val: {
10207 assert(elf.base.comp.config.output_mode == .Exe); // static libraries don't have GOTs10178 assert(elf.base.comp.config.output_mode == .Exe); // static libraries don't have GOTs
...@@ -10209,25 +10180,28 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -10209,25 +10180,28 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
10209 },10180 },
10210 .dynamic => .{ .reloc = .{10181 .dynamic => .{ .reloc = .{
10211 .type = .dtpMod(elf),10182 .type = .dtpMod(elf),
10212 .dynsym_index = switch (elf.classifySymbolValue(sym)) {10183 .dynsym_index = switch (sym) {
10213 .static, .static_relative => 0,10184 .null => 0,
10214 .dynamic => sym.unwrap().global.dynsymIndex(elf).?,10185 else => switch (elf.classifySymbolValue(sym)) {
10186 .static, .static_relative => 0,
10187 .dynamic => sym.unwrap().global.dynsymIndex(elf).?,
10188 },
10215 },10189 },
10216 .addend = 0,10190 .addend = 0,
10217 } },10191 } },
10218 },10192 },
10219 .tlsld0 => switch (elf.base.comp.config.link_mode) {10193 .tlsgd1 => |sym| switch (sym) {
10220 .static => val: {10194 .null => .{ .unsigned = 0 },
10221 assert(elf.base.comp.config.output_mode == .Exe); // static libraries don't have GOTs10195 else => switch (elf.classifySymbolValue(sym)) {
10222 break :val .{ .unsigned = 1 }; // TLS module ID for executable10196 .static => .{ .unsigned = sym.value(elf) },
10197 .static_relative => unreachable, // TLS variables should be in TLS sections, which do not return `.static_relative`
10198 .dynamic => .{ .reloc = .{
10199 .type = .dtpOff(elf),
10200 .dynsym_index = sym.unwrap().global.dynsymIndex(elf).?,
10201 .addend = 0,
10202 } },
10223 },10203 },
10224 .dynamic => .{ .reloc = .{
10225 .type = .dtpMod(elf),
10226 .dynsym_index = 0,
10227 .addend = 0,
10228 } },
10229 },10204 },
10230 .tlsld1 => .{ .unsigned = 0 },
10231 };10205 };
1023210206
10233 // First, write to the GOT itself. If we're planning to use a relocation, we'll just write zeroes.10207 // First, write to the GOT itself. If we're planning to use a relocation, we'll just write zeroes.
...@@ -10994,7 +10968,7 @@ pub fn idle(elf: *Elf) link.Error!bool {...@@ -10994,7 +10968,7 @@ pub fn idle(elf: *Elf) link.Error!bool {
10994 var ri = symtab_index.ptr(elf).first_target_reloc;10968 var ri = symtab_index.ptr(elf).first_target_reloc;
10995 while (ri != .none) {10969 while (ri != .none) {
10996 const reloc = ri.get(elf);10970 const reloc = ri.get(elf);
10997 assert(reloc.target == sym_id);10971 assert(reloc.target_symbol == sym_id);
10998 // In relocatables, every symbol relocation has an output relocation.10972 // In relocatables, every symbol relocation has an output relocation.
10999 const rela_index = reloc.rela_index.unwrap().?;10973 const rela_index = reloc.rela_index.unwrap().?;
11000 reloc.relaSection(elf).relaUpdateSym(elf, rela_index, @backingInt(symtab_index));10974 reloc.relaSection(elf).relaUpdateSym(elf, rela_index, @backingInt(symtab_index));
...@@ -11024,7 +10998,7 @@ pub fn idle(elf: *Elf) link.Error!bool {...@@ -11024,7 +10998,7 @@ pub fn idle(elf: *Elf) link.Error!bool {
11024 var ri = symtab_index.ptr(elf).first_target_reloc;10998 var ri = symtab_index.ptr(elf).first_target_reloc;
11025 while (ri != .none) {10999 while (ri != .none) {
11026 const reloc = ri.get(elf);11000 const reloc = ri.get(elf);
11027 assert(reloc.target == sym_id);11001 assert(reloc.target_symbol == sym_id);
11028 // There may or may not be a runtime relocation for this symbol reloc.11002 // There may or may not be a runtime relocation for this symbol reloc.
11029 if (reloc.rela_index.unwrap()) |rela_index| {11003 if (reloc.rela_index.unwrap()) |rela_index| {
11030 elf.shndx.rela_dyn.relaUpdateSym(elf, rela_index, dynsym_index);11004 elf.shndx.rela_dyn.relaUpdateSym(elf, rela_index, dynsym_index);
...@@ -11615,8 +11589,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -11615,8 +11589,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
11615 const rela_index = opt_rela_index.unwrap() orelse continue;11589 const rela_index = opt_rela_index.unwrap() orelse continue;
11616 rela_dyn_shndx.relaAdjustOffset(elf, rela_index, old_addr, addr);11590 rela_dyn_shndx.relaAdjustOffset(elf, rela_index, old_addr, addr);
11617 }11591 }
11618 for (elf.got_relocs.items) |*reloc| {11592 for (elf.got_relocs.keys()) |ri| {
11619 reloc.apply(elf);11593 ri.get(elf).apply(elf);
11620 }11594 }
11621 } else if (shndx == elf.shndx.plt) {11595 } else if (shndx == elf.shndx.plt) {
11622 elf.flushMovedNodeRelocs(ni, .{11596 elf.flushMovedNodeRelocs(ni, .{
...@@ -11683,7 +11657,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -11683,7 +11657,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1168311657
11684 elf.flushMovedNodeRelocs(ni, .{11658 elf.flushMovedNodeRelocs(ni, .{
11685 .first_symbol_reloc = isi.ptrConst(elf).first_symbol_reloc,11659 .first_symbol_reloc = isi.ptrConst(elf).first_symbol_reloc,
11686 .first_got_reloc = isi.ptrConst(elf).first_got_reloc,
11687 });11660 });
11688 },11661 },
11689 .copied_global => |global_name| {11662 .copied_global => |global_name| {
...@@ -11714,7 +11687,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void...@@ -11714,7 +11687,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
11714 .none,11687 .none,
11715 .uav, .lazy_code, .lazy_const_data => .none,11688 .uav, .lazy_code, .lazy_const_data => .none,
11716 },11689 },
11717 .first_got_reloc = mi.firstGotReloc(elf),
11718 });11690 });
11719 },11691 },
11720 .debug_shared => |ss| {11692 .debug_shared => |ss| {
...@@ -12200,8 +12172,6 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo...@@ -12200,8 +12172,6 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
12200 switch (got_key) {12172 switch (got_key) {
12201 .reserved,12173 .reserved,
12202 .symbol,12174 .symbol,
12203 .tlsld0,
12204 .tlsld1,
12205 .tlsgd0,12175 .tlsgd0,
12206 .tlsgd1,12176 .tlsgd1,
12207 => {12177 => {