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 {
208208 lsi: Symbol.LocalIndex,
209209 /// The start index of the contiguous sequence of symbol relocations in this NAV.
210210 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,
213211}),
214212uavs: std.array_hash_map.Auto(InternPool.Index, struct {
215213 lsi: Symbol.LocalIndex,
216214 /// The start index of the contiguous sequence of symbol relocations in this UAV.
217215 first_symbol_reloc: SymbolReloc.Index,
218 // No `first_got_reloc` field because a UAV never contains GOT relocations.
219216}),
220217lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
221218 map: std.array_hash_map.Auto(InternPool.Index, struct {
222219 lsi: Symbol.LocalIndex,
223220 /// The start index of the contiguous sequence of symbol relocations in this lazy code/data.
224221 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,
227222 }),
228223 pending_index: u32,
229224}),
230225pending_uavs: std.ArrayList(Node.UavMapIndex),
231226symbol_relocs: std.ArrayList(SymbolReloc),
232227node_relocs: std.ArrayList(NodeReloc),
233got_relocs: std.ArrayList(GotReloc),
228got_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
234229/// Set of relocations which must be re-applied if the size of the TLS segment changes.
235230tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void),
236231/// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`.
......@@ -388,9 +383,6 @@ const Node = union(enum) {
388383 fn firstSymbolReloc(nmi: NavMapIndex, elf: *const Elf) SymbolReloc.Index {
389384 return elf.navs.values()[@backingInt(nmi)].first_symbol_reloc;
390385 }
391 fn firstGotReloc(nmi: NavMapIndex, elf: *const Elf) GotReloc.Index {
392 return elf.navs.values()[@backingInt(nmi)].first_got_reloc;
393 }
394386 };
395387
396388 pub const UavMapIndex = enum(u32) {
......@@ -407,11 +399,6 @@ const Node = union(enum) {
407399 fn firstSymbolReloc(umi: UavMapIndex, elf: *const Elf) SymbolReloc.Index {
408400 return elf.uavs.values()[@backingInt(umi)].first_symbol_reloc;
409401 }
410 fn firstGotReloc(umi: UavMapIndex, elf: *const Elf) GotReloc.Index {
411 _ = umi;
412 _ = elf;
413 return .none;
414 }
415402 };
416403
417404 pub const LazyMapRef = struct {
......@@ -437,9 +424,6 @@ const Node = union(enum) {
437424 fn firstSymbolReloc(lmi: @This(), elf: *const Elf) SymbolReloc.Index {
438425 return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_symbol_reloc;
439426 }
440 fn firstGotReloc(lmi: @This(), elf: *const Elf) GotReloc.Index {
441 return elf.lazy.getPtrConst(kind).map.values()[@backingInt(lmi)].first_got_reloc;
442 }
443427 };
444428 }
445429
......@@ -603,8 +587,6 @@ const InputSection = struct {
603587 node: MappedFile.Node.Index,
604588 /// The start index of the contiguous sequence of symbol relocations in this input section.
605589 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
609591 const Index = enum(u32) {
610592 _,
......@@ -1387,14 +1369,29 @@ const SymbolReloc = struct {
13871369 node: MappedFile.Node.Index.Optional,
13881370 /// The offset of the relocation inside of `node`.
13891371 offset: u64,
1390 /// A symbol used to compute the relocated value. Precise meaning depends on `@"type"`.
1391 target: Symbol.Id,
1392 /// A signed constant 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"`.
1373 target_symbol: Symbol.Id,
1374 /// A signed constant used to compute the relocated value. Precise meaning depends on `bits.@"type"`.
13931375 addend: SymbolReloc.Addend,
1394 /// Specifies how to apply the relocation.
1395 ///
1396 /// When emitting a relocatable, this field is `undefined`.
1397 type: SymbolReloc.Type,
1376 bits: packed struct(u32) {
1377 /// Specifies how to apply the relocation.
1378 ///
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 },
13981395 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so
13991396 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.
14001397 /// Doubly-linked so that relocations can be removed.
......@@ -1412,13 +1409,6 @@ const SymbolReloc = struct {
14121409 /// relocation entry. The entry will be removed if we discover a definition which allows us to
14131410 /// statically resolve the relocation.
14141411 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
14231413 /// Determines the section in which this relocation will be placed if it is outstanding.
14241414 ///
......@@ -1464,7 +1454,7 @@ const SymbolReloc = struct {
14641454 /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on
14651455 /// a symbol value. The representation is simply a big enum containing all of these exceptional
14661456 /// cases---see `Special`. This representation is in use when `Type.target == .special`.
1467 const Type = packed struct(u16) {
1457 const Type = packed struct(u18) {
14681458 /// Helper function for constructing a "simple" relocation type. This mainly exists to
14691459 /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`.
14701460 fn simple(target: Target, action: Simple) SymbolReloc.Type {
......@@ -1493,7 +1483,7 @@ const SymbolReloc = struct {
14931483 /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the
14941484 /// relocation---whether we care about the target symbol's absolute address, its PC-relative
14951485 /// address, its PLT entry, etc.
1496 const Target = enum(u3) {
1486 const Target = enum(u5) {
14971487 /// This is a "special" relocation whose specific type is in the `action.special` field.
14981488 special,
14991489
......@@ -1501,6 +1491,7 @@ const SymbolReloc = struct {
15011491 abs,
15021492 /// Offset from the relocation itself to the target symbol ("PC-relative").
15031493 rel,
1494
15041495 /// Address of the target symbol's PLT entry.
15051496 ///
15061497 /// If the target symbol does not have a PLT entry, equivalent to `.abs`.
......@@ -1509,12 +1500,35 @@ const SymbolReloc = struct {
15091500 ///
15101501 /// If the target symbol does not have a PLT entry, equivalent to `.rel`.
15111502 pltrel,
1503
15121504 /// Offset of the target TLS symbol from the base of this DSO's own TLS region.
15131505 dtpoff,
15141506 /// Offset of the target TLS symbol from the raw thread pointer.
15151507 tpoff,
1508
15161509 /// Size of the target symbol.
15171510 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,
15181532 };
15191533
15201534 /// For a "simple" relocation, after the initial value is computed according to `Target`, a
......@@ -1701,17 +1715,22 @@ const SymbolReloc = struct {
17011715 larch_b21,
17021716 larch_b26,
17031717 larch_call36,
1718 larch_got_pcala_hi20,
1719 larch_got_pcala64_lo20,
1720 larch_got_pcala64_hi12,
17041721
17051722 sparc_olo10,
17061723 sparc_hix22,
17071724 sparc_le_hix22,
17081725 sparc_wdisp10,
17091726 sparc_wdisp16,
1727 sparc_got_op_lox10,
1728 sparc_got_op_hix22,
17101729
17111730 fn applyInner(
17121731 s: Special,
17131732 elf: *Elf,
1714 target: Symbol.Id,
1733 target_sym: Symbol.Id,
17151734 addend: SymbolReloc.Addend,
17161735 dest_vaddr: u64,
17171736 dest_slice: []u8,
......@@ -1719,7 +1738,7 @@ const SymbolReloc = struct {
17191738 const normal_addend: u64 = @bitCast(addend.normal);
17201739 switch (s) {
17211740 .larch_pcala_hi20 => {
1722 const val = target.value(elf) +% normal_addend;
1741 const val = target_sym.value(elf) +% normal_addend;
17231742 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
17241743 elf.targetStore(inst, .{
17251744 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1728,7 +1747,7 @@ const SymbolReloc = struct {
17281747 });
17291748 },
17301749 .larch_pcala64_lo20 => {
1731 const val = target.value(elf) +% normal_addend;
1750 const val = target_sym.value(elf) +% normal_addend;
17321751 const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]);
17331752 elf.targetStore(inst, .{
17341753 .b0_4 = elf.targetLoad(inst).b0_4,
......@@ -1737,7 +1756,7 @@ const SymbolReloc = struct {
17371756 });
17381757 },
17391758 .larch_pcala64_hi12 => {
1740 const val = target.value(elf) +% normal_addend;
1759 const val = target_sym.value(elf) +% normal_addend;
17411760 const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]);
17421761 elf.targetStore(inst, .{
17431762 .b0_9 = elf.targetLoad(inst).b0_9,
......@@ -1746,7 +1765,7 @@ const SymbolReloc = struct {
17461765 });
17471766 },
17481767 .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);
17501769 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
17511770 if ((jump_offset >> 2) << 2 != jump_offset) {
17521771 return error.RelocationMisaligned;
......@@ -1806,9 +1825,43 @@ const SymbolReloc = struct {
18061825 }
18071826 },
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
18091862 .sparc_olo10 => {
18101863 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));
18121865 const simm13 = std.math.cast(i13, lo10 + addends.o) orelse return error.RelocationOverflow;
18131866 const dest_ptr: *align(1) packed struct(u32) {
18141867 simm13: u13,
......@@ -1825,7 +1878,7 @@ const SymbolReloc = struct {
18251878 b22_31: u10,
18261879 } = @ptrCast(dest_slice);
18271880 elf.targetStore(dest_ptr, .{
1828 .imm22 = @truncate(~(target.value(elf) +% normal_addend) >> 10),
1881 .imm22 = @truncate(~(target_sym.value(elf) +% normal_addend) >> 10),
18291882 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
18301883 });
18311884 },
......@@ -1842,12 +1895,12 @@ const SymbolReloc = struct {
18421895 b22_31: u10,
18431896 } = @ptrCast(dest_slice);
18441897 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),
18461899 .b22_31 = elf.targetLoad(dest_ptr).b22_31,
18471900 });
18481901 },
18491902 .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);
18511904 const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr);
18521905 if ((jump_offset >> 2) << 2 != jump_offset) {
18531906 return error.RelocationMisaligned;
......@@ -1897,10 +1950,120 @@ const SymbolReloc = struct {
18971950 else => unreachable,
18981951 }
18991952 },
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 },
19001976 }
19011977 }
19021978 };
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
19042067 fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool {
19052068 return switch (elf.targetTlsVariant()) {
19062069 // In TLS variant I, the executable's TLS block starts at a fixed offset from the
......@@ -1917,6 +2080,15 @@ const SymbolReloc = struct {
19172080 .pltrel,
19182081 .dtpoff,
19192082 .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,
19202092 => false,
19212093
19222094 .tpoff => true,
......@@ -1931,11 +2103,16 @@ const SymbolReloc = struct {
19312103 .larch_b21,
19322104 .larch_b26,
19332105 .larch_call36,
2106 .larch_got_pcala_hi20,
2107 .larch_got_pcala64_lo20,
2108 .larch_got_pcala64_hi12,
19342109
19352110 .sparc_olo10,
19362111 .sparc_hix22,
19372112 .sparc_wdisp10,
19382113 .sparc_wdisp16,
2114 .sparc_got_op_lox10,
2115 .sparc_got_op_hix22,
19392116 => false,
19402117 },
19412118 },
......@@ -1954,7 +2131,7 @@ const SymbolReloc = struct {
19542131
19552132 fn apply(reloc: *SymbolReloc, elf: *Elf) void {
19562133 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)) {
19582135 // There's no point applying the relocation now, because it will be re-applied by
19592136 // `flushMoved` at some point anyway.
19602137 return;
......@@ -1966,7 +2143,7 @@ const SymbolReloc = struct {
19662143 reloc.relaSection(elf).relaSetOffset(elf, rela_index, reloc_addr);
19672144 return;
19682145 }
1969 switch (reloc.result) {
2146 switch (reloc.bits.result) {
19702147 .ok => {},
19712148 .overflowed => elf.overflowed_reloc_count -= 1,
19722149 .misaligned => elf.misaligned_reloc_count -= 1,
......@@ -1977,14 +2154,14 @@ const SymbolReloc = struct {
19772154 }
19782155 if (reloc.applyInner(elf)) {
19792156 @branchHint(.likely);
1980 reloc.result = .ok;
2157 reloc.bits.result = .ok;
19812158 } else |err| switch (err) {
19822159 error.RelocationOverflow => {
1983 reloc.result = .overflowed;
2160 reloc.bits.result = .overflowed;
19842161 elf.overflowed_reloc_count += 1;
19852162 },
19862163 error.RelocationMisaligned => {
1987 reloc.result = .misaligned;
2164 reloc.bits.result = .misaligned;
19882165 elf.misaligned_reloc_count += 1;
19892166 },
19902167 }
......@@ -1995,21 +2172,21 @@ const SymbolReloc = struct {
19952172 const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..];
19962173
19972174 const addend: u64 = @bitCast(reloc.addend);
1998 const target_val: u64 = type: switch (reloc.type.target) {
1999 .abs => reloc.target.value(elf) +% addend,
2000 .rel => reloc.target.value(elf) +% addend -% dest_vaddr,
2175 const target_val: u64 = type: switch (reloc.bits.type.target) {
2176 .abs => reloc.target_symbol.value(elf) +% addend,
2177 .rel => reloc.target_symbol.value(elf) +% addend -% dest_vaddr,
20012178 .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;
20032180 break :type plt_entry_addr +% addend;
20042181 },
20052182 .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;
20072184 break :type plt_entry_addr +% addend -% dest_vaddr;
20082185 },
2009 .dtpoff => reloc.target.value(elf) +% addend,
2186 .dtpoff => reloc.target_symbol.value(elf) +% addend,
20102187 .tpoff => switch (elf.targetTlsVariant()) {
2011 .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend,
2012 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend,
2188 .I_original => |tls| tls.tcb_size +% reloc.target_symbol.value(elf) +% addend,
2189 .I_modified => |tls| 0 -% tls.tp_off +% reloc.target_symbol.value(elf) +% addend,
20132190 .II => {
20142191 const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment;
20152192 const tls_size: u64 = switch (elf.phdrSlice()) {
......@@ -2018,13 +2195,57 @@ const SymbolReloc = struct {
20182195 break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz);
20192196 },
20202197 };
2021 break :type reloc.target.value(elf) +% addend -% tls_size;
2198 break :type reloc.target_symbol.value(elf) +% addend -% tls_size;
20222199 },
20232200 },
2024 .size => reloc.target.size(elf),
2025 .special => return reloc.type.action.special.applyInner(
2201 .size => reloc.target_symbol.size(elf),
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(
20262247 elf,
2027 reloc.target,
2248 reloc.target_symbol,
20282249 reloc.addend,
20292250 dest_vaddr,
20302251 dest_slice,
......@@ -2033,7 +2254,7 @@ const SymbolReloc = struct {
20332254
20342255 // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast
20352256 // 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)) {
20372258 .static => unreachable,
20382259 .dynamic => {
20392260 // The relocation happens at runtime; we just need to update its offset.
......@@ -2046,31 +2267,34 @@ const SymbolReloc = struct {
20462267 // destination slice, we actually want to write it to the runtime relocation entry.
20472268 switch (elf.identClass()) {
20482269 .NONE, _ => unreachable,
2049 .@"32" => assert(reloc.type.action.simple.dest == .@"32"),
2050 .@"64" => assert(reloc.type.action.simple.dest == .@"64"),
2270 .@"32" => assert(reloc.bits.type.action.simple.dest == .@"32"),
2271 .@"64" => assert(reloc.bits.type.action.simple.dest == .@"64"),
20512272 }
2052 assert(reloc.type.action.simple.cast == .unsigned);
2053 assert(reloc.type.action.simple.shift == .@"0");
2273 assert(reloc.bits.type.action.simple.cast == .unsigned);
2274 assert(reloc.bits.type.action.simple.shift == .@"0");
20542275 elf.shndx.rela_dyn.relaSetOffset(elf, rela_index, dest_vaddr);
20552276 elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val);
20562277 return;
20572278 },
20582279 };
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());
20612282 }
20622283
20632284 fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void {
20642285 assert(index.get(elf) == reloc);
20652286
20662287 reloc.deleteOutputRel(elf);
2067 if (reloc.type.dependsOnTlsSize(elf)) {
2288 if (reloc.bits.type.dependsOnTlsSize(elf)) {
20682289 assert(elf.tls_size_symbol_relocs.swapRemove(index));
20692290 }
2291 if (reloc.bits.type.dependsOnGotAddress()) {
2292 assert(elf.got_relocs.swapRemove(index));
2293 }
20702294
20712295 switch (reloc.prev) {
20722296 .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;
20742298 assert(first_target_reloc.* == index);
20752299 first_target_reloc.* = reloc.next;
20762300 },
......@@ -2080,7 +2304,7 @@ const SymbolReloc = struct {
20802304 .none => {},
20812305 else => |next| next.get(elf).prev = reloc.prev,
20822306 }
2083 switch (reloc.result) {
2307 switch (reloc.bits.result) {
20842308 .ok => {},
20852309 .overflowed => elf.overflowed_reloc_count -= 1,
20862310 .misaligned => elf.misaligned_reloc_count -= 1,
......@@ -2113,25 +2337,25 @@ const SymbolReloc = struct {
21132337 const reloc_node = reloc.node.unwrap().?; // deleted
21142338
21152339 // Delete any current output relocation or error.
2116 switch (reloc.result) {
2340 switch (reloc.bits.result) {
21172341 .ok, .overflowed, .misaligned => {
21182342 reloc.deleteOutputRel(elf);
21192343 },
21202344 .illegal_dynamic_type => {
21212345 elf.illegal_dynamic_type_reloc_count -= 1;
2122 reloc.result = .ok;
2346 reloc.bits.result = .ok;
21232347 },
21242348 .illegal_dynamic_section => {
21252349 elf.illegal_dynamic_section_reloc_count -= 1;
2126 reloc.result = .ok;
2350 reloc.bits.result = .ok;
21272351 },
21282352 }
21292353
21302354 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()) {
21352359 .local => {},
21362360 .global => |gsi| switch (symbol_class) {
21372361 .static => gsi.ptr(elf).status.any_static_target_relocs = true,
......@@ -2152,25 +2376,36 @@ const SymbolReloc = struct {
21522376 } = switch (symbol_class) {
21532377 .static => return,
21542378
2155 .static_relative => switch (reloc.type.target) {
2379 .static_relative => switch (reloc.bits.type.target) {
21562380 // We need a runtime relocation if the relocation depends on our load address, which
21572381 // is the case iff the relocation resolves to the absolute value of a symbol. Relocs
21582382 // which are PC-relative, or which resolve to something other than a symbol address
21592383 // (e.g. a symbol's size), are fine.
21602384
21612385 .pltrel,
2386 .gotrel_symbol,
2387 .gotoff_symbol,
2388 .gotrel_tpoff,
2389 .gotoff_tpoff,
2390 .gotrel_tlsgd,
2391 .gotoff_tlsgd,
21622392 .rel,
21632393 .size,
21642394 .dtpoff,
21652395 .tpoff,
21662396 => 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)) {
21692404 true => .relative,
21702405 false => .illegal,
21712406 },
21722407
2173 .special => switch (reloc.type.action.special) {
2408 .special => switch (reloc.bits.type.action.special) {
21742409 .larch_pcala_hi20,
21752410 .larch_pcala64_lo20,
21762411 .larch_pcala64_hi12,
......@@ -2180,6 +2415,11 @@ const SymbolReloc = struct {
21802415 .sparc_wdisp10,
21812416 .sparc_wdisp16,
21822417 .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,
21832423 => return,
21842424
21852425 .sparc_olo10,
......@@ -2188,44 +2428,60 @@ const SymbolReloc = struct {
21882428 },
21892429 },
21902430
2191 .dynamic => switch (reloc.type.target) {
2192 // PLT relocations targeting dynamic symbols actually target that symbol's PLT
2193 // entry, so we should emit an `R_*_RELATIVE` relocation instead.
2194 .pltabs => switch (reloc.type.action.simple.dest.isAddr(elf)) {
2431 .dynamic => switch (reloc.bits.type.target) {
2432 // PLT/GOT relocations targeting dynamic symbols actually target that symbol's PLT
2433 // or GOT entry, so we should emit an `R_*_RELATIVE` relocation instead.
2434 .pltabs,
2435 .gotabs_symbol,
2436 .gotabs_tpoff,
2437 .gotabs_tlsgd,
2438 => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
21952439 true => .relative,
21962440 false => .illegal,
21972441 },
2198 // ...although PC-relative PLT relocations don't even need that that!
2199 .pltrel => return,
2442 // ...although PC-relative PLT/GOT relocations don't even need that that!
2443 .pltrel,
2444 .gotrel_symbol,
2445 .gotoff_symbol,
2446 .gotrel_tpoff,
2447 .gotoff_tpoff,
2448 .gotrel_tlsgd,
2449 .gotoff_tlsgd,
2450 => return,
22002451 // PC-relative relocations are not valid dynamic relocations.
22012452 .rel => .illegal,
22022453 // 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) {
22042455 .@"32" => .size32,
22052456 .@"64" => .size64,
22062457 else => .illegal,
22072458 },
22082459 // Absolute addresses and TLS offsets can be lowered at runtime provided they
22092460 // are address-sized.
2210 .dtpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) {
2461 .dtpoff => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
22112462 true => .dtp_off,
22122463 false => .illegal,
22132464 },
2214 .tpoff => switch (reloc.type.action.simple.dest.isAddr(elf)) {
2465 .tpoff => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
22152466 true => .tp_off,
22162467 false => .illegal,
22172468 },
2218 .abs => switch (reloc.type.action.simple.dest.isAddr(elf)) {
2469 .abs => switch (reloc.bits.type.action.simple.dest.isAddr(elf)) {
22192470 true => .abs_addr,
22202471 false => .illegal,
22212472 },
22222473
2223 .special => switch (reloc.type.action.special) {
2474 .special => switch (reloc.bits.type.action.special) {
22242475 .larch_b21,
22252476 .larch_b26,
22262477 .larch_call36,
22272478 .sparc_wdisp10,
22282479 .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,
22292485 => return,
22302486
22312487 .larch_pcala_hi20,
......@@ -2255,7 +2511,7 @@ const SymbolReloc = struct {
22552511 .abs_addr,
22562512 .dtp_off,
22572513 .tp_off,
2258 => switch (reloc.target.unwrap()) {
2514 => switch (reloc.target_symbol.unwrap()) {
22592515 .local => true,
22602516 .global => |gsi| gsi.resolveAlias(elf).defined(elf),
22612517 },
......@@ -2267,7 +2523,7 @@ const SymbolReloc = struct {
22672523 };
22682524 if (!allow) {
22692525 // ...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;
22712527 elf.illegal_dynamic_section_reloc_count += 1;
22722528 }
22732529 return;
......@@ -2278,7 +2534,7 @@ const SymbolReloc = struct {
22782534
22792535 const rel_type: MachineRelocType = rel: switch (want_dynamic_reloc) {
22802536 .illegal => {
2281 reloc.result = .illegal_dynamic_type;
2537 reloc.bits.result = .illegal_dynamic_type;
22822538 elf.illegal_dynamic_type_reloc_count += 1;
22832539 return;
22842540 },
......@@ -2292,7 +2548,7 @@ const SymbolReloc = struct {
22922548 const target_dynsym: u32 = switch (want_dynamic_reloc) {
22932549 .illegal => unreachable, // handled above
22942550 .relative => 0,
2295 else => reloc.target.unwrap().global.dynsymIndex(elf).?,
2551 else => reloc.target_symbol.unwrap().global.dynsymIndex(elf).?,
22962552 };
22972553
22982554 try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, 1);
......@@ -2435,227 +2691,20 @@ const GotKey = union(enum) {
24352691 /// Value is the signed offset of the given symbol from the TLS pointer.
24362692 tpoff: Symbol.Id,
24372693
2438 /// Value is the TLS module ID of the DSO we are creating.
2439 ///
2440 /// Used for the first of the two GOT entries generated by a TLSLD relocation.
2441 tlsld0,
2442 /// Value is always 0.
2694 /// Value is the TLS module ID for the given STT_TLS symbol. Alternatively, it may be set to
2695 /// `Symbol.Id.null` to resolve to the TLS module ID of this module (for TLSLD relocations).
24432696 ///
2444 /// Used for the second of the two GOT entries generated by a TLSLD relocation.
2445 tlsld1,
2446
2447 /// Value is the TLS module ID for the given STT_TLS symbol.
2697 /// Alternative
24482698 ///
24492699 /// Used for the first of the two GOT entries generated by a TLSGD relocation.
24502700 tlsgd0: Symbol.Id,
24512701 /// 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).
24522703 ///
24532704 /// Used for the second of the two GOT entries generated by a TLSGD relocation.
24542705 tlsgd1: Symbol.Id,
24552706};
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
26592708/// Records all global symbols defined in any DSO we depend on. For each symbol, its name, version,
26602709/// type, size, and alignment are all stored, as well as the soname of the DSO defining it. If one
26612710/// of these symbols ends up being referenced by the ELF module we are producing, we need this
......@@ -3000,6 +3049,8 @@ const AddLocalSymbolOptions = struct {
30003049fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalIndex {
30013050 const gpa = elf.base.comp.gpa;
30023051
3052 assert(opts.shndx != .UNDEF);
3053
30033054 try elf.symtab.ensureUnusedCapacity(gpa, 1);
30043055 try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1);
30053056 try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) {
......@@ -4293,7 +4344,7 @@ const Symbol = struct {
42934344 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;
42944345 while (ri != .none) {
42954346 const reloc = ri.get(elf);
4296 assert(reloc.target == sym_id);
4347 assert(reloc.target_symbol == sym_id);
42974348 try reloc.updateDynamicReloc(elf);
42984349 ri = reloc.next;
42994350 }
......@@ -4470,7 +4521,7 @@ const Symbol = struct {
44704521 var ri = sym_id.index(elf).ptr(elf).first_target_reloc;
44714522 while (ri != .none) {
44724523 const reloc = ri.get(elf);
4473 assert(reloc.target == sym_id);
4524 assert(reloc.target_symbol == sym_id);
44744525 reloc.apply(elf);
44754526 ri = reloc.next;
44764527 }
......@@ -4563,7 +4614,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum {
45634614
45644615 const shndx: Section.Index = switch (resolved_sym.unwrap()) {
45654616 .local => shndx: {
4566 assert(symtab_shndx != .UNDEF);
4617 assert(sym == Symbol.Id.null or symtab_shndx != .UNDEF);
45674618 assert(visibility == .DEFAULT);
45684619 break :shndx symtab_shndx;
45694620 },
......@@ -4683,7 +4734,6 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol
46834734 .shndx = shndx,
46844735 }),
46854736 .first_symbol_reloc = .none,
4686 .first_got_reloc = .none,
46874737 };
46884738 elf.base.comp.link_prog_node.increaseEstimatedTotalItems(1);
46894739 }
......@@ -6787,7 +6837,6 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
67876837 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
67886838 first_node_reloc: ?*NodeReloc.Index = null,
67896839 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
6790 first_got_reloc: ?*GotReloc.Index = null,
67916840 } = switch (elf.getNode(ni)) {
67926841 .deleted,
67936842 .archive,
......@@ -6814,18 +6863,15 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void {
68146863 => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported)
68156864 .input_section => |isi| .{
68166865 .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,
68186866 },
68196867 .nav => |nmi| .{
68206868 .first_symbol_reloc = &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc,
6821 .first_got_reloc = &elf.navs.values()[@backingInt(nmi)].first_got_reloc,
68226869 },
68236870 .uav => |umi| .{
68246871 .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc,
68256872 },
68266873 inline .lazy_code, .lazy_const_data => |lmi| .{
68276874 .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,
68296875 },
68306876 .unit_debug_info_header => |ui| .{
68316877 .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 {
68936939 }
68946940 ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len));
68956941 }
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 }
69096942}
69106943
69116944/// Given that `node` has moved, updates all relocations in `node` as needed. In relocatables, this
......@@ -6918,7 +6951,6 @@ fn flushMovedNodeRelocs(
69186951 skip_symbol_relocs: MappedFile.Node.Index.Optional = .none,
69196952 first_node_reloc: NodeReloc.Index = .none,
69206953 skip_node_relocs: MappedFile.Node.Index.Optional = .none,
6921 first_got_reloc: GotReloc.Index = .none,
69226954 },
69236955) void {
69246956 if (opts.first_symbol_reloc != .none) {
......@@ -6942,16 +6974,6 @@ fn flushMovedNodeRelocs(
69426974 reloc.apply(elf);
69436975 }
69446976 }
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 }
69556977}
69566978
69576979fn identClass(elf: *const Elf) std.elf.CLASS {
......@@ -7496,7 +7518,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node
74967518 .shndx = shndx,
74977519 }),
74987520 .first_symbol_reloc = .none,
7499 .first_got_reloc = .none,
75007521 };
75017522 }
75027523 return nmi;
......@@ -8064,7 +8085,6 @@ fn loadObject(
80648085 .vaddr = 0,
80658086 .node = ni,
80668087 .first_symbol_reloc = .none,
8067 .first_got_reloc = .none,
80688088 };
80698089 elf.input_prog_node.increaseEstimatedTotalItems(1);
80708090 }
......@@ -9422,7 +9442,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
94229442 const gpa = elf.base.comp.gpa;
94239443 try elf.symbol_relocs.ensureUnusedCapacity(gpa, len);
94249444 try elf.node_relocs.ensureUnusedCapacity(gpa, len);
9425 try elf.got_relocs.ensureUnusedCapacity(gpa, len);
94269445 const class = elf.identClass();
94279446 switch (elf.ehdrType()) {
94289447 .REL => {
......@@ -9460,7 +9479,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize)
94609479 try shndx.get(elf).rela.shndx.relaEnsureAdditionalCapacity(elf, len);
94619480 },
94629481 .EXEC, .DYN => {
9463 try elf.tls_size_symbol_relocs.ensureUnusedCapacity(gpa, len);
94649482 const new_got_entries = len * 2; // at worst, every reloc is a new TLSGD
94659483 try elf.got.ensureUnusedCapacity(gpa, new_got_entries);
94669484 const need_got_size = switch (class) {
......@@ -9506,13 +9524,12 @@ fn addRelocAssumeCapacity(
95069524 elf.symbol_relocs.appendAssumeCapacity(.{
95079525 .node = node.toOptional(),
95089526 .offset = offset,
9509 .type = undefined,
9510 .target = target,
9527 .bits = undefined,
9528 .target_symbol = target,
95119529 .addend = .{ .normal = addend },
95129530 .next = next,
95139531 .prev = .none,
95149532 .rela_index = rela_index.toOptional(),
9515 .result = .ok,
95169533 });
95179534 ri.get(elf).apply(elf);
95189535 },
......@@ -9567,14 +9584,14 @@ fn addRelocAssumeCapacity(
95679584 .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),
95689585 .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" })),
9571 .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala_hi20)),
9572 .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala64_lo20)),
9573 .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.larch_pcala64_hi12)),
9574 .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .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" })),
9576 .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.abs, .{ .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" })),
9587 .GOT_PC_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),
9588 .GOT_PC_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala_hi20)),
9589 .GOT64_PC_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala64_lo20)),
9590 .GOT64_PC_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.larch_got_pcala64_hi12)),
9591 .GOT_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .trunc, .shift = .@"0" })),
9592 .GOT_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"12" })),
9593 .GOT64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })),
9594 .GOT64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotabs_symbol, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })),
95789595 // zig fmt: on
95799596 },
95809597 .PPC64 => switch (@"type".PPC64) {
......@@ -9678,13 +9695,13 @@ fn addRelocAssumeCapacity(
96789695 .TLS_DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),
96799696 .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" })),
9682 .GOT22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9683 .GOTDATA_OP_LOX10 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.sparc_op_lox10)),
9684 .GOTDATA_OP_HIX22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .special(.sparc_op_hix22)),
9685 .TLS_GD_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .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" })),
9687 .TLS_IE_HI22 => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .simple(.offset, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9698 .GOT13 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32[12:0]", .cast = .unsigned, .shift = .@"0" })),
9699 .GOT22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
9700 .GOTDATA_OP_LOX10 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.sparc_got_op_lox10)),
9701 .GOTDATA_OP_HIX22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .special(.sparc_got_op_hix22)),
9702 .TLS_GD_HI22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tlsgd, .{ .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" })),
9704 .TLS_IE_HI22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_tpoff, .{ .dest = .@"32[21:0]", .cast = .trunc, .shift = .@"10" })),
96889705 // zig fmt: on
96899706
96909707 .TLS_GD_CALL, .TLS_LDM_CALL => {
......@@ -9750,19 +9767,19 @@ fn addRelocAssumeCapacity(
97509767 },
97519768 .GOT10 => {
97529769 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" }));
97549771 },
97559772 .TLS_GD_LO10 => {
97569773 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" }));
97589775 },
97599776 .TLS_LDM_LO10 => {
97609777 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" }));
97629779 },
97639780 .TLS_IE_LO10 => {
97649781 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" }));
97669783 },
97679784 },
97689785 .X86_64 => rel_type: switch (@"type".X86_64) {
......@@ -9790,12 +9807,7 @@ fn addRelocAssumeCapacity(
97909807 .GOTOFF64 => return error.UnimplementedRelocation, // offset of symbol from GOT base
97919808 .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`
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.
9810 // TODO: figure out how to do relaxations
97999811
98009812 // Relaxable versions of other relocations. Since we don't yet implement relaxation,
98019813 // just use the handling for the non-relaxable versions.
......@@ -9831,13 +9843,13 @@ fn addRelocAssumeCapacity(
98319843 .TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
98329844 .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" })),
9835 .GOT64 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),
9836 .GOTPCREL => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9837 .GOTPCREL64 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.rel, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),
9838 .TLSGD => elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9839 .TLSLD => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9840 .GOTTPOFF => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .simple(.rel, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9846 .GOT32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })),
9847 .GOT64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotoff_symbol, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })),
9848 .GOTPCREL => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_symbol, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9849 .GOTPCREL64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_symbol, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })),
9850 .TLSGD => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_tlsgd, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9851 .TLSLD => try elf.addSymbolRelocAssumeCapacity(node, offset, .null, addend, .simple(.gotrel_tlsgd, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
9852 .GOTTPOFF => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.gotrel_tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })),
98419853 // zig fmt: on
98429854
98439855 .GOTPC64 => {
......@@ -9872,6 +9884,8 @@ fn addSymbolRelocAssumeCapacityInner(
98729884) Error!void {
98739885 assert(elf.ehdrType() != .REL);
98749886
9887 const gpa = elf.base.comp.gpa;
9888
98759889 request_static_target: {
98769890 if (elf.shndx.dynamic == .UNDEF) break :request_static_target;
98779891 const gsi: Symbol.Global.Index = switch (target.unwrap()) {
......@@ -9894,6 +9908,15 @@ fn addSymbolRelocAssumeCapacityInner(
98949908 .dtpoff,
98959909 .tpoff,
98969910 .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,
98979920 => false,
98989921
98999922 .special => switch (@"type".action.special) {
......@@ -9908,10 +9931,15 @@ fn addSymbolRelocAssumeCapacityInner(
99089931 .larch_b21,
99099932 .larch_b26,
99109933 .larch_call36,
9934 .larch_got_pcala_hi20,
9935 .larch_got_pcala64_lo20,
9936 .larch_got_pcala64_hi12,
99119937
99129938 .sparc_le_hix22,
99139939 .sparc_wdisp10,
99149940 .sparc_wdisp16,
9941 .sparc_got_op_lox10,
9942 .sparc_got_op_hix22,
99159943 => false,
99169944 },
99179945 };
......@@ -9923,6 +9951,42 @@ fn addSymbolRelocAssumeCapacityInner(
99239951 }
99249952 }
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
99269990 const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len));
99279991 const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc;
99289992 const next = first_target_reloc.*;
......@@ -9931,16 +9995,21 @@ fn addSymbolRelocAssumeCapacityInner(
99319995 elf.symbol_relocs.appendAssumeCapacity(.{
99329996 .node = node.toOptional(),
99339997 .offset = offset,
9934 .target = target,
9998 .target_symbol = target,
99359999 .addend = addend,
9936 .type = @"type",
10000 .bits = .{
10001 .type = @"type",
10002 .result = .ok,
10003 },
993710004 .next = next,
993810005 .prev = .none,
993910006 .rela_index = .none,
9940 .result = .ok,
994110007 });
994210008 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, {});
994410013 }
994510014 try ri.get(elf).updateDynamicReloc(elf);
994610015
......@@ -10046,95 +10115,6 @@ fn addNodeRelocAssumeCapacity(
1004610115 },
1004710116 }
1004810117}
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}
1013810118fn updateGotEntry(elf: *Elf, got_index: usize) void {
1013910119 assert(elf.ehdrType() != .REL);
1014010120 const entry_value: union(enum) {
......@@ -10193,15 +10173,6 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
1019310173 .addend = 0,
1019410174 } },
1019510175 },
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 },
1020510176 .tlsgd0 => |sym| switch (elf.base.comp.config.link_mode) {
1020610177 .static => val: {
1020710178 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 {
1020910180 },
1021010181 .dynamic => .{ .reloc = .{
1021110182 .type = .dtpMod(elf),
10212 .dynsym_index = switch (elf.classifySymbolValue(sym)) {
10213 .static, .static_relative => 0,
10214 .dynamic => sym.unwrap().global.dynsymIndex(elf).?,
10183 .dynsym_index = switch (sym) {
10184 .null => 0,
10185 else => switch (elf.classifySymbolValue(sym)) {
10186 .static, .static_relative => 0,
10187 .dynamic => sym.unwrap().global.dynsymIndex(elf).?,
10188 },
1021510189 },
1021610190 .addend = 0,
1021710191 } },
1021810192 },
10219 .tlsld0 => switch (elf.base.comp.config.link_mode) {
10220 .static => val: {
10221 assert(elf.base.comp.config.output_mode == .Exe); // static libraries don't have GOTs
10222 break :val .{ .unsigned = 1 }; // TLS module ID for executable
10193 .tlsgd1 => |sym| switch (sym) {
10194 .null => .{ .unsigned = 0 },
10195 else => switch (elf.classifySymbolValue(sym)) {
10196 .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 } },
1022310203 },
10224 .dynamic => .{ .reloc = .{
10225 .type = .dtpMod(elf),
10226 .dynsym_index = 0,
10227 .addend = 0,
10228 } },
1022910204 },
10230 .tlsld1 => .{ .unsigned = 0 },
1023110205 };
1023210206
1023310207 // 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 {
1099410968 var ri = symtab_index.ptr(elf).first_target_reloc;
1099510969 while (ri != .none) {
1099610970 const reloc = ri.get(elf);
10997 assert(reloc.target == sym_id);
10971 assert(reloc.target_symbol == sym_id);
1099810972 // In relocatables, every symbol relocation has an output relocation.
1099910973 const rela_index = reloc.rela_index.unwrap().?;
1100010974 reloc.relaSection(elf).relaUpdateSym(elf, rela_index, @backingInt(symtab_index));
......@@ -11024,7 +10998,7 @@ pub fn idle(elf: *Elf) link.Error!bool {
1102410998 var ri = symtab_index.ptr(elf).first_target_reloc;
1102510999 while (ri != .none) {
1102611000 const reloc = ri.get(elf);
11027 assert(reloc.target == sym_id);
11001 assert(reloc.target_symbol == sym_id);
1102811002 // There may or may not be a runtime relocation for this symbol reloc.
1102911003 if (reloc.rela_index.unwrap()) |rela_index| {
1103011004 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
1161511589 const rela_index = opt_rela_index.unwrap() orelse continue;
1161611590 rela_dyn_shndx.relaAdjustOffset(elf, rela_index, old_addr, addr);
1161711591 }
11618 for (elf.got_relocs.items) |*reloc| {
11619 reloc.apply(elf);
11592 for (elf.got_relocs.keys()) |ri| {
11593 ri.get(elf).apply(elf);
1162011594 }
1162111595 } else if (shndx == elf.shndx.plt) {
1162211596 elf.flushMovedNodeRelocs(ni, .{
......@@ -11683,7 +11657,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1168311657
1168411658 elf.flushMovedNodeRelocs(ni, .{
1168511659 .first_symbol_reloc = isi.ptrConst(elf).first_symbol_reloc,
11686 .first_got_reloc = isi.ptrConst(elf).first_got_reloc,
1168711660 });
1168811661 },
1168911662 .copied_global => |global_name| {
......@@ -11714,7 +11687,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void
1171411687 .none,
1171511688 .uav, .lazy_code, .lazy_const_data => .none,
1171611689 },
11717 .first_got_reloc = mi.firstGotReloc(elf),
1171811690 });
1171911691 },
1172011692 .debug_shared => |ss| {
......@@ -12200,8 +12172,6 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
1220012172 switch (got_key) {
1220112173 .reserved,
1220212174 .symbol,
12203 .tlsld0,
12204 .tlsld1,
1220512175 .tlsgd0,
1220612176 .tlsgd1,
1220712177 => {