| ... | ... | @@ -208,29 +208,24 @@ navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { |
| 208 | 208 | lsi: Symbol.LocalIndex, |
| 209 | 209 | /// The start index of the contiguous sequence of symbol relocations in this NAV. |
| 210 | 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 | }), |
| 214 | 212 | uavs: std.array_hash_map.Auto(InternPool.Index, struct { |
| 215 | 213 | lsi: Symbol.LocalIndex, |
| 216 | 214 | /// The start index of the contiguous sequence of symbol relocations in this UAV. |
| 217 | 215 | first_symbol_reloc: SymbolReloc.Index, |
| 218 | | // No `first_got_reloc` field because a UAV never contains GOT relocations. |
| 219 | 216 | }), |
| 220 | 217 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 221 | 218 | map: std.array_hash_map.Auto(InternPool.Index, struct { |
| 222 | 219 | lsi: Symbol.LocalIndex, |
| 223 | 220 | /// The start index of the contiguous sequence of symbol relocations in this lazy code/data. |
| 224 | 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 | 223 | pending_index: u32, |
| 229 | 224 | }), |
| 230 | 225 | pending_uavs: std.ArrayList(Node.UavMapIndex), |
| 231 | 226 | symbol_relocs: std.ArrayList(SymbolReloc), |
| 232 | 227 | node_relocs: std.ArrayList(NodeReloc), |
| 233 | | got_relocs: std.ArrayList(GotReloc), |
| 228 | got_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void), |
| 234 | 229 | /// Set of relocations which must be re-applied if the size of the TLS segment changes. |
| 235 | 230 | tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void), |
| 236 | 231 | /// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`. |
| ... | ... | @@ -388,9 +383,6 @@ const Node = union(enum) { |
| 388 | 383 | fn firstSymbolReloc(nmi: NavMapIndex, elf: *const Elf) SymbolReloc.Index { |
| 389 | 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 | }; |
| 395 | 387 | |
| 396 | 388 | pub const UavMapIndex = enum(u32) { |
| ... | ... | @@ -407,11 +399,6 @@ const Node = union(enum) { |
| 407 | 399 | fn firstSymbolReloc(umi: UavMapIndex, elf: *const Elf) SymbolReloc.Index { |
| 408 | 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 | }; |
| 416 | 403 | |
| 417 | 404 | pub const LazyMapRef = struct { |
| ... | ... | @@ -437,9 +424,6 @@ const Node = union(enum) { |
| 437 | 424 | fn firstSymbolReloc(lmi: @This(), elf: *const Elf) SymbolReloc.Index { |
| 438 | 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 | } |
| 445 | 429 | |
| ... | ... | @@ -603,8 +587,6 @@ const InputSection = struct { |
| 603 | 587 | node: MappedFile.Node.Index, |
| 604 | 588 | /// The start index of the contiguous sequence of symbol relocations in this input section. |
| 605 | 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, |
| 608 | 590 | |
| 609 | 591 | const Index = enum(u32) { |
| 610 | 592 | _, |
| ... | ... | @@ -1387,14 +1369,29 @@ const SymbolReloc = struct { |
| 1387 | 1369 | node: MappedFile.Node.Index.Optional, |
| 1388 | 1370 | /// The offset of the relocation inside of `node`. |
| 1389 | 1371 | 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"`. |
| 1393 | 1375 | 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 | }, |
| 1398 | 1395 | /// Forms a linked list of all symbol relocations with the same `target`. This list exists so |
| 1399 | 1396 | /// that all relocations targeting a particular symbol can be re-applied if that symbol moves. |
| 1400 | 1397 | /// Doubly-linked so that relocations can be removed. |
| ... | ... | @@ -1412,13 +1409,6 @@ const SymbolReloc = struct { |
| 1412 | 1409 | /// relocation entry. The entry will be removed if we discover a definition which allows us to |
| 1413 | 1410 | /// statically resolve the relocation. |
| 1414 | 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 | | }, |
| 1422 | 1412 | |
| 1423 | 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 | 1454 | /// relocations which write multiple sequences of bits or which need to do unusual arithmetic on |
| 1465 | 1455 | /// a symbol value. The representation is simply a big enum containing all of these exceptional |
| 1466 | 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 | 1458 | /// Helper function for constructing a "simple" relocation type. This mainly exists to |
| 1469 | 1459 | /// improve readability in the relocation lowering logic in `addRelocAssumeCapacity`. |
| 1470 | 1460 | fn simple(target: Target, action: Simple) SymbolReloc.Type { |
| ... | ... | @@ -1493,7 +1483,7 @@ const SymbolReloc = struct { |
| 1493 | 1483 | /// Otherwise (for "simple" relocations), `Target` indicates the first step in computing the |
| 1494 | 1484 | /// relocation---whether we care about the target symbol's absolute address, its PC-relative |
| 1495 | 1485 | /// address, its PLT entry, etc. |
| 1496 | | const Target = enum(u3) { |
| 1486 | const Target = enum(u5) { |
| 1497 | 1487 | /// This is a "special" relocation whose specific type is in the `action.special` field. |
| 1498 | 1488 | special, |
| 1499 | 1489 | |
| ... | ... | @@ -1501,6 +1491,7 @@ const SymbolReloc = struct { |
| 1501 | 1491 | abs, |
| 1502 | 1492 | /// Offset from the relocation itself to the target symbol ("PC-relative"). |
| 1503 | 1493 | rel, |
| 1494 | |
| 1504 | 1495 | /// Address of the target symbol's PLT entry. |
| 1505 | 1496 | /// |
| 1506 | 1497 | /// If the target symbol does not have a PLT entry, equivalent to `.abs`. |
| ... | ... | @@ -1509,12 +1500,35 @@ const SymbolReloc = struct { |
| 1509 | 1500 | /// |
| 1510 | 1501 | /// If the target symbol does not have a PLT entry, equivalent to `.rel`. |
| 1511 | 1502 | pltrel, |
| 1503 | |
| 1512 | 1504 | /// Offset of the target TLS symbol from the base of this DSO's own TLS region. |
| 1513 | 1505 | dtpoff, |
| 1514 | 1506 | /// Offset of the target TLS symbol from the raw thread pointer. |
| 1515 | 1507 | tpoff, |
| 1508 | |
| 1516 | 1509 | /// Size of the target symbol. |
| 1517 | 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 | }; |
| 1519 | 1533 | |
| 1520 | 1534 | /// For a "simple" relocation, after the initial value is computed according to `Target`, a |
| ... | ... | @@ -1701,17 +1715,22 @@ const SymbolReloc = struct { |
| 1701 | 1715 | larch_b21, |
| 1702 | 1716 | larch_b26, |
| 1703 | 1717 | larch_call36, |
| 1718 | larch_got_pcala_hi20, |
| 1719 | larch_got_pcala64_lo20, |
| 1720 | larch_got_pcala64_hi12, |
| 1704 | 1721 | |
| 1705 | 1722 | sparc_olo10, |
| 1706 | 1723 | sparc_hix22, |
| 1707 | 1724 | sparc_le_hix22, |
| 1708 | 1725 | sparc_wdisp10, |
| 1709 | 1726 | sparc_wdisp16, |
| 1727 | sparc_got_op_lox10, |
| 1728 | sparc_got_op_hix22, |
| 1710 | 1729 | |
| 1711 | 1730 | fn applyInner( |
| 1712 | 1731 | s: Special, |
| 1713 | 1732 | elf: *Elf, |
| 1714 | | target: Symbol.Id, |
| 1733 | target_sym: Symbol.Id, |
| 1715 | 1734 | addend: SymbolReloc.Addend, |
| 1716 | 1735 | dest_vaddr: u64, |
| 1717 | 1736 | dest_slice: []u8, |
| ... | ... | @@ -1719,7 +1738,7 @@ const SymbolReloc = struct { |
| 1719 | 1738 | const normal_addend: u64 = @bitCast(addend.normal); |
| 1720 | 1739 | switch (s) { |
| 1721 | 1740 | .larch_pcala_hi20 => { |
| 1722 | | const val = target.value(elf) +% normal_addend; |
| 1741 | const val = target_sym.value(elf) +% normal_addend; |
| 1723 | 1742 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); |
| 1724 | 1743 | elf.targetStore(inst, .{ |
| 1725 | 1744 | .b0_4 = elf.targetLoad(inst).b0_4, |
| ... | ... | @@ -1728,7 +1747,7 @@ const SymbolReloc = struct { |
| 1728 | 1747 | }); |
| 1729 | 1748 | }, |
| 1730 | 1749 | .larch_pcala64_lo20 => { |
| 1731 | | const val = target.value(elf) +% normal_addend; |
| 1750 | const val = target_sym.value(elf) +% normal_addend; |
| 1732 | 1751 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); |
| 1733 | 1752 | elf.targetStore(inst, .{ |
| 1734 | 1753 | .b0_4 = elf.targetLoad(inst).b0_4, |
| ... | ... | @@ -1737,7 +1756,7 @@ const SymbolReloc = struct { |
| 1737 | 1756 | }); |
| 1738 | 1757 | }, |
| 1739 | 1758 | .larch_pcala64_hi12 => { |
| 1740 | | const val = target.value(elf) +% normal_addend; |
| 1759 | const val = target_sym.value(elf) +% normal_addend; |
| 1741 | 1760 | const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]); |
| 1742 | 1761 | elf.targetStore(inst, .{ |
| 1743 | 1762 | .b0_9 = elf.targetLoad(inst).b0_9, |
| ... | ... | @@ -1746,7 +1765,7 @@ const SymbolReloc = struct { |
| 1746 | 1765 | }); |
| 1747 | 1766 | }, |
| 1748 | 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 | 1769 | const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr); |
| 1751 | 1770 | if ((jump_offset >> 2) << 2 != jump_offset) { |
| 1752 | 1771 | return error.RelocationMisaligned; |
| ... | ... | @@ -1806,9 +1825,43 @@ const SymbolReloc = struct { |
| 1806 | 1825 | } |
| 1807 | 1826 | }, |
| 1808 | 1827 | |
| 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 | 1862 | .sparc_olo10 => { |
| 1810 | 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 | 1865 | const simm13 = std.math.cast(i13, lo10 + addends.o) orelse return error.RelocationOverflow; |
| 1813 | 1866 | const dest_ptr: *align(1) packed struct(u32) { |
| 1814 | 1867 | simm13: u13, |
| ... | ... | @@ -1825,7 +1878,7 @@ const SymbolReloc = struct { |
| 1825 | 1878 | b22_31: u10, |
| 1826 | 1879 | } = @ptrCast(dest_slice); |
| 1827 | 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 | 1882 | .b22_31 = elf.targetLoad(dest_ptr).b22_31, |
| 1830 | 1883 | }); |
| 1831 | 1884 | }, |
| ... | ... | @@ -1842,12 +1895,12 @@ const SymbolReloc = struct { |
| 1842 | 1895 | b22_31: u10, |
| 1843 | 1896 | } = @ptrCast(dest_slice); |
| 1844 | 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 | 1899 | .b22_31 = elf.targetLoad(dest_ptr).b22_31, |
| 1847 | 1900 | }); |
| 1848 | 1901 | }, |
| 1849 | 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 | 1904 | const jump_offset: i64 = @bitCast(target_vaddr +% normal_addend -% dest_vaddr); |
| 1852 | 1905 | if ((jump_offset >> 2) << 2 != jump_offset) { |
| 1853 | 1906 | return error.RelocationMisaligned; |
| ... | ... | @@ -1897,10 +1950,120 @@ const SymbolReloc = struct { |
| 1897 | 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 | }; |
| 1903 | 1979 | |
| 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 | 2067 | fn dependsOnTlsSize(t: SymbolReloc.Type, elf: *const Elf) bool { |
| 1905 | 2068 | return switch (elf.targetTlsVariant()) { |
| 1906 | 2069 | // In TLS variant I, the executable's TLS block starts at a fixed offset from the |
| ... | ... | @@ -1917,6 +2080,15 @@ const SymbolReloc = struct { |
| 1917 | 2080 | .pltrel, |
| 1918 | 2081 | .dtpoff, |
| 1919 | 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 | 2092 | => false, |
| 1921 | 2093 | |
| 1922 | 2094 | .tpoff => true, |
| ... | ... | @@ -1931,11 +2103,16 @@ const SymbolReloc = struct { |
| 1931 | 2103 | .larch_b21, |
| 1932 | 2104 | .larch_b26, |
| 1933 | 2105 | .larch_call36, |
| 2106 | .larch_got_pcala_hi20, |
| 2107 | .larch_got_pcala64_lo20, |
| 2108 | .larch_got_pcala64_hi12, |
| 1934 | 2109 | |
| 1935 | 2110 | .sparc_olo10, |
| 1936 | 2111 | .sparc_hix22, |
| 1937 | 2112 | .sparc_wdisp10, |
| 1938 | 2113 | .sparc_wdisp16, |
| 2114 | .sparc_got_op_lox10, |
| 2115 | .sparc_got_op_hix22, |
| 1939 | 2116 | => false, |
| 1940 | 2117 | }, |
| 1941 | 2118 | }, |
| ... | ... | @@ -1954,7 +2131,7 @@ const SymbolReloc = struct { |
| 1954 | 2131 | |
| 1955 | 2132 | fn apply(reloc: *SymbolReloc, elf: *Elf) void { |
| 1956 | 2133 | 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 | 2135 | // There's no point applying the relocation now, because it will be re-applied by |
| 1959 | 2136 | // `flushMoved` at some point anyway. |
| 1960 | 2137 | return; |
| ... | ... | @@ -1966,7 +2143,7 @@ const SymbolReloc = struct { |
| 1966 | 2143 | reloc.relaSection(elf).relaSetOffset(elf, rela_index, reloc_addr); |
| 1967 | 2144 | return; |
| 1968 | 2145 | } |
| 1969 | | switch (reloc.result) { |
| 2146 | switch (reloc.bits.result) { |
| 1970 | 2147 | .ok => {}, |
| 1971 | 2148 | .overflowed => elf.overflowed_reloc_count -= 1, |
| 1972 | 2149 | .misaligned => elf.misaligned_reloc_count -= 1, |
| ... | ... | @@ -1977,14 +2154,14 @@ const SymbolReloc = struct { |
| 1977 | 2154 | } |
| 1978 | 2155 | if (reloc.applyInner(elf)) { |
| 1979 | 2156 | @branchHint(.likely); |
| 1980 | | reloc.result = .ok; |
| 2157 | reloc.bits.result = .ok; |
| 1981 | 2158 | } else |err| switch (err) { |
| 1982 | 2159 | error.RelocationOverflow => { |
| 1983 | | reloc.result = .overflowed; |
| 2160 | reloc.bits.result = .overflowed; |
| 1984 | 2161 | elf.overflowed_reloc_count += 1; |
| 1985 | 2162 | }, |
| 1986 | 2163 | error.RelocationMisaligned => { |
| 1987 | | reloc.result = .misaligned; |
| 2164 | reloc.bits.result = .misaligned; |
| 1988 | 2165 | elf.misaligned_reloc_count += 1; |
| 1989 | 2166 | }, |
| 1990 | 2167 | } |
| ... | ... | @@ -1995,21 +2172,21 @@ const SymbolReloc = struct { |
| 1995 | 2172 | const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 1996 | 2173 | |
| 1997 | 2174 | 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, |
| 2001 | 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 | 2180 | break :type plt_entry_addr +% addend; |
| 2004 | 2181 | }, |
| 2005 | 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 | 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 | 2187 | .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, |
| 2013 | 2190 | .II => { |
| 2014 | 2191 | const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment; |
| 2015 | 2192 | const tls_size: u64 = switch (elf.phdrSlice()) { |
| ... | ... | @@ -2018,13 +2195,57 @@ const SymbolReloc = struct { |
| 2018 | 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), |
| 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( |
| 2026 | 2247 | elf, |
| 2027 | | reloc.target, |
| 2248 | reloc.target_symbol, |
| 2028 | 2249 | reloc.addend, |
| 2029 | 2250 | dest_vaddr, |
| 2030 | 2251 | dest_slice, |
| ... | ... | @@ -2033,7 +2254,7 @@ const SymbolReloc = struct { |
| 2033 | 2254 | |
| 2034 | 2255 | // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast |
| 2035 | 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 | 2258 | .static => unreachable, |
| 2038 | 2259 | .dynamic => { |
| 2039 | 2260 | // The relocation happens at runtime; we just need to update its offset. |
| ... | ... | @@ -2046,31 +2267,34 @@ const SymbolReloc = struct { |
| 2046 | 2267 | // destination slice, we actually want to write it to the runtime relocation entry. |
| 2047 | 2268 | switch (elf.identClass()) { |
| 2048 | 2269 | .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"), |
| 2051 | 2272 | } |
| 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"); |
| 2054 | 2275 | elf.shndx.rela_dyn.relaSetOffset(elf, rela_index, dest_vaddr); |
| 2055 | 2276 | elf.shndx.rela_dyn.relaSetAddend(elf, rela_index, target_val); |
| 2056 | 2277 | return; |
| 2057 | 2278 | }, |
| 2058 | 2279 | }; |
| 2059 | 2280 | |
| 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 | } |
| 2062 | 2283 | |
| 2063 | 2284 | fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void { |
| 2064 | 2285 | assert(index.get(elf) == reloc); |
| 2065 | 2286 | |
| 2066 | 2287 | reloc.deleteOutputRel(elf); |
| 2067 | | if (reloc.type.dependsOnTlsSize(elf)) { |
| 2288 | if (reloc.bits.type.dependsOnTlsSize(elf)) { |
| 2068 | 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 | } |
| 2070 | 2294 | |
| 2071 | 2295 | switch (reloc.prev) { |
| 2072 | 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 | 2298 | assert(first_target_reloc.* == index); |
| 2075 | 2299 | first_target_reloc.* = reloc.next; |
| 2076 | 2300 | }, |
| ... | ... | @@ -2080,7 +2304,7 @@ const SymbolReloc = struct { |
| 2080 | 2304 | .none => {}, |
| 2081 | 2305 | else => |next| next.get(elf).prev = reloc.prev, |
| 2082 | 2306 | } |
| 2083 | | switch (reloc.result) { |
| 2307 | switch (reloc.bits.result) { |
| 2084 | 2308 | .ok => {}, |
| 2085 | 2309 | .overflowed => elf.overflowed_reloc_count -= 1, |
| 2086 | 2310 | .misaligned => elf.misaligned_reloc_count -= 1, |
| ... | ... | @@ -2113,25 +2337,25 @@ const SymbolReloc = struct { |
| 2113 | 2337 | const reloc_node = reloc.node.unwrap().?; // deleted |
| 2114 | 2338 | |
| 2115 | 2339 | // Delete any current output relocation or error. |
| 2116 | | switch (reloc.result) { |
| 2340 | switch (reloc.bits.result) { |
| 2117 | 2341 | .ok, .overflowed, .misaligned => { |
| 2118 | 2342 | reloc.deleteOutputRel(elf); |
| 2119 | 2343 | }, |
| 2120 | 2344 | .illegal_dynamic_type => { |
| 2121 | 2345 | elf.illegal_dynamic_type_reloc_count -= 1; |
| 2122 | | reloc.result = .ok; |
| 2346 | reloc.bits.result = .ok; |
| 2123 | 2347 | }, |
| 2124 | 2348 | .illegal_dynamic_section => { |
| 2125 | 2349 | elf.illegal_dynamic_section_reloc_count -= 1; |
| 2126 | | reloc.result = .ok; |
| 2350 | reloc.bits.result = .ok; |
| 2127 | 2351 | }, |
| 2128 | 2352 | } |
| 2129 | 2353 | |
| 2130 | 2354 | assert(reloc.rela_index == .none); |
| 2131 | 2355 | |
| 2132 | | const symbol_class = elf.classifySymbolValue(reloc.target); |
| 2356 | const symbol_class = elf.classifySymbolValue(reloc.target_symbol); |
| 2133 | 2357 | |
| 2134 | | switch (reloc.target.unwrap()) { |
| 2358 | switch (reloc.target_symbol.unwrap()) { |
| 2135 | 2359 | .local => {}, |
| 2136 | 2360 | .global => |gsi| switch (symbol_class) { |
| 2137 | 2361 | .static => gsi.ptr(elf).status.any_static_target_relocs = true, |
| ... | ... | @@ -2152,25 +2376,36 @@ const SymbolReloc = struct { |
| 2152 | 2376 | } = switch (symbol_class) { |
| 2153 | 2377 | .static => return, |
| 2154 | 2378 | |
| 2155 | | .static_relative => switch (reloc.type.target) { |
| 2379 | .static_relative => switch (reloc.bits.type.target) { |
| 2156 | 2380 | // We need a runtime relocation if the relocation depends on our load address, which |
| 2157 | 2381 | // is the case iff the relocation resolves to the absolute value of a symbol. Relocs |
| 2158 | 2382 | // which are PC-relative, or which resolve to something other than a symbol address |
| 2159 | 2383 | // (e.g. a symbol's size), are fine. |
| 2160 | 2384 | |
| 2161 | 2385 | .pltrel, |
| 2386 | .gotrel_symbol, |
| 2387 | .gotoff_symbol, |
| 2388 | .gotrel_tpoff, |
| 2389 | .gotoff_tpoff, |
| 2390 | .gotrel_tlsgd, |
| 2391 | .gotoff_tlsgd, |
| 2162 | 2392 | .rel, |
| 2163 | 2393 | .size, |
| 2164 | 2394 | .dtpoff, |
| 2165 | 2395 | .tpoff, |
| 2166 | 2396 | => return, |
| 2167 | 2397 | |
| 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 | 2404 | true => .relative, |
| 2170 | 2405 | false => .illegal, |
| 2171 | 2406 | }, |
| 2172 | 2407 | |
| 2173 | | .special => switch (reloc.type.action.special) { |
| 2408 | .special => switch (reloc.bits.type.action.special) { |
| 2174 | 2409 | .larch_pcala_hi20, |
| 2175 | 2410 | .larch_pcala64_lo20, |
| 2176 | 2411 | .larch_pcala64_hi12, |
| ... | ... | @@ -2180,6 +2415,11 @@ const SymbolReloc = struct { |
| 2180 | 2415 | .sparc_wdisp10, |
| 2181 | 2416 | .sparc_wdisp16, |
| 2182 | 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 | 2423 | => return, |
| 2184 | 2424 | |
| 2185 | 2425 | .sparc_olo10, |
| ... | ... | @@ -2188,44 +2428,60 @@ const SymbolReloc = struct { |
| 2188 | 2428 | }, |
| 2189 | 2429 | }, |
| 2190 | 2430 | |
| 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)) { |
| 2195 | 2439 | true => .relative, |
| 2196 | 2440 | false => .illegal, |
| 2197 | 2441 | }, |
| 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, |
| 2200 | 2451 | // PC-relative relocations are not valid dynamic relocations. |
| 2201 | 2452 | .rel => .illegal, |
| 2202 | 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 | 2455 | .@"32" => .size32, |
| 2205 | 2456 | .@"64" => .size64, |
| 2206 | 2457 | else => .illegal, |
| 2207 | 2458 | }, |
| 2208 | 2459 | // Absolute addresses and TLS offsets can be lowered at runtime provided they |
| 2209 | 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 | 2462 | true => .dtp_off, |
| 2212 | 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 | 2466 | true => .tp_off, |
| 2216 | 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 | 2470 | true => .abs_addr, |
| 2220 | 2471 | false => .illegal, |
| 2221 | 2472 | }, |
| 2222 | 2473 | |
| 2223 | | .special => switch (reloc.type.action.special) { |
| 2474 | .special => switch (reloc.bits.type.action.special) { |
| 2224 | 2475 | .larch_b21, |
| 2225 | 2476 | .larch_b26, |
| 2226 | 2477 | .larch_call36, |
| 2227 | 2478 | .sparc_wdisp10, |
| 2228 | 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 | 2485 | => return, |
| 2230 | 2486 | |
| 2231 | 2487 | .larch_pcala_hi20, |
| ... | ... | @@ -2255,7 +2511,7 @@ const SymbolReloc = struct { |
| 2255 | 2511 | .abs_addr, |
| 2256 | 2512 | .dtp_off, |
| 2257 | 2513 | .tp_off, |
| 2258 | | => switch (reloc.target.unwrap()) { |
| 2514 | => switch (reloc.target_symbol.unwrap()) { |
| 2259 | 2515 | .local => true, |
| 2260 | 2516 | .global => |gsi| gsi.resolveAlias(elf).defined(elf), |
| 2261 | 2517 | }, |
| ... | ... | @@ -2267,7 +2523,7 @@ const SymbolReloc = struct { |
| 2267 | 2523 | }; |
| 2268 | 2524 | if (!allow) { |
| 2269 | 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 | 2527 | elf.illegal_dynamic_section_reloc_count += 1; |
| 2272 | 2528 | } |
| 2273 | 2529 | return; |
| ... | ... | @@ -2278,7 +2534,7 @@ const SymbolReloc = struct { |
| 2278 | 2534 | |
| 2279 | 2535 | const rel_type: MachineRelocType = rel: switch (want_dynamic_reloc) { |
| 2280 | 2536 | .illegal => { |
| 2281 | | reloc.result = .illegal_dynamic_type; |
| 2537 | reloc.bits.result = .illegal_dynamic_type; |
| 2282 | 2538 | elf.illegal_dynamic_type_reloc_count += 1; |
| 2283 | 2539 | return; |
| 2284 | 2540 | }, |
| ... | ... | @@ -2292,7 +2548,7 @@ const SymbolReloc = struct { |
| 2292 | 2548 | const target_dynsym: u32 = switch (want_dynamic_reloc) { |
| 2293 | 2549 | .illegal => unreachable, // handled above |
| 2294 | 2550 | .relative => 0, |
| 2295 | | else => reloc.target.unwrap().global.dynsymIndex(elf).?, |
| 2551 | else => reloc.target_symbol.unwrap().global.dynsymIndex(elf).?, |
| 2296 | 2552 | }; |
| 2297 | 2553 | |
| 2298 | 2554 | try elf.shndx.rela_dyn.relaEnsureAdditionalCapacity(elf, 1); |
| ... | ... | @@ -2435,227 +2691,20 @@ const GotKey = union(enum) { |
| 2435 | 2691 | /// Value is the signed offset of the given symbol from the TLS pointer. |
| 2436 | 2692 | tpoff: Symbol.Id, |
| 2437 | 2693 | |
| 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). |
| 2443 | 2696 | /// |
| 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 |
| 2448 | 2698 | /// |
| 2449 | 2699 | /// Used for the first of the two GOT entries generated by a TLSGD relocation. |
| 2450 | 2700 | tlsgd0: Symbol.Id, |
| 2451 | 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 | 2704 | /// Used for the second of the two GOT entries generated by a TLSGD relocation. |
| 2454 | 2705 | tlsgd1: Symbol.Id, |
| 2455 | 2706 | }; |
| 2456 | 2707 | |
| 2457 | | /// A relocation targeting a particular GOT entry. |
| 2458 | | const 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 | 2708 | /// Records all global symbols defined in any DSO we depend on. For each symbol, its name, version, |
| 2660 | 2709 | /// type, size, and alignment are all stored, as well as the soname of the DSO defining it. If one |
| 2661 | 2710 | /// 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 | 3049 | fn addLocalSymbol(elf: *Elf, opts: AddLocalSymbolOptions) Error!Symbol.LocalIndex { |
| 3001 | 3050 | const gpa = elf.base.comp.gpa; |
| 3002 | 3051 | |
| 3052 | assert(opts.shndx != .UNDEF); |
| 3053 | |
| 3003 | 3054 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 3004 | 3055 | try elf.changed_symtab_index.ensureUnusedCapacity(gpa, 1); |
| 3005 | 3056 | try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) { |
| ... | ... | @@ -4293,7 +4344,7 @@ const Symbol = struct { |
| 4293 | 4344 | var ri = sym_id.index(elf).ptr(elf).first_target_reloc; |
| 4294 | 4345 | while (ri != .none) { |
| 4295 | 4346 | const reloc = ri.get(elf); |
| 4296 | | assert(reloc.target == sym_id); |
| 4347 | assert(reloc.target_symbol == sym_id); |
| 4297 | 4348 | try reloc.updateDynamicReloc(elf); |
| 4298 | 4349 | ri = reloc.next; |
| 4299 | 4350 | } |
| ... | ... | @@ -4470,7 +4521,7 @@ const Symbol = struct { |
| 4470 | 4521 | var ri = sym_id.index(elf).ptr(elf).first_target_reloc; |
| 4471 | 4522 | while (ri != .none) { |
| 4472 | 4523 | const reloc = ri.get(elf); |
| 4473 | | assert(reloc.target == sym_id); |
| 4524 | assert(reloc.target_symbol == sym_id); |
| 4474 | 4525 | reloc.apply(elf); |
| 4475 | 4526 | ri = reloc.next; |
| 4476 | 4527 | } |
| ... | ... | @@ -4563,7 +4614,7 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { |
| 4563 | 4614 | |
| 4564 | 4615 | const shndx: Section.Index = switch (resolved_sym.unwrap()) { |
| 4565 | 4616 | .local => shndx: { |
| 4566 | | assert(symtab_shndx != .UNDEF); |
| 4617 | assert(sym == Symbol.Id.null or symtab_shndx != .UNDEF); |
| 4567 | 4618 | assert(visibility == .DEFAULT); |
| 4568 | 4619 | break :shndx symtab_shndx; |
| 4569 | 4620 | }, |
| ... | ... | @@ -4683,7 +4734,6 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol |
| 4683 | 4734 | .shndx = shndx, |
| 4684 | 4735 | }), |
| 4685 | 4736 | .first_symbol_reloc = .none, |
| 4686 | | .first_got_reloc = .none, |
| 4687 | 4737 | }; |
| 4688 | 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 | 6837 | skip_symbol_relocs: MappedFile.Node.Index.Optional = .none, |
| 6788 | 6838 | first_node_reloc: ?*NodeReloc.Index = null, |
| 6789 | 6839 | skip_node_relocs: MappedFile.Node.Index.Optional = .none, |
| 6790 | | first_got_reloc: ?*GotReloc.Index = null, |
| 6791 | 6840 | } = switch (elf.getNode(ni)) { |
| 6792 | 6841 | .deleted, |
| 6793 | 6842 | .archive, |
| ... | ... | @@ -6814,18 +6863,15 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 6814 | 6863 | => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported) |
| 6815 | 6864 | .input_section => |isi| .{ |
| 6816 | 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 | 6867 | .nav => |nmi| .{ |
| 6820 | 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 | 6870 | .uav => |umi| .{ |
| 6824 | 6871 | .first_symbol_reloc = &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc, |
| 6825 | 6872 | }, |
| 6826 | 6873 | inline .lazy_code, .lazy_const_data => |lmi| .{ |
| 6827 | 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 | 6876 | .unit_debug_info_header => |ui| .{ |
| 6831 | 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 | 6939 | } |
| 6894 | 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 | } |
| 6910 | 6943 | |
| 6911 | 6944 | /// Given that `node` has moved, updates all relocations in `node` as needed. In relocatables, this |
| ... | ... | @@ -6918,7 +6951,6 @@ fn flushMovedNodeRelocs( |
| 6918 | 6951 | skip_symbol_relocs: MappedFile.Node.Index.Optional = .none, |
| 6919 | 6952 | first_node_reloc: NodeReloc.Index = .none, |
| 6920 | 6953 | skip_node_relocs: MappedFile.Node.Index.Optional = .none, |
| 6921 | | first_got_reloc: GotReloc.Index = .none, |
| 6922 | 6954 | }, |
| 6923 | 6955 | ) void { |
| 6924 | 6956 | if (opts.first_symbol_reloc != .none) { |
| ... | ... | @@ -6942,16 +6974,6 @@ fn flushMovedNodeRelocs( |
| 6942 | 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 | } |
| 6956 | 6978 | |
| 6957 | 6979 | fn 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 | 7518 | .shndx = shndx, |
| 7497 | 7519 | }), |
| 7498 | 7520 | .first_symbol_reloc = .none, |
| 7499 | | .first_got_reloc = .none, |
| 7500 | 7521 | }; |
| 7501 | 7522 | } |
| 7502 | 7523 | return nmi; |
| ... | ... | @@ -8064,7 +8085,6 @@ fn loadObject( |
| 8064 | 8085 | .vaddr = 0, |
| 8065 | 8086 | .node = ni, |
| 8066 | 8087 | .first_symbol_reloc = .none, |
| 8067 | | .first_got_reloc = .none, |
| 8068 | 8088 | }; |
| 8069 | 8089 | elf.input_prog_node.increaseEstimatedTotalItems(1); |
| 8070 | 8090 | } |
| ... | ... | @@ -9422,7 +9442,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 9422 | 9442 | const gpa = elf.base.comp.gpa; |
| 9423 | 9443 | try elf.symbol_relocs.ensureUnusedCapacity(gpa, len); |
| 9424 | 9444 | try elf.node_relocs.ensureUnusedCapacity(gpa, len); |
| 9425 | | try elf.got_relocs.ensureUnusedCapacity(gpa, len); |
| 9426 | 9445 | const class = elf.identClass(); |
| 9427 | 9446 | switch (elf.ehdrType()) { |
| 9428 | 9447 | .REL => { |
| ... | ... | @@ -9460,7 +9479,6 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 9460 | 9479 | try shndx.get(elf).rela.shndx.relaEnsureAdditionalCapacity(elf, len); |
| 9461 | 9480 | }, |
| 9462 | 9481 | .EXEC, .DYN => { |
| 9463 | | try elf.tls_size_symbol_relocs.ensureUnusedCapacity(gpa, len); |
| 9464 | 9482 | const new_got_entries = len * 2; // at worst, every reloc is a new TLSGD |
| 9465 | 9483 | try elf.got.ensureUnusedCapacity(gpa, new_got_entries); |
| 9466 | 9484 | const need_got_size = switch (class) { |
| ... | ... | @@ -9506,13 +9524,12 @@ fn addRelocAssumeCapacity( |
| 9506 | 9524 | elf.symbol_relocs.appendAssumeCapacity(.{ |
| 9507 | 9525 | .node = node.toOptional(), |
| 9508 | 9526 | .offset = offset, |
| 9509 | | .type = undefined, |
| 9510 | | .target = target, |
| 9527 | .bits = undefined, |
| 9528 | .target_symbol = target, |
| 9511 | 9529 | .addend = .{ .normal = addend }, |
| 9512 | 9530 | .next = next, |
| 9513 | 9531 | .prev = .none, |
| 9514 | 9532 | .rela_index = rela_index.toOptional(), |
| 9515 | | .result = .ok, |
| 9516 | 9533 | }); |
| 9517 | 9534 | ri.get(elf).apply(elf); |
| 9518 | 9535 | }, |
| ... | ... | @@ -9567,14 +9584,14 @@ fn addRelocAssumeCapacity( |
| 9567 | 9584 | .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[24:5]", .cast = .trunc, .shift = .@"32" })), |
| 9568 | 9585 | .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[21:10]", .cast = .unsigned, .shift = .@"52" })), |
| 9569 | 9586 | |
| 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" })), |
| 9578 | 9595 | // zig fmt: on |
| 9579 | 9596 | }, |
| 9580 | 9597 | .PPC64 => switch (@"type".PPC64) { |
| ... | ... | @@ -9678,13 +9695,13 @@ fn addRelocAssumeCapacity( |
| 9678 | 9695 | .TLS_DTPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32", .cast = .unsigned, .shift = .@"0" })), |
| 9679 | 9696 | .TLS_DTPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"64", .cast = .unsigned, .shift = .@"0" })), |
| 9680 | 9697 | |
| 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" })), |
| 9688 | 9705 | // zig fmt: on |
| 9689 | 9706 | |
| 9690 | 9707 | .TLS_GD_CALL, .TLS_LDM_CALL => { |
| ... | ... | @@ -9750,19 +9767,19 @@ fn addRelocAssumeCapacity( |
| 9750 | 9767 | }, |
| 9751 | 9768 | .GOT10 => { |
| 9752 | 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 | 9772 | .TLS_GD_LO10 => { |
| 9756 | 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 | 9776 | .TLS_LDM_LO10 => { |
| 9760 | 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 | 9780 | .TLS_IE_LO10 => { |
| 9764 | 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 | 9785 | .X86_64 => rel_type: switch (@"type".X86_64) { |
| ... | ... | @@ -9790,12 +9807,7 @@ fn addRelocAssumeCapacity( |
| 9790 | 9807 | .GOTOFF64 => return error.UnimplementedRelocation, // offset of symbol from GOT base |
| 9791 | 9808 | .PLTOFF64 => return error.UnimplementedRelocation, // offset of PLT entry from GOT base (yes, I know, the name is stupid) |
| 9792 | 9809 | |
| 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 |
| 9799 | 9811 | |
| 9800 | 9812 | // Relaxable versions of other relocations. Since we don't yet implement relaxation, |
| 9801 | 9813 | // just use the handling for the non-relaxable versions. |
| ... | ... | @@ -9831,13 +9843,13 @@ fn addRelocAssumeCapacity( |
| 9831 | 9843 | .TPOFF32 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32", .cast = .signed, .shift = .@"0" })), |
| 9832 | 9844 | .TPOFF64 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"64", .cast = .signed, .shift = .@"0" })), |
| 9833 | 9845 | |
| 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" })), |
| 9841 | 9853 | // zig fmt: on |
| 9842 | 9854 | |
| 9843 | 9855 | .GOTPC64 => { |
| ... | ... | @@ -9872,6 +9884,8 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9872 | 9884 | ) Error!void { |
| 9873 | 9885 | assert(elf.ehdrType() != .REL); |
| 9874 | 9886 | |
| 9887 | const gpa = elf.base.comp.gpa; |
| 9888 | |
| 9875 | 9889 | request_static_target: { |
| 9876 | 9890 | if (elf.shndx.dynamic == .UNDEF) break :request_static_target; |
| 9877 | 9891 | const gsi: Symbol.Global.Index = switch (target.unwrap()) { |
| ... | ... | @@ -9894,6 +9908,15 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9894 | 9908 | .dtpoff, |
| 9895 | 9909 | .tpoff, |
| 9896 | 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 | 9920 | => false, |
| 9898 | 9921 | |
| 9899 | 9922 | .special => switch (@"type".action.special) { |
| ... | ... | @@ -9908,10 +9931,15 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9908 | 9931 | .larch_b21, |
| 9909 | 9932 | .larch_b26, |
| 9910 | 9933 | .larch_call36, |
| 9934 | .larch_got_pcala_hi20, |
| 9935 | .larch_got_pcala64_lo20, |
| 9936 | .larch_got_pcala64_hi12, |
| 9911 | 9937 | |
| 9912 | 9938 | .sparc_le_hix22, |
| 9913 | 9939 | .sparc_wdisp10, |
| 9914 | 9940 | .sparc_wdisp16, |
| 9941 | .sparc_got_op_lox10, |
| 9942 | .sparc_got_op_hix22, |
| 9915 | 9943 | => false, |
| 9916 | 9944 | }, |
| 9917 | 9945 | }; |
| ... | ... | @@ -9923,6 +9951,42 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9923 | 9951 | } |
| 9924 | 9952 | } |
| 9925 | 9953 | |
| 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 | 9990 | const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 9927 | 9991 | const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc; |
| 9928 | 9992 | const next = first_target_reloc.*; |
| ... | ... | @@ -9931,16 +9995,21 @@ fn addSymbolRelocAssumeCapacityInner( |
| 9931 | 9995 | elf.symbol_relocs.appendAssumeCapacity(.{ |
| 9932 | 9996 | .node = node.toOptional(), |
| 9933 | 9997 | .offset = offset, |
| 9934 | | .target = target, |
| 9998 | .target_symbol = target, |
| 9935 | 9999 | .addend = addend, |
| 9936 | | .type = @"type", |
| 10000 | .bits = .{ |
| 10001 | .type = @"type", |
| 10002 | .result = .ok, |
| 10003 | }, |
| 9937 | 10004 | .next = next, |
| 9938 | 10005 | .prev = .none, |
| 9939 | 10006 | .rela_index = .none, |
| 9940 | | .result = .ok, |
| 9941 | 10007 | }); |
| 9942 | 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 | 10014 | try ri.get(elf).updateDynamicReloc(elf); |
| 9946 | 10015 | |
| ... | ... | @@ -10046,95 +10115,6 @@ fn addNodeRelocAssumeCapacity( |
| 10046 | 10115 | }, |
| 10047 | 10116 | } |
| 10048 | 10117 | } |
| 10049 | | fn 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 | | } |
| 10138 | 10118 | fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 10139 | 10119 | assert(elf.ehdrType() != .REL); |
| 10140 | 10120 | const entry_value: union(enum) { |
| ... | ... | @@ -10193,15 +10173,6 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 10193 | 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 | 10176 | .tlsgd0 => |sym| switch (elf.base.comp.config.link_mode) { |
| 10206 | 10177 | .static => val: { |
| 10207 | 10178 | 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 | 10180 | }, |
| 10210 | 10181 | .dynamic => .{ .reloc = .{ |
| 10211 | 10182 | .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 | }, |
| 10215 | 10189 | }, |
| 10216 | 10190 | .addend = 0, |
| 10217 | 10191 | } }, |
| 10218 | 10192 | }, |
| 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 | } }, |
| 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 | }; |
| 10232 | 10206 | |
| 10233 | 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 | 10968 | var ri = symtab_index.ptr(elf).first_target_reloc; |
| 10995 | 10969 | while (ri != .none) { |
| 10996 | 10970 | const reloc = ri.get(elf); |
| 10997 | | assert(reloc.target == sym_id); |
| 10971 | assert(reloc.target_symbol == sym_id); |
| 10998 | 10972 | // In relocatables, every symbol relocation has an output relocation. |
| 10999 | 10973 | const rela_index = reloc.rela_index.unwrap().?; |
| 11000 | 10974 | reloc.relaSection(elf).relaUpdateSym(elf, rela_index, @backingInt(symtab_index)); |
| ... | ... | @@ -11024,7 +10998,7 @@ pub fn idle(elf: *Elf) link.Error!bool { |
| 11024 | 10998 | var ri = symtab_index.ptr(elf).first_target_reloc; |
| 11025 | 10999 | while (ri != .none) { |
| 11026 | 11000 | const reloc = ri.get(elf); |
| 11027 | | assert(reloc.target == sym_id); |
| 11001 | assert(reloc.target_symbol == sym_id); |
| 11028 | 11002 | // There may or may not be a runtime relocation for this symbol reloc. |
| 11029 | 11003 | if (reloc.rela_index.unwrap()) |rela_index| { |
| 11030 | 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 | 11589 | const rela_index = opt_rela_index.unwrap() orelse continue; |
| 11616 | 11590 | rela_dyn_shndx.relaAdjustOffset(elf, rela_index, old_addr, addr); |
| 11617 | 11591 | } |
| 11618 | | for (elf.got_relocs.items) |*reloc| { |
| 11619 | | reloc.apply(elf); |
| 11592 | for (elf.got_relocs.keys()) |ri| { |
| 11593 | ri.get(elf).apply(elf); |
| 11620 | 11594 | } |
| 11621 | 11595 | } else if (shndx == elf.shndx.plt) { |
| 11622 | 11596 | elf.flushMovedNodeRelocs(ni, .{ |
| ... | ... | @@ -11683,7 +11657,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11683 | 11657 | |
| 11684 | 11658 | elf.flushMovedNodeRelocs(ni, .{ |
| 11685 | 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 | 11662 | .copied_global => |global_name| { |
| ... | ... | @@ -11714,7 +11687,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 11714 | 11687 | .none, |
| 11715 | 11688 | .uav, .lazy_code, .lazy_const_data => .none, |
| 11716 | 11689 | }, |
| 11717 | | .first_got_reloc = mi.firstGotReloc(elf), |
| 11718 | 11690 | }); |
| 11719 | 11691 | }, |
| 11720 | 11692 | .debug_shared => |ss| { |
| ... | ... | @@ -12200,8 +12172,6 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 12200 | 12172 | switch (got_key) { |
| 12201 | 12173 | .reserved, |
| 12202 | 12174 | .symbol, |
| 12203 | | .tlsld0, |
| 12204 | | .tlsld1, |
| 12205 | 12175 | .tlsgd0, |
| 12206 | 12176 | .tlsgd1, |
| 12207 | 12177 | => { |