| ... | @@ -36,6 +36,7 @@ shndx: struct { | ... | @@ -36,6 +36,7 @@ shndx: struct { |
| 36 | dynsym: Section.Index, | 36 | dynsym: Section.Index, |
| 37 | dynstr: Section.Index, | 37 | dynstr: Section.Index, |
| 38 | dynamic: Section.Index, | 38 | dynamic: Section.Index, |
| | 39 | hash: Section.Index, |
| 39 | tdata: Section.Index, | 40 | tdata: Section.Index, |
| 40 | rela_dyn: Section.Index, | 41 | rela_dyn: Section.Index, |
| 41 | rela_plt: Section.Index, | 42 | rela_plt: Section.Index, |
| ... | @@ -119,8 +120,6 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional), | ... | @@ -119,8 +120,6 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional), |
| 119 | plt: std.array_hash_map.Auto(String(.strtab), void), | 120 | plt: std.array_hash_map.Auto(String(.strtab), void), |
| 120 | /// The `.plt` section contains zero or more symbol relocations starting at this index. | 121 | /// The `.plt` section contains zero or more symbol relocations starting at this index. |
| 121 | plt_first_symbol_reloc: SymbolReloc.Index, | 122 | plt_first_symbol_reloc: SymbolReloc.Index, |
| 122 | /// The `.dynamic` section contains zero or more symbol relocations starting at this index. | | |
| 123 | dynamic_first_symbol_reloc: SymbolReloc.Index, | | |
| 124 | | 123 | |
| 125 | needed: std.array_hash_map.Auto(String(.dynstr), void), | 124 | needed: std.array_hash_map.Auto(String(.dynstr), void), |
| 126 | inputs: std.ArrayList(struct { | 125 | inputs: std.ArrayList(struct { |
| ... | @@ -136,6 +135,18 @@ inputs: std.ArrayList(struct { | ... | @@ -136,6 +135,18 @@ inputs: std.ArrayList(struct { |
| 136 | input_pending_index: u32, | 135 | input_pending_index: u32, |
| 137 | input_sections: std.ArrayList(InputSection), | 136 | input_sections: std.ArrayList(InputSection), |
| 138 | input_section_pending_index: u32, | 137 | input_section_pending_index: u32, |
| | 138 | /// SPARC has some weird relocations which involve setting some bits to fixed constant values. When |
| | 139 | /// we encounter such a relocation, we queue the action here, and apply them during `idle`. |
| | 140 | one_shot_fixups: std.ArrayList(struct { |
| | 141 | node: MappedFile.Node.Index, |
| | 142 | offset: u64, |
| | 143 | /// The syntax in these tag names matches the syntax used in `SymbolReloc.Type.Simple.dest`. |
| | 144 | action: enum { |
| | 145 | @"32[12:10] = 0b000", |
| | 146 | @"32[12:10] = 0b111", |
| | 147 | @"32[12:12] = 0b0", |
| | 148 | }, |
| | 149 | }), |
| 139 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { | 150 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { |
| 140 | lsi: Symbol.LocalIndex, | 151 | lsi: Symbol.LocalIndex, |
| 141 | /// The start index of the contiguous sequence of symbol relocations in this NAV. | 152 | /// The start index of the contiguous sequence of symbol relocations in this NAV. |
| ... | @@ -195,8 +206,6 @@ const Node = union(enum) { | ... | @@ -195,8 +206,6 @@ const Node = union(enum) { |
| 195 | shdr, | 206 | shdr, |
| 196 | segment: u32, | 207 | segment: u32, |
| 197 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. | 208 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. |
| 198 | /// | | |
| 199 | /// The section '.dynamic' may contain relocations via `elf.dynamic_first_symbol_reloc`. | | |
| 200 | section: Section.Index, | 209 | section: Section.Index, |
| 201 | /// Only valid for static libraries, represents one non-zcu archive member. | 210 | /// Only valid for static libraries, represents one non-zcu archive member. |
| 202 | input_member: InputIndex, | 211 | input_member: InputIndex, |
| ... | @@ -530,6 +539,26 @@ const Section = struct { | ... | @@ -530,6 +539,26 @@ const Section = struct { |
| 530 | } | 539 | } |
| 531 | } | 540 | } |
| 532 | | 541 | |
| | 542 | fn ensureAligned(shndx: Index, elf: *Elf, min_align: std.mem.Alignment) Error!void { |
| | 543 | switch (elf.shdrPtr(shndx)) { |
| | 544 | inline else => |shdr| { |
| | 545 | if (elf.targetLoad(&shdr.addralign) >= min_align.toByteUnits()) { |
| | 546 | return; // already aligned |
| | 547 | } |
| | 548 | elf.targetStore(&shdr.addralign, @intCast(min_align.toByteUnits())); |
| | 549 | }, |
| | 550 | } |
| | 551 | const ni = shndx.get(elf).ni; |
| | 552 | if (min_align.compare(.gt, ni.alignment(&elf.mf))) { |
| | 553 | try ni.realign(&elf.mf, elf.base.comp.gpa, min_align, .{}); |
| | 554 | } |
| | 555 | switch (elf.getNode(ni.parent(&elf.mf))) { |
| | 556 | .elf => {}, |
| | 557 | .segment => |phndx| try elf.ensureSegmentAligned(phndx, min_align), |
| | 558 | else => unreachable, |
| | 559 | } |
| | 560 | } |
| | 561 | |
| 533 | /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough | 562 | /// Asserts that `rela_shndx` is a `SHT_RELA` section and ensures that its node has enough |
| 534 | /// unused space to hold `n` additional `ElfN.Rela` entries. | 563 | /// unused space to hold `n` additional `ElfN.Rela` entries. |
| 535 | fn relaEnsureAdditionalCapacity(rela_shndx: Index, elf: *Elf, n: usize) Error!void { | 564 | fn relaEnsureAdditionalCapacity(rela_shndx: Index, elf: *Elf, n: usize) Error!void { |
| ... | @@ -634,11 +663,6 @@ const Section = struct { | ... | @@ -634,11 +663,6 @@ const Section = struct { |
| 634 | const old_size = elf.targetLoad(&shdr.size); | 663 | const old_size = elf.targetLoad(&shdr.size); |
| 635 | const new_size = old_size + ent_size; | 664 | const new_size = old_size + ent_size; |
| 636 | elf.targetStore(&shdr.size, new_size); | 665 | elf.targetStore(&shdr.size, new_size); |
| 637 | if (rela_shndx == elf.shndx.rela_dyn) { | | |
| 638 | elf.updateDynamicEntry(std.elf.DT_RELASZ, new_size); | | |
| 639 | } else if (rela_shndx == elf.shndx.rela_plt) { | | |
| 640 | elf.updateDynamicEntry(std.elf.DT_PLTRELSZ, new_size); | | |
| 641 | } | | |
| 642 | break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size))); | 666 | break :new_index @fromBackingInt(@intCast(@divExact(old_size, ent_size))); |
| 643 | }; | 667 | }; |
| 644 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( | 668 | const relas: []class.ElfN().Rela = @ptrCast(@alignCast( |
| ... | @@ -1378,7 +1402,7 @@ const SymbolReloc = struct { | ... | @@ -1378,7 +1402,7 @@ const SymbolReloc = struct { |
| 1378 | const shift: u6, const shift_exact: bool = switch (s.shift) { | 1402 | const shift: u6, const shift_exact: bool = switch (s.shift) { |
| 1379 | .@"0" => .{ 0, false }, | 1403 | .@"0" => .{ 0, false }, |
| 1380 | .@"2_exact" => .{ 2, true }, | 1404 | .@"2_exact" => .{ 2, true }, |
| 1381 | .@"10" => .{ 10, true }, | 1405 | .@"10" => .{ 10, false }, |
| 1382 | .@"12" => .{ 12, false }, | 1406 | .@"12" => .{ 12, false }, |
| 1383 | .@"22" => .{ 22, false }, | 1407 | .@"22" => .{ 22, false }, |
| 1384 | .@"32" => .{ 32, false }, | 1408 | .@"32" => .{ 32, false }, |
| ... | @@ -1760,6 +1784,170 @@ const SymbolReloc = struct { | ... | @@ -1760,6 +1784,170 @@ const SymbolReloc = struct { |
| 1760 | } | 1784 | } |
| 1761 | }; | 1785 | }; |
| 1762 | | 1786 | |
| | 1787 | fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| | 1788 | const min_buckets = max_dynsym_count / 2; |
| | 1789 | |
| | 1790 | const cur_dynsym_count: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| | 1791 | inline else => |shdr, class| @intCast(@divExact( |
| | 1792 | elf.targetLoad(&shdr.size), |
| | 1793 | @sizeOf(class.ElfN().Sym), |
| | 1794 | )), |
| | 1795 | }; |
| | 1796 | |
| | 1797 | switch (elf.targetDynsymHashInfo()) { |
| | 1798 | inline else => |info| { |
| | 1799 | { |
| | 1800 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1801 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1802 | assert(elf.targetLoad(&header.nchain) == cur_dynsym_count); |
| | 1803 | const nbucket = elf.targetLoad(&header.nbucket); |
| | 1804 | if (nbucket >= min_buckets) { |
| | 1805 | // We don't need to add any buckets, but we still need to make sure the section is large |
| | 1806 | // enough to fit `max_dynsym_count` chains. |
| | 1807 | const need_size = @sizeOf(info.Header()) + (nbucket + max_dynsym_count) * 4; |
| | 1808 | try elf.ensureNodeSize(elf.shndx.hash.get(elf).ni, need_size); |
| | 1809 | return; |
| | 1810 | } |
| | 1811 | // We need more buckets, so we'll have to rebuild the hash table. |
| | 1812 | } |
| | 1813 | |
| | 1814 | // Rebuilding the hash table is quite expensive, so to avoid doing it too often we use a large |
| | 1815 | // growth factor (* 2) for `nbucket`. |
| | 1816 | const new_nbucket = min_buckets * 2; |
| | 1817 | |
| | 1818 | { |
| | 1819 | const need_size = @sizeOf(info.Header()) + (new_nbucket + max_dynsym_count) * 4; |
| | 1820 | try elf.ensureNodeSize(elf.shndx.hash.get(elf).ni, need_size); |
| | 1821 | } |
| | 1822 | |
| | 1823 | elf.mf.nodes_lock.lock(); |
| | 1824 | defer elf.mf.nodes_lock.unlock(); |
| | 1825 | |
| | 1826 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1827 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1828 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| | 1829 | |
| | 1830 | header.* = .{ .nbucket = new_nbucket, .nchain = cur_dynsym_count }; |
| | 1831 | if (elf.targetEndian() != std.lang.Endian.native) { |
| | 1832 | std.mem.byteSwapAllFields(info.Header(), header); |
| | 1833 | } |
| | 1834 | const buckets: []info.Int() = trailing[0..@intCast(elf.targetLoad(&header.nbucket))]; |
| | 1835 | const chains: []info.Int() = trailing[@intCast(elf.targetLoad(&header.nbucket))..][0..@intCast(elf.targetLoad(&header.nchain))]; |
| | 1836 | |
| | 1837 | @memset(buckets, 0); |
| | 1838 | chains[0] = 0; |
| | 1839 | for (1..cur_dynsym_count, chains[1..]) |dynsym_index_usize, *chain| { |
| | 1840 | const dynsym_index: u32 = @intCast(dynsym_index_usize); |
| | 1841 | const sym_name: String(.dynstr) = switch (elf.dynsymPtr(dynsym_index)) { |
| | 1842 | inline else => |sym| @fromBackingInt(elf.targetLoad(&sym.name)), |
| | 1843 | }; |
| | 1844 | const b = std.elf.hash.calculate(sym_name.slice(elf)) % buckets.len; |
| | 1845 | // Make this symbol the head of that bucket, and chain to the old head. |
| | 1846 | chain.* = buckets[b]; |
| | 1847 | elf.targetStore(&buckets[b], dynsym_index); |
| | 1848 | } |
| | 1849 | }, |
| | 1850 | } |
| | 1851 | } |
| | 1852 | |
| | 1853 | fn appendDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| | 1854 | switch (elf.targetDynsymHashInfo()) { |
| | 1855 | inline else => |info| { |
| | 1856 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1857 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1858 | assert(elf.targetLoad(&header.nchain) == dynsym_index); |
| | 1859 | elf.targetStore(&header.nchain, dynsym_index + 1); |
| | 1860 | |
| | 1861 | switch (elf.shdrPtr(elf.shndx.hash)) { |
| | 1862 | inline else => |shdr| elf.targetStore(&shdr.size, elf.targetLoad(&shdr.size) + @sizeOf(info.Int())), |
| | 1863 | } |
| | 1864 | }, |
| | 1865 | } |
| | 1866 | |
| | 1867 | elf.populateDynsymHashEntry(dynsym_index); |
| | 1868 | } |
| | 1869 | fn populateDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| | 1870 | elf.mf.nodes_lock.lock(); |
| | 1871 | defer elf.mf.nodes_lock.unlock(); |
| | 1872 | |
| | 1873 | assert(dynsym_index != 0); |
| | 1874 | |
| | 1875 | switch (elf.targetDynsymHashInfo()) { |
| | 1876 | inline else => |info| { |
| | 1877 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1878 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1879 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| | 1880 | |
| | 1881 | const buckets: []info.Int() = trailing[0..@intCast(elf.targetLoad(&header.nbucket))]; |
| | 1882 | const chains: []info.Int() = trailing[@intCast(elf.targetLoad(&header.nbucket))..][0..@intCast(elf.targetLoad(&header.nchain))]; |
| | 1883 | |
| | 1884 | const sym_name: String(.dynstr) = switch (elf.dynsymPtr(dynsym_index)) { |
| | 1885 | inline else => |sym| @fromBackingInt(elf.targetLoad(&sym.name)), |
| | 1886 | }; |
| | 1887 | const b = std.elf.hash.calculate(sym_name.slice(elf)) % buckets.len; |
| | 1888 | // Make this symbol the head of that bucket, and chain to the old head. |
| | 1889 | chains[dynsym_index] = buckets[b]; |
| | 1890 | elf.targetStore(&buckets[b], dynsym_index); |
| | 1891 | }, |
| | 1892 | } |
| | 1893 | } |
| | 1894 | fn popDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| | 1895 | elf.clearDynsymHashEntry(dynsym_index); |
| | 1896 | |
| | 1897 | switch (elf.targetDynsymHashInfo()) { |
| | 1898 | inline else => |info| { |
| | 1899 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1900 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1901 | assert(elf.targetLoad(&header.nchain) == dynsym_index + 1); |
| | 1902 | elf.targetStore(&header.nchain, dynsym_index); |
| | 1903 | |
| | 1904 | switch (elf.shdrPtr(elf.shndx.hash)) { |
| | 1905 | inline else => |shdr| elf.targetStore(&shdr.size, elf.targetLoad(&shdr.size) - @sizeOf(info.Int())), |
| | 1906 | } |
| | 1907 | }, |
| | 1908 | } |
| | 1909 | } |
| | 1910 | fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| | 1911 | elf.mf.nodes_lock.lock(); |
| | 1912 | defer elf.mf.nodes_lock.unlock(); |
| | 1913 | |
| | 1914 | assert(dynsym_index != 0); |
| | 1915 | |
| | 1916 | switch (elf.targetDynsymHashInfo()) { |
| | 1917 | inline else => |info| { |
| | 1918 | const section_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 1919 | const header: *info.Header() = @ptrCast(section_slice[0..@sizeOf(info.Header())]); |
| | 1920 | const trailing: []info.Int() = @ptrCast(section_slice[@sizeOf(info.Header())..]); |
| | 1921 | |
| | 1922 | const buckets: []info.Int() = trailing[0..@intCast(elf.targetLoad(&header.nbucket))]; |
| | 1923 | const chains: []info.Int() = trailing[@intCast(elf.targetLoad(&header.nbucket))..][0..@intCast(elf.targetLoad(&header.nchain))]; |
| | 1924 | |
| | 1925 | const sym_name: String(.dynstr) = switch (elf.dynsymPtr(dynsym_index)) { |
| | 1926 | inline else => |sym| @fromBackingInt(elf.targetLoad(&sym.name)), |
| | 1927 | }; |
| | 1928 | const b = std.elf.hash.calculate(sym_name.slice(elf)) % buckets.len; |
| | 1929 | |
| | 1930 | const next_dynsym_index = elf.targetLoad(&chains[dynsym_index]); |
| | 1931 | elf.targetStore(&chains[dynsym_index], 0); |
| | 1932 | |
| | 1933 | // To remove `dynsym_index` from the singly-linked list, we need to iterate the chain to find |
| | 1934 | // and replace it. But since this is, well, a hash table, that's actually fine. |
| | 1935 | if (elf.targetLoad(&buckets[b]) == dynsym_index) { |
| | 1936 | elf.targetStore(&buckets[b], next_dynsym_index); |
| | 1937 | } else { |
| | 1938 | var cur: usize = @intCast(elf.targetLoad(&buckets[b])); |
| | 1939 | while (true) { |
| | 1940 | assert(cur != 0); // `dynsym_index` is definitely somewhere in the chain |
| | 1941 | if (elf.targetLoad(&chains[cur]) == dynsym_index) break; |
| | 1942 | cur = @intCast(elf.targetLoad(&chains[cur])); |
| | 1943 | } |
| | 1944 | // We found `dynsym_index`; replace it with `next_dynsym_index`. |
| | 1945 | elf.targetStore(&chains[cur], next_dynsym_index); |
| | 1946 | } |
| | 1947 | }, |
| | 1948 | } |
| | 1949 | } |
| | 1950 | |
| 1763 | fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void { | 1951 | fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void { |
| 1764 | const gpa = elf.base.comp.gpa; | 1952 | const gpa = elf.base.comp.gpa; |
| 1765 | | 1953 | |
| ... | @@ -1789,12 +1977,19 @@ fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe | ... | @@ -1789,12 +1977,19 @@ fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe |
| 1789 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, len); | 1977 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, len); |
| 1790 | | 1978 | |
| 1791 | if (elf.shndx.dynsym != .UNDEF) { | 1979 | if (elf.shndx.dynsym != .UNDEF) { |
| 1792 | // Ensure the `.dynsym` section's node is big enough | 1980 | const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) { |
| 1793 | const dynsym_need_size: u64 = switch (elf.shdrPtr(elf.shndx.dynsym)) { | 1981 | inline else => |shdr, class| .{ |
| 1794 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), | 1982 | elf.targetLoad(&shdr.size), |
| | 1983 | @sizeOf(class.ElfN().Sym), |
| | 1984 | }, |
| 1795 | }; | 1985 | }; |
| | 1986 | const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size)); |
| | 1987 | |
| | 1988 | const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size; |
| 1796 | try elf.ensureNodeSize(elf.shndx.dynsym.get(elf).ni, dynsym_need_size); | 1989 | try elf.ensureNodeSize(elf.shndx.dynsym.get(elf).ni, dynsym_need_size); |
| 1797 | | 1990 | |
| | 1991 | try elf.ensureDynsymHashCapacity(dynsym_cur_len + len); |
| | 1992 | |
| 1798 | try elf.ensureUnusedPltCapacity(len); | 1993 | try elf.ensureUnusedPltCapacity(len); |
| 1799 | } | 1994 | } |
| 1800 | }, | 1995 | }, |
| ... | @@ -2131,6 +2326,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{ | ... | @@ -2131,6 +2326,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{ |
| 2131 | if (elf.targetEndian() != native_endian) { | 2326 | if (elf.targetEndian() != native_endian) { |
| 2132 | std.mem.byteSwapAllFields(Sym, sym); | 2327 | std.mem.byteSwapAllFields(Sym, sym); |
| 2133 | } | 2328 | } |
| | 2329 | elf.appendDynsymHashEntry(dynsym_index); |
| 2134 | break :dynsym_index dynsym_index; | 2330 | break :dynsym_index dynsym_index; |
| 2135 | }, | 2331 | }, |
| 2136 | } | 2332 | } |
| ... | @@ -2279,8 +2475,9 @@ fn setGlobalSymbolValue( | ... | @@ -2279,8 +2475,9 @@ fn setGlobalSymbolValue( |
| 2279 | } | 2475 | } |
| 2280 | | 2476 | |
| 2281 | // If this symbol was previously undefined, relocations targeting it may have been lowered to | 2477 | // If this symbol was previously undefined, relocations targeting it may have been lowered to |
| 2282 | // runtime relocations which we have now discovered we do not need, so delete those. | 2478 | // runtime relocations which we have now discovered we do not need, so delete those. This does |
| 2283 | if (elf.shndx.dynamic != .UNDEF) { | 2479 | // not apply if the symbol is preemptible, which we check with `classifySymbolValue`. |
| | 2480 | if (elf.shndx.dynamic != .UNDEF and elf.classifySymbolValue(.global(global_name)) != .dynamic) { |
| 2284 | Symbol.Id.global(global_name).deleteDynamicTargetRelocs(elf); | 2481 | Symbol.Id.global(global_name).deleteDynamicTargetRelocs(elf); |
| 2285 | } | 2482 | } |
| 2286 | | 2483 | |
| ... | @@ -2404,6 +2601,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { | ... | @@ -2404,6 +2601,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2404 | const new_size = old_size - ent_size; | 2601 | const new_size = old_size - ent_size; |
| 2405 | const remove_dynsym_index: u32 = @intCast(@divExact(new_size, ent_size)); | 2602 | const remove_dynsym_index: u32 = @intCast(@divExact(new_size, ent_size)); |
| 2406 | | 2603 | |
| | 2604 | elf.popDynsymHashEntry(remove_dynsym_index); |
| | 2605 | |
| 2407 | const free_dynsym_index = global_ptr.dynsym_index; | 2606 | const free_dynsym_index = global_ptr.dynsym_index; |
| 2408 | global_ptr.dynsym_index = 0; | 2607 | global_ptr.dynsym_index = 0; |
| 2409 | | 2608 | |
| ... | @@ -2411,6 +2610,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { | ... | @@ -2411,6 +2610,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2411 | // The demoted global wasn't the last entry, so move whatever entry we just | 2610 | // The demoted global wasn't the last entry, so move whatever entry we just |
| 2412 | // truncated out of dynsym into its place. | 2611 | // truncated out of dynsym into its place. |
| 2413 | | 2612 | |
| | 2613 | elf.clearDynsymHashEntry(free_dynsym_index); |
| | 2614 | |
| 2414 | const src_dynsym_ptr = @field(elf.dynsymPtr(remove_dynsym_index), @tagName(class)); | 2615 | const src_dynsym_ptr = @field(elf.dynsymPtr(remove_dynsym_index), @tagName(class)); |
| 2415 | const dest_dynsym_ptr = @field(elf.dynsymPtr(free_dynsym_index), @tagName(class)); | 2616 | const dest_dynsym_ptr = @field(elf.dynsymPtr(free_dynsym_index), @tagName(class)); |
| 2416 | | 2617 | |
| ... | @@ -2423,6 +2624,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { | ... | @@ -2423,6 +2624,8 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2423 | assert(moved_global_ptr.dynsym_index == remove_dynsym_index); | 2624 | assert(moved_global_ptr.dynsym_index == remove_dynsym_index); |
| 2424 | moved_global_ptr.dynsym_index = free_dynsym_index; | 2625 | moved_global_ptr.dynsym_index = free_dynsym_index; |
| 2425 | | 2626 | |
| | 2627 | elf.populateDynsymHashEntry(free_dynsym_index); |
| | 2628 | |
| 2426 | // Since that symbol's dynsym index has changed, we'll have to update any | 2629 | // Since that symbol's dynsym index has changed, we'll have to update any |
| 2427 | // relocation entries targeting it. | 2630 | // relocation entries targeting it. |
| 2428 | elf.changed_symtab_index.putAssumeCapacity(moved_name, {}); | 2631 | elf.changed_symtab_index.putAssumeCapacity(moved_name, {}); |
| ... | @@ -3045,9 +3248,6 @@ const StringTable = struct { | ... | @@ -3045,9 +3248,6 @@ const StringTable = struct { |
| 3045 | break :size .{ old_size, new_size }; | 3248 | break :size .{ old_size, new_size }; |
| 3046 | }, | 3249 | }, |
| 3047 | }; | 3250 | }; |
| 3048 | if (shndx == elf.shndx.dynstr) { | | |
| 3049 | elf.updateDynamicEntry(std.elf.DT_STRSZ, new_size); | | |
| 3050 | } | | |
| 3051 | try elf.ensureNodeSize(ni, new_size); | 3251 | try elf.ensureNodeSize(ni, new_size); |
| 3052 | const slice = ni.slice(&elf.mf)[old_size..]; | 3252 | const slice = ni.slice(&elf.mf)[old_size..]; |
| 3053 | @memcpy(slice[0..key.len], key); | 3253 | @memcpy(slice[0..key.len], key); |
| ... | @@ -3172,6 +3372,7 @@ fn create( | ... | @@ -3172,6 +3372,7 @@ fn create( |
| 3172 | .dynsym = .UNDEF, | 3372 | .dynsym = .UNDEF, |
| 3173 | .dynstr = .UNDEF, | 3373 | .dynstr = .UNDEF, |
| 3174 | .dynamic = .UNDEF, | 3374 | .dynamic = .UNDEF, |
| | 3375 | .hash = .UNDEF, |
| 3175 | .tdata = .UNDEF, | 3376 | .tdata = .UNDEF, |
| 3176 | .rela_dyn = .UNDEF, | 3377 | .rela_dyn = .UNDEF, |
| 3177 | .rela_plt = .UNDEF, | 3378 | .rela_plt = .UNDEF, |
| ... | @@ -3202,12 +3403,12 @@ fn create( | ... | @@ -3202,12 +3403,12 @@ fn create( |
| 3202 | .got = .empty, | 3403 | .got = .empty, |
| 3203 | .plt = .empty, | 3404 | .plt = .empty, |
| 3204 | .plt_first_symbol_reloc = .none, | 3405 | .plt_first_symbol_reloc = .none, |
| 3205 | .dynamic_first_symbol_reloc = .none, | | |
| 3206 | .needed = .empty, | 3406 | .needed = .empty, |
| 3207 | .inputs = .empty, | 3407 | .inputs = .empty, |
| 3208 | .input_pending_index = 0, | 3408 | .input_pending_index = 0, |
| 3209 | .input_sections = .empty, | 3409 | .input_sections = .empty, |
| 3210 | .input_section_pending_index = 0, | 3410 | .input_section_pending_index = 0, |
| | 3411 | .one_shot_fixups = .empty, |
| 3211 | .navs = .empty, | 3412 | .navs = .empty, |
| 3212 | .uavs = .empty, | 3413 | .uavs = .empty, |
| 3213 | .lazy = comptime .initFill(.{ | 3414 | .lazy = comptime .initFill(.{ |
| ... | @@ -3257,6 +3458,7 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -3257,6 +3458,7 @@ pub fn deinit(elf: *Elf) void { |
| 3257 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); | 3458 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 3258 | elf.inputs.deinit(gpa); | 3459 | elf.inputs.deinit(gpa); |
| 3259 | elf.input_sections.deinit(gpa); | 3460 | elf.input_sections.deinit(gpa); |
| | 3461 | elf.one_shot_fixups.deinit(gpa); |
| 3260 | elf.navs.deinit(gpa); | 3462 | elf.navs.deinit(gpa); |
| 3261 | elf.uavs.deinit(gpa); | 3463 | elf.uavs.deinit(gpa); |
| 3262 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); | 3464 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| ... | @@ -3293,6 +3495,16 @@ fn initHeaders( | ... | @@ -3293,6 +3495,16 @@ fn initHeaders( |
| 3293 | .@"64" => .@"8", | 3495 | .@"64" => .@"8", |
| 3294 | }; | 3496 | }; |
| 3295 | | 3497 | |
| | 3498 | // Minimum alignment for an arbitrarily-chosen set of "large" nodes in the file (e.g. common |
| | 3499 | // sections), to allow `MappedFile` to perform operations more efficiently. The downside to |
| | 3500 | // using `elf.mf.flags.block_size` is that it causes outputs to be potentially unreproducible |
| | 3501 | // across host filesystems, so in the future we may want to set this to `.@"1"` when using a |
| | 3502 | // build mode that requires reproducibility. |
| | 3503 | // |
| | 3504 | // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it |
| | 3505 | // prevents alignment bugs from being hidden by your filesystem's block alignment. |
| | 3506 | const node_block_align: std.mem.Alignment = elf.mf.flags.block_size; |
| | 3507 | |
| 3296 | const plt: PltInfo = .fromMachine(machine); | 3508 | const plt: PltInfo = .fromMachine(machine); |
| 3297 | | 3509 | |
| 3298 | const shnum: u32 = shnum: { | 3510 | const shnum: u32 = shnum: { |
| ... | @@ -3310,6 +3522,7 @@ fn initHeaders( | ... | @@ -3310,6 +3522,7 @@ fn initHeaders( |
| 3310 | shnum += 1; // .dynamic | 3522 | shnum += 1; // .dynamic |
| 3311 | shnum += 1; // .dynstr | 3523 | shnum += 1; // .dynstr |
| 3312 | shnum += 1; // .dynsym | 3524 | shnum += 1; // .dynsym |
| | 3525 | shnum += 1; // .hash |
| 3313 | shnum += 1; // .rela.dyn | 3526 | shnum += 1; // .rela.dyn |
| 3314 | shnum += 1; // .rela.plt | 3527 | shnum += 1; // .rela.plt |
| 3315 | } | 3528 | } |
| ... | @@ -3328,6 +3541,10 @@ fn initHeaders( | ... | @@ -3328,6 +3541,10 @@ fn initHeaders( |
| 3328 | rodata: u32, | 3541 | rodata: u32, |
| 3329 | text: u32, | 3542 | text: u32, |
| 3330 | data: u32, | 3543 | data: u32, |
| | 3544 | /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write |
| | 3545 | /// directly to the PLT, we place the PLT in its own segment in order to avoid making the |
| | 3546 | /// general data segment RWX. |
| | 3547 | plt: u32, |
| 3331 | tls: u32, | 3548 | tls: u32, |
| 3332 | dynamic: u32, | 3549 | dynamic: u32, |
| 3333 | relro: u32, | 3550 | relro: u32, |
| ... | @@ -3359,6 +3576,10 @@ fn initHeaders( | ... | @@ -3359,6 +3576,10 @@ fn initHeaders( |
| 3359 | defer phnum += 1; | 3576 | defer phnum += 1; |
| 3360 | break :phndx phnum; | 3577 | break :phndx phnum; |
| 3361 | }, | 3578 | }, |
| | 3579 | .plt = if (plt.got_plt == null) phndx: { |
| | 3580 | defer phnum += 1; |
| | 3581 | break :phndx phnum; |
| | 3582 | } else undefined, |
| 3362 | .tls = if (comp.config.any_non_single_threaded) phndx: { | 3583 | .tls = if (comp.config.any_non_single_threaded) phndx: { |
| 3363 | defer phnum += 1; | 3584 | defer phnum += 1; |
| 3364 | break :phndx phnum; | 3585 | break :phndx phnum; |
| ... | @@ -3414,7 +3635,7 @@ fn initHeaders( | ... | @@ -3414,7 +3635,7 @@ fn initHeaders( |
| 3414 | | 3635 | |
| 3415 | elf.nodes.appendAssumeCapacity(.archive_header); | 3636 | elf.nodes.appendAssumeCapacity(.archive_header); |
| 3416 | elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{ | 3637 | elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{ |
| 3417 | .alignment = elf.mf.flags.block_size.max(.@"2"), | 3638 | .alignment = node_block_align.max(.@"2"), |
| 3418 | .next_moved = true, | 3639 | .next_moved = true, |
| 3419 | .bubbles_moved = false, | 3640 | .bubbles_moved = false, |
| 3420 | .enable_next_moved = true, | 3641 | .enable_next_moved = true, |
| ... | @@ -3424,9 +3645,98 @@ fn initHeaders( | ... | @@ -3424,9 +3645,98 @@ fn initHeaders( |
| 3424 | | 3645 | |
| 3425 | const entsize: struct { ph: u32, sh: u32 } = switch (class) { | 3646 | const entsize: struct { ph: u32, sh: u32 } = switch (class) { |
| 3426 | .NONE, _ => unreachable, | 3647 | .NONE, _ => unreachable, |
| 3427 | inline else => |ct_class| entsize: { | 3648 | inline else => |ct_class| .{ |
| | 3649 | .ph = @sizeOf(ct_class.ElfN().Phdr), |
| | 3650 | .sh = @sizeOf(ct_class.ElfN().Shdr), |
| | 3651 | }, |
| | 3652 | }; |
| | 3653 | |
| | 3654 | // We want to create the segment nodes *before* the ehdr, because the ehdr should go inside of |
| | 3655 | // the rodata segment. Although to my knowledge neither ELF nor any ELF-based OS strictly |
| | 3656 | // requires this, it is highly conventional and therefore sometimes relied upon. |
| | 3657 | if (@"type" != .REL) { |
| | 3658 | elf.ni.rodata = try elf.mf.addOnlyChildNode(gpa, elf.ni.elf, .{ |
| | 3659 | // Must be at least `addr_align` for `elf.ni.phdr` to be placed inside this node |
| | 3660 | .alignment = node_block_align.max(addr_align), |
| | 3661 | // This node will contain the ehdr, which must be at the start of the ELF file, so this |
| | 3662 | // node must itself be fixed. |
| | 3663 | .fixed = true, |
| | 3664 | .moved = true, |
| | 3665 | .bubbles_moved = false, |
| | 3666 | }); |
| | 3667 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata }); |
| | 3668 | elf.phdrs.items[phndx.rodata] = elf.ni.rodata; |
| | 3669 | |
| | 3670 | elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| | 3671 | .size = @as(u64, phnum) * entsize.ph, |
| | 3672 | .alignment = addr_align, // keep in sync with `elf.ni.rodata` alignment above |
| | 3673 | .moved = true, |
| | 3674 | .resized = true, |
| | 3675 | .bubbles_moved = false, |
| | 3676 | }); |
| | 3677 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr }); |
| | 3678 | elf.phdrs.items[phndx.phdr] = elf.ni.phdr; |
| | 3679 | |
| | 3680 | elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| | 3681 | .alignment = node_block_align, |
| | 3682 | .moved = true, |
| | 3683 | .bubbles_moved = false, |
| | 3684 | }); |
| | 3685 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text }); |
| | 3686 | elf.phdrs.items[phndx.text] = elf.ni.text; |
| | 3687 | |
| | 3688 | elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| | 3689 | // Must be at least `addr_align` for `elf.ni.data_rel_ro` to be placed inside this node |
| | 3690 | .alignment = node_block_align.max(addr_align), |
| | 3691 | .moved = true, |
| | 3692 | .bubbles_moved = false, |
| | 3693 | }); |
| | 3694 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data }); |
| | 3695 | elf.phdrs.items[phndx.data] = elf.ni.data; |
| | 3696 | |
| | 3697 | if (plt.got_plt == null) { |
| | 3698 | const plt_ni = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| | 3699 | .alignment = node_block_align, |
| | 3700 | .moved = true, |
| | 3701 | .bubbles_moved = false, |
| | 3702 | }); |
| | 3703 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt }); |
| | 3704 | elf.phdrs.items[phndx.plt] = plt_ni; |
| | 3705 | } |
| | 3706 | |
| | 3707 | elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ |
| | 3708 | // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one |
| | 3709 | // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above. |
| | 3710 | .alignment = node_block_align.max(addr_align), |
| | 3711 | .moved = true, |
| | 3712 | .bubbles_moved = false, |
| | 3713 | }); |
| | 3714 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro }); |
| | 3715 | elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro; |
| | 3716 | |
| | 3717 | if (comp.config.any_non_single_threaded) { |
| | 3718 | elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| | 3719 | .alignment = node_block_align, |
| | 3720 | .moved = true, |
| | 3721 | .bubbles_moved = false, |
| | 3722 | }); |
| | 3723 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls }); |
| | 3724 | elf.phdrs.items[phndx.tls] = elf.ni.tls; |
| | 3725 | } |
| | 3726 | |
| | 3727 | elf.phdrs.items[phndx.gnu_stack] = .none; |
| | 3728 | } |
| | 3729 | |
| | 3730 | switch (class) { |
| | 3731 | .NONE, _ => unreachable, |
| | 3732 | inline else => |ct_class| { |
| 3428 | const ElfN = ct_class.ElfN(); | 3733 | const ElfN = ct_class.ElfN(); |
| 3429 | elf.ni.ehdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ | 3734 | // In loadable modules, the ehdr goes in the rodata segment, as described above. |
| | 3735 | const parent_ni = switch (@"type") { |
| | 3736 | .REL => elf.ni.elf, |
| | 3737 | .DYN, .EXEC => elf.ni.rodata, |
| | 3738 | }; |
| | 3739 | elf.ni.ehdr = try elf.mf.addFirstChildNode(gpa, parent_ni, .{ |
| 3430 | .size = @sizeOf(ElfN.Ehdr), | 3740 | .size = @sizeOf(ElfN.Ehdr), |
| 3431 | .alignment = addr_align, | 3741 | .alignment = addr_align, |
| 3432 | .fixed = true, | 3742 | .fixed = true, |
| ... | @@ -3478,106 +3788,58 @@ fn initHeaders( | ... | @@ -3478,106 +3788,58 @@ fn initHeaders( |
| 3478 | ehdr.shnum = 1; // Only the null shdr initially---will be incremented by `addSection` | 3788 | ehdr.shnum = 1; // Only the null shdr initially---will be incremented by `addSection` |
| 3479 | ehdr.shstrndx = std.elf.SHN_UNDEF; | 3789 | ehdr.shstrndx = std.elf.SHN_UNDEF; |
| 3480 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | 3790 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); |
| 3481 | | | |
| 3482 | break :entsize .{ .ph = @sizeOf(ElfN.Phdr), .sh = @sizeOf(ElfN.Shdr) }; | | |
| 3483 | }, | 3791 | }, |
| 3484 | }; | 3792 | } |
| 3485 | | 3793 | |
| 3486 | elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ | 3794 | elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3487 | .size = 1 * entsize.sh, // as above, only the null shdr initially | 3795 | .size = 1 * entsize.sh, // as above, only the null shdr initially |
| 3488 | .alignment = elf.mf.flags.block_size, | 3796 | .alignment = addr_align.max(node_block_align), |
| 3489 | .moved = true, | 3797 | .moved = true, |
| 3490 | .resized = true, | 3798 | .resized = true, |
| 3491 | }); | 3799 | }); |
| 3492 | elf.nodes.appendAssumeCapacity(.shdr); | 3800 | elf.nodes.appendAssumeCapacity(.shdr); |
| 3493 | | 3801 | |
| 3494 | const page_align: std.mem.Alignment = .fromByteUnits(switch (machine) { | | |
| 3495 | .AARCH64 => 0x10000, | | |
| 3496 | .LOONGARCH => 0x4000, | | |
| 3497 | .PPC64 => 0x10000, | | |
| 3498 | .RISCV => 0x1000, | | |
| 3499 | .SPARCV9 => 0x100000, | | |
| 3500 | .X86_64 => 0x1000, | | |
| 3501 | | | |
| 3502 | //.@"68K" => 0x2000, | | |
| 3503 | //.AMDGPU => 0x10000, | | |
| 3504 | //.ARC_COMPACT2 => 0x2000, | | |
| 3505 | //.AVR => 0x1, | | |
| 3506 | //.BPF => 0x100000, | | |
| 3507 | //.MIPS => 0x10000, | | |
| 3508 | //.MSP430 => 0x4, | | |
| 3509 | //.PPC => 0x10000, | | |
| 3510 | //.QDSP6 => 0x10000, | | |
| 3511 | //.SPARC => 0x10000, | | |
| 3512 | //.SPARC32PLUS => 0x10000, | | |
| 3513 | }); | | |
| 3514 | | | |
| 3515 | var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: { | | |
| 3516 | elf.ni.rodata = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ | | |
| 3517 | .alignment = elf.mf.flags.block_size, | | |
| 3518 | .moved = true, | | |
| 3519 | .bubbles_moved = false, | | |
| 3520 | }); | | |
| 3521 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata }); | | |
| 3522 | elf.phdrs.items[phndx.rodata] = elf.ni.rodata; | | |
| 3523 | | | |
| 3524 | elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ | | |
| 3525 | .size = @as(u64, phnum) * entsize.ph, | | |
| 3526 | .alignment = addr_align, | | |
| 3527 | .moved = true, | | |
| 3528 | .resized = true, | | |
| 3529 | .bubbles_moved = false, | | |
| 3530 | }); | | |
| 3531 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr }); | | |
| 3532 | elf.phdrs.items[phndx.phdr] = elf.ni.phdr; | | |
| 3533 | | | |
| 3534 | elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ | | |
| 3535 | .alignment = elf.mf.flags.block_size, | | |
| 3536 | .moved = true, | | |
| 3537 | .bubbles_moved = false, | | |
| 3538 | }); | | |
| 3539 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text }); | | |
| 3540 | elf.phdrs.items[phndx.text] = elf.ni.text; | | |
| 3541 | | | |
| 3542 | elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ | | |
| 3543 | .alignment = elf.mf.flags.block_size, | | |
| 3544 | .moved = true, | | |
| 3545 | .bubbles_moved = false, | | |
| 3546 | }); | | |
| 3547 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data }); | | |
| 3548 | elf.phdrs.items[phndx.data] = elf.ni.data; | | |
| 3549 | | | |
| 3550 | elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ | | |
| 3551 | .alignment = elf.mf.flags.block_size, | | |
| 3552 | .moved = true, | | |
| 3553 | .bubbles_moved = false, | | |
| 3554 | }); | | |
| 3555 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro }); | | |
| 3556 | elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro; | | |
| 3557 | | | |
| 3558 | elf.phdrs.items[phndx.gnu_stack] = .none; | | |
| 3559 | | | |
| 3560 | break :ph_vaddr switch (elf.ehdrType()) { | | |
| 3561 | .REL, .DYN => 0, | | |
| 3562 | .EXEC => switch (machine) { | | |
| 3563 | .AARCH64, | | |
| 3564 | => 0x200000, | | |
| 3565 | .LOONGARCH => 0x10000, | | |
| 3566 | .PPC64 => 0x10000000, | | |
| 3567 | .RISCV => 0x10000, | | |
| 3568 | .SPARCV9 => 0x100000, | | |
| 3569 | .X86_64 => 0x200000, | | |
| 3570 | }, | | |
| 3571 | }; | | |
| 3572 | } else undefined; | | |
| 3573 | switch (class) { | 3802 | switch (class) { |
| 3574 | .NONE, _ => unreachable, | 3803 | .NONE, _ => unreachable, |
| 3575 | inline else => |ct_class| { | 3804 | inline else => |ct_class| { |
| 3576 | const ElfN = ct_class.ElfN(); | 3805 | const ElfN = ct_class.ElfN(); |
| 3577 | const target_endian = elf.targetEndian(); | 3806 | const target_endian = elf.targetEndian(); |
| 3578 | | 3807 | |
| 3579 | if (@"type" != .REL) { | 3808 | populate_phdrs: { |
| 3580 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf))); | 3809 | // Initially we will give every `PT_LOAD` segment this address. When we re-allocate |
| | 3810 | // segments in the virtual address space in `flushMoved` and `flushResized`, we will |
| | 3811 | // move some segments to higher addresses to prevent overlap. This address therefore |
| | 3812 | // becomes the image's "base address"; i.e. the first `PT_LOAD` segment will start |
| | 3813 | // at this address. The base address could eventually end up higher than this due to |
| | 3814 | // how we re-allocate the address space, but never lower. |
| | 3815 | const base_vaddr: u64 = switch (@"type") { |
| | 3816 | .REL => break :populate_phdrs, |
| | 3817 | .DYN => 0, |
| | 3818 | .EXEC => switch (machine) { |
| | 3819 | .AARCH64 => 0x200000, |
| | 3820 | .LOONGARCH => 0x10000, |
| | 3821 | .PPC64 => 0x10000000, |
| | 3822 | .RISCV => 0x10000, |
| | 3823 | .SPARCV9 => 0x100000, |
| | 3824 | .X86_64 => 0x200000, |
| | 3825 | }, |
| | 3826 | }; |
| | 3827 | |
| | 3828 | // All `PT_LOAD` segments are given this `.@"align"`. However, to avoid bloating the |
| | 3829 | // binary, their *nodes* are not aligned to this boundary---ELF only requires that |
| | 3830 | // ecah segment's address equals its file offset modulo this alignment, not that its |
| | 3831 | // file offset is actually aligned to this boundary. This property is maintained by |
| | 3832 | // the segment virtual address space allocation logic. |
| | 3833 | const page_align = elf.targetPageAlign(); |
| | 3834 | |
| | 3835 | // We will populate elements in this slice (by index). The `PT_LOAD` segments are |
| | 3836 | // actually `PT_NULL` for now, because we initialize `filesz` and `memsz` to zero. |
| | 3837 | // Any which end up non-empty will have their size populated (and their type set to |
| | 3838 | // `PT_LOAD`) by the segment virtual address space allocation logic. |
| | 3839 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast( |
| | 3840 | elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)], |
| | 3841 | )); |
| | 3842 | |
| 3581 | const ph_phdr = &phdr[phndx.phdr]; | 3843 | const ph_phdr = &phdr[phndx.phdr]; |
| 3582 | ph_phdr.* = .{ | 3844 | ph_phdr.* = .{ |
| 3583 | .type = .PHDR, | 3845 | .type = .PHDR, |
| ... | @@ -3589,7 +3851,6 @@ fn initHeaders( | ... | @@ -3589,7 +3851,6 @@ fn initHeaders( |
| 3589 | .flags = .{ .R = true }, | 3851 | .flags = .{ .R = true }, |
| 3590 | .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()), | 3852 | .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()), |
| 3591 | }; | 3853 | }; |
| 3592 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); | | |
| 3593 | | 3854 | |
| 3594 | if (maybe_interp) |_| { | 3855 | if (maybe_interp) |_| { |
| 3595 | const ph_interp = &phdr[phndx.interp]; | 3856 | const ph_interp = &phdr[phndx.interp]; |
| ... | @@ -3603,53 +3864,57 @@ fn initHeaders( | ... | @@ -3603,53 +3864,57 @@ fn initHeaders( |
| 3603 | .flags = .{ .R = true }, | 3864 | .flags = .{ .R = true }, |
| 3604 | .@"align" = 1, | 3865 | .@"align" = 1, |
| 3605 | }; | 3866 | }; |
| 3606 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); | | |
| 3607 | } | 3867 | } |
| 3608 | | 3868 | |
| 3609 | _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf); | | |
| 3610 | const ph_rodata = &phdr[phndx.rodata]; | 3869 | const ph_rodata = &phdr[phndx.rodata]; |
| 3611 | ph_rodata.* = .{ | 3870 | ph_rodata.* = .{ |
| 3612 | .type = if (rodata_size == 0) .NULL else .LOAD, | 3871 | .type = .NULL, |
| 3613 | .offset = 0, | 3872 | .offset = 0, |
| 3614 | .vaddr = ph_vaddr, | 3873 | .vaddr = @intCast(base_vaddr), |
| 3615 | .paddr = ph_vaddr, | 3874 | .paddr = @intCast(base_vaddr), |
| 3616 | .filesz = @intCast(rodata_size), | 3875 | .filesz = 0, |
| 3617 | .memsz = @intCast(rodata_size), | 3876 | .memsz = 0, |
| 3618 | .flags = .{ .R = true }, | 3877 | .flags = .{ .R = true }, |
| 3619 | .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).max(page_align).toByteUnits()), | 3878 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3620 | }; | 3879 | }; |
| 3621 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); | | |
| 3622 | ph_vaddr += @intCast(rodata_size); | | |
| 3623 | | 3880 | |
| 3624 | _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf); | | |
| 3625 | const ph_text = &phdr[phndx.text]; | 3881 | const ph_text = &phdr[phndx.text]; |
| 3626 | ph_text.* = .{ | 3882 | ph_text.* = .{ |
| 3627 | .type = if (text_size == 0) .NULL else .LOAD, | 3883 | .type = .NULL, |
| 3628 | .offset = 0, | 3884 | .offset = 0, |
| 3629 | .vaddr = ph_vaddr, | 3885 | .vaddr = @intCast(base_vaddr), |
| 3630 | .paddr = ph_vaddr, | 3886 | .paddr = @intCast(base_vaddr), |
| 3631 | .filesz = @intCast(text_size), | 3887 | .filesz = 0, |
| 3632 | .memsz = @intCast(text_size), | 3888 | .memsz = 0, |
| 3633 | .flags = .{ .R = true, .X = true }, | 3889 | .flags = .{ .R = true, .X = true }, |
| 3634 | .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).max(page_align).toByteUnits()), | 3890 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3635 | }; | 3891 | }; |
| 3636 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); | | |
| 3637 | ph_vaddr += @intCast(text_size); | | |
| 3638 | | 3892 | |
| 3639 | _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf); | | |
| 3640 | const ph_data = &phdr[phndx.data]; | 3893 | const ph_data = &phdr[phndx.data]; |
| 3641 | ph_data.* = .{ | 3894 | ph_data.* = .{ |
| 3642 | .type = if (data_size == 0) .NULL else .LOAD, | 3895 | .type = .NULL, |
| 3643 | .offset = 0, | 3896 | .offset = 0, |
| 3644 | .vaddr = ph_vaddr, | 3897 | .vaddr = @intCast(base_vaddr), |
| 3645 | .paddr = ph_vaddr, | 3898 | .paddr = @intCast(base_vaddr), |
| 3646 | .filesz = @intCast(data_size), | 3899 | .filesz = 0, |
| 3647 | .memsz = @intCast(data_size), | 3900 | .memsz = 0, |
| 3648 | .flags = .{ .R = true, .W = true }, | 3901 | .flags = .{ .R = true, .W = true }, |
| 3649 | .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).max(page_align).toByteUnits()), | 3902 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3650 | }; | 3903 | }; |
| 3651 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); | 3904 | |
| 3652 | ph_vaddr += @intCast(data_size); | 3905 | if (plt.got_plt == null) { |
| | 3906 | const ph_plt = &phdr[phndx.plt]; |
| | 3907 | ph_plt.* = .{ |
| | 3908 | .type = .NULL, |
| | 3909 | .offset = 0, |
| | 3910 | .vaddr = @intCast(base_vaddr), |
| | 3911 | .paddr = @intCast(base_vaddr), |
| | 3912 | .filesz = 0, |
| | 3913 | .memsz = 0, |
| | 3914 | .flags = .{ .R = true, .W = true, .X = true }, |
| | 3915 | .@"align" = @intCast(page_align.toByteUnits()), |
| | 3916 | }; |
| | 3917 | } |
| 3653 | | 3918 | |
| 3654 | if (comp.config.any_non_single_threaded) { | 3919 | if (comp.config.any_non_single_threaded) { |
| 3655 | const ph_tls = &phdr[phndx.tls]; | 3920 | const ph_tls = &phdr[phndx.tls]; |
| ... | @@ -3661,9 +3926,8 @@ fn initHeaders( | ... | @@ -3661,9 +3926,8 @@ fn initHeaders( |
| 3661 | .filesz = 0, | 3926 | .filesz = 0, |
| 3662 | .memsz = 0, | 3927 | .memsz = 0, |
| 3663 | .flags = .{ .R = true }, | 3928 | .flags = .{ .R = true }, |
| 3664 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), | 3929 | .@"align" = @intCast(elf.ni.tls.alignment(&elf.mf).toByteUnits()), |
| 3665 | }; | 3930 | }; |
| 3666 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); | | |
| 3667 | } | 3931 | } |
| 3668 | | 3932 | |
| 3669 | if (have_dynamic_section) { | 3933 | if (have_dynamic_section) { |
| ... | @@ -3678,7 +3942,6 @@ fn initHeaders( | ... | @@ -3678,7 +3942,6 @@ fn initHeaders( |
| 3678 | .flags = .{ .R = true, .W = true }, | 3942 | .flags = .{ .R = true, .W = true }, |
| 3679 | .@"align" = @intCast(addr_align.toByteUnits()), | 3943 | .@"align" = @intCast(addr_align.toByteUnits()), |
| 3680 | }; | 3944 | }; |
| 3681 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic); | | |
| 3682 | } | 3945 | } |
| 3683 | | 3946 | |
| 3684 | const ph_relro = &phdr[phndx.relro]; | 3947 | const ph_relro = &phdr[phndx.relro]; |
| ... | @@ -3690,9 +3953,8 @@ fn initHeaders( | ... | @@ -3690,9 +3953,8 @@ fn initHeaders( |
| 3690 | .filesz = 0, | 3953 | .filesz = 0, |
| 3691 | .memsz = 0, | 3954 | .memsz = 0, |
| 3692 | .flags = .{ .R = true }, | 3955 | .flags = .{ .R = true }, |
| 3693 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), | 3956 | .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()), |
| 3694 | }; | 3957 | }; |
| 3695 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_relro); | | |
| 3696 | | 3958 | |
| 3697 | const ph_gnu_stack = &phdr[phndx.gnu_stack]; | 3959 | const ph_gnu_stack = &phdr[phndx.gnu_stack]; |
| 3698 | ph_gnu_stack.* = .{ | 3960 | ph_gnu_stack.* = .{ |
| ... | @@ -3705,7 +3967,10 @@ fn initHeaders( | ... | @@ -3705,7 +3967,10 @@ fn initHeaders( |
| 3705 | .flags = .{ .R = true, .W = true }, | 3967 | .flags = .{ .R = true, .W = true }, |
| 3706 | .@"align" = 1, | 3968 | .@"align" = 1, |
| 3707 | }; | 3969 | }; |
| 3708 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_gnu_stack); | 3970 | |
| | 3971 | if (target_endian != std.lang.Endian.native) { |
| | 3972 | std.mem.byteSwapAllElements(ElfN.Phdr, phdr); |
| | 3973 | } |
| 3709 | } | 3974 | } |
| 3710 | | 3975 | |
| 3711 | const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); | 3976 | const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); |
| ... | @@ -3733,7 +3998,7 @@ fn initHeaders( | ... | @@ -3733,7 +3998,7 @@ fn initHeaders( |
| 3733 | .size = @sizeOf(ElfN.Sym) * 1, | 3998 | .size = @sizeOf(ElfN.Sym) * 1, |
| 3734 | .addralign = addr_align, | 3999 | .addralign = addr_align, |
| 3735 | .entsize = @sizeOf(ElfN.Sym), | 4000 | .entsize = @sizeOf(ElfN.Sym), |
| 3736 | .node_align = elf.mf.flags.block_size, | 4001 | .node_align = node_block_align, |
| 3737 | .info = 1, // index of first non-local symbol | 4002 | .info = 1, // index of first non-local symbol |
| 3738 | })); | 4003 | })); |
| 3739 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); | 4004 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); |
| ... | @@ -3755,7 +4020,7 @@ fn initHeaders( | ... | @@ -3755,7 +4020,7 @@ fn initHeaders( |
| 3755 | .type = .STRTAB, | 4020 | .type = .STRTAB, |
| 3756 | .size = 1, | 4021 | .size = 1, |
| 3757 | .entsize = 1, | 4022 | .entsize = 1, |
| 3758 | .node_align = elf.mf.flags.block_size, | 4023 | .node_align = node_block_align, |
| 3759 | })); | 4024 | })); |
| 3760 | Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0; | 4025 | Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 3761 | | 4026 | |
| ... | @@ -3767,7 +4032,7 @@ fn initHeaders( | ... | @@ -3767,7 +4032,7 @@ fn initHeaders( |
| 3767 | .type = .STRTAB, | 4032 | .type = .STRTAB, |
| 3768 | .size = 1, | 4033 | .size = 1, |
| 3769 | .entsize = 1, | 4034 | .entsize = 1, |
| 3770 | .node_align = elf.mf.flags.block_size, | 4035 | .node_align = node_block_align, |
| 3771 | })); | 4036 | })); |
| 3772 | Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0; | 4037 | Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 3773 | switch (elf.shdrPtr(.symtab)) { | 4038 | switch (elf.shdrPtr(.symtab)) { |
| ... | @@ -3777,22 +4042,22 @@ fn initHeaders( | ... | @@ -3777,22 +4042,22 @@ fn initHeaders( |
| 3777 | assert(.rodata == try elf.addSection(elf.ni.rodata, .{ | 4042 | assert(.rodata == try elf.addSection(elf.ni.rodata, .{ |
| 3778 | .name = ".rodata", | 4043 | .name = ".rodata", |
| 3779 | .flags = .{ .ALLOC = true }, | 4044 | .flags = .{ .ALLOC = true }, |
| 3780 | .addralign = elf.mf.flags.block_size, | 4045 | .node_align = node_block_align, |
| 3781 | })); | 4046 | })); |
| 3782 | assert(.text == try elf.addSection(elf.ni.text, .{ | 4047 | assert(.text == try elf.addSection(elf.ni.text, .{ |
| 3783 | .name = ".text", | 4048 | .name = ".text", |
| 3784 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 4049 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 3785 | .addralign = elf.mf.flags.block_size, | 4050 | .node_align = node_block_align, |
| 3786 | })); | 4051 | })); |
| 3787 | assert(.data == try elf.addSection(elf.ni.data, .{ | 4052 | assert(.data == try elf.addSection(elf.ni.data, .{ |
| 3788 | .name = ".data", | 4053 | .name = ".data", |
| 3789 | .flags = .{ .WRITE = true, .ALLOC = true }, | 4054 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3790 | .addralign = elf.mf.flags.block_size, | 4055 | .node_align = node_block_align, |
| 3791 | })); | 4056 | })); |
| 3792 | assert(.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{ | 4057 | assert(.data_rel_ro == try elf.addSection(elf.ni.data_rel_ro, .{ |
| 3793 | .name = ".data.rel.ro", | 4058 | .name = ".data.rel.ro", |
| 3794 | .flags = .{ .WRITE = true, .ALLOC = true }, | 4059 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3795 | .addralign = elf.mf.flags.block_size, | 4060 | .node_align = node_block_align, |
| 3796 | })); | 4061 | })); |
| 3797 | if (@"type" != .REL) { | 4062 | if (@"type" != .REL) { |
| 3798 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ | 4063 | elf.shndx.got = try elf.addSection(elf.ni.data_rel_ro, .{ |
| ... | @@ -3808,34 +4073,39 @@ fn initHeaders( | ... | @@ -3808,34 +4073,39 @@ fn initHeaders( |
| 3808 | .addralign = addr_align, | 4073 | .addralign = addr_align, |
| 3809 | .entsize = @intCast(addr_align.toByteUnits()), | 4074 | .entsize = @intCast(addr_align.toByteUnits()), |
| 3810 | }); | 4075 | }); |
| 3811 | if (plt.got_plt) |got_plt| elf.shndx.got_plt = try elf.addSection( | 4076 | if (plt.got_plt) |got_plt| { |
| 3812 | if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data, | 4077 | const got_plt_segment_ni = if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data; |
| 3813 | .{ | 4078 | elf.shndx.got_plt = try elf.addSection(got_plt_segment_ni, .{ |
| 3814 | .name = ".got.plt", | 4079 | .name = ".got.plt", |
| 3815 | .type = .PROGBITS, | 4080 | .type = .PROGBITS, |
| 3816 | .flags = .{ .WRITE = true, .ALLOC = true }, | 4081 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3817 | .size = got_plt.header_entries * elf.targetPtrSize(), | 4082 | .size = got_plt.header_entries * elf.targetPtrSize(), |
| 3818 | .addralign = addr_align, | 4083 | .addralign = addr_align, |
| 3819 | .entsize = @intCast(addr_align.toByteUnits()), | 4084 | .entsize = @intCast(addr_align.toByteUnits()), |
| 3820 | }, | 4085 | }); |
| 3821 | ); | 4086 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ |
| 3822 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ | 4087 | .name = ".plt", |
| 3823 | .name = ".plt", | 4088 | .type = .PROGBITS, |
| 3824 | .type = .PROGBITS, | 4089 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 3825 | .flags = .{ | 4090 | .size = plt.entry_size * plt.header_entries, |
| 3826 | .ALLOC = true, | 4091 | .addralign = plt.@"align", |
| 3827 | .EXECINSTR = true, | 4092 | .node_align = node_block_align, |
| 3828 | .WRITE = plt.got_plt == null, | 4093 | }); |
| 3829 | }, | 4094 | } else { |
| 3830 | .size = plt.entry_size * plt.header_entries, | 4095 | elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt], .{ |
| 3831 | .addralign = plt.@"align", | 4096 | .name = ".plt", |
| 3832 | .node_align = elf.mf.flags.block_size, | 4097 | .type = .PROGBITS, |
| 3833 | }); | 4098 | .flags = .{ .ALLOC = true, .WRITE = true, .EXECINSTR = true }, |
| | 4099 | .size = plt.entry_size * plt.header_entries, |
| | 4100 | .addralign = plt.@"align", |
| | 4101 | .node_align = node_block_align, |
| | 4102 | }); |
| | 4103 | } |
| 3834 | if (plt.plt_sec != null) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{ | 4104 | if (plt.plt_sec != null) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{ |
| 3835 | .name = ".plt.sec", | 4105 | .name = ".plt.sec", |
| 3836 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 4106 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 3837 | .addralign = plt.@"align", | 4107 | .addralign = plt.@"align", |
| 3838 | .node_align = elf.mf.flags.block_size, | 4108 | .node_align = node_block_align, |
| 3839 | }); | 4109 | }); |
| 3840 | if (maybe_interp) |interp| { | 4110 | if (maybe_interp) |interp| { |
| 3841 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ | 4111 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| ... | @@ -3858,6 +4128,7 @@ fn initHeaders( | ... | @@ -3858,6 +4128,7 @@ fn initHeaders( |
| 3858 | sec_interp[interp.len] = 0; | 4128 | sec_interp[interp.len] = 0; |
| 3859 | } | 4129 | } |
| 3860 | if (have_dynamic_section) { | 4130 | if (have_dynamic_section) { |
| | 4131 | assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align)); |
| 3861 | const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data_rel_ro, .{ | 4132 | const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data_rel_ro, .{ |
| 3862 | .alignment = addr_align, | 4133 | .alignment = addr_align, |
| 3863 | .moved = true, | 4134 | .moved = true, |
| ... | @@ -3872,7 +4143,7 @@ fn initHeaders( | ... | @@ -3872,7 +4143,7 @@ fn initHeaders( |
| 3872 | .flags = .{ .ALLOC = true }, | 4143 | .flags = .{ .ALLOC = true }, |
| 3873 | .size = 1, | 4144 | .size = 1, |
| 3874 | .entsize = 1, | 4145 | .entsize = 1, |
| 3875 | .node_align = elf.mf.flags.block_size, | 4146 | .node_align = node_block_align, |
| 3876 | }); | 4147 | }); |
| 3877 | dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0; | 4148 | dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0; |
| 3878 | elf.shndx.dynstr = dynstr_shndx; | 4149 | elf.shndx.dynstr = dynstr_shndx; |
| ... | @@ -3890,7 +4161,7 @@ fn initHeaders( | ... | @@ -3890,7 +4161,7 @@ fn initHeaders( |
| 3890 | .info = 1, | 4161 | .info = 1, |
| 3891 | .addralign = addr_align, | 4162 | .addralign = addr_align, |
| 3892 | .entsize = @sizeOf(Sym), | 4163 | .entsize = @sizeOf(Sym), |
| 3893 | .node_align = elf.mf.flags.block_size, | 4164 | .node_align = node_block_align, |
| 3894 | }); | 4165 | }); |
| 3895 | const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class)); | 4166 | const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class)); |
| 3896 | dynsym_null.* = .{ | 4167 | dynsym_null.* = .{ |
| ... | @@ -3918,7 +4189,7 @@ fn initHeaders( | ... | @@ -3918,7 +4189,7 @@ fn initHeaders( |
| 3918 | .link = elf.shndx.dynsym.toSection().?, | 4189 | .link = elf.shndx.dynsym.toSection().?, |
| 3919 | .addralign = addr_align, | 4190 | .addralign = addr_align, |
| 3920 | .entsize = rela_size, | 4191 | .entsize = rela_size, |
| 3921 | .node_align = elf.mf.flags.block_size, | 4192 | .node_align = node_block_align, |
| 3922 | }); | 4193 | }); |
| 3923 | elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{ | 4194 | elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{ |
| 3924 | .name = ".rela.plt", | 4195 | .name = ".rela.plt", |
| ... | @@ -3928,7 +4199,7 @@ fn initHeaders( | ... | @@ -3928,7 +4199,7 @@ fn initHeaders( |
| 3928 | .info = (if (plt.got_plt != null) elf.shndx.got_plt else elf.shndx.plt).toSection().?, | 4199 | .info = (if (plt.got_plt != null) elf.shndx.got_plt else elf.shndx.plt).toSection().?, |
| 3929 | .addralign = addr_align, | 4200 | .addralign = addr_align, |
| 3930 | .entsize = rela_size, | 4201 | .entsize = rela_size, |
| 3931 | .node_align = elf.mf.flags.block_size, | 4202 | .node_align = node_block_align, |
| 3932 | }); | 4203 | }); |
| 3933 | elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{ | 4204 | elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{ |
| 3934 | .name = ".dynamic", | 4205 | .name = ".dynamic", |
| ... | @@ -3938,6 +4209,32 @@ fn initHeaders( | ... | @@ -3938,6 +4209,32 @@ fn initHeaders( |
| 3938 | .entsize = @intCast(addr_align.toByteUnits() * 2), | 4209 | .entsize = @intCast(addr_align.toByteUnits() * 2), |
| 3939 | .node_align = addr_align, | 4210 | .node_align = addr_align, |
| 3940 | }); | 4211 | }); |
| | 4212 | switch (elf.targetDynsymHashInfo()) { |
| | 4213 | inline else => |info| { |
| | 4214 | elf.shndx.hash = try elf.addSection(elf.ni.rodata, .{ |
| | 4215 | .name = ".hash", |
| | 4216 | .type = .HASH, |
| | 4217 | .flags = .{ .ALLOC = true }, |
| | 4218 | .link = elf.shndx.dynsym.toSection().?, |
| | 4219 | // It's unclear what value is correct for the alignment. binutils uses 8 everywhere, |
| | 4220 | // while lld uses 4 everywhere (but lld lacks support for the alpha/s390x special |
| | 4221 | // case). Matching the hash word (= entry) size seems like the actually sane choice, |
| | 4222 | // and is what mold does too. |
| | 4223 | .addralign = .fromByteUnits(@sizeOf(info.Int())), |
| | 4224 | // initially: nbucket = 8 + nchain = 1 |
| | 4225 | .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1), |
| | 4226 | }); |
| | 4227 | const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| | 4228 | const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]); |
| | 4229 | header.* = .{ .nbucket = 8, .nchain = 1 }; |
| | 4230 | if (elf.targetEndian() != std.lang.Endian.native) { |
| | 4231 | std.mem.byteSwapAllFields(info.Header(), header); |
| | 4232 | } |
| | 4233 | // The initial bucket and chain values are all 0, but `MappedFile` initialized |
| | 4234 | // the node with zeroes anyway, so no need to memset. |
| | 4235 | }, |
| | 4236 | } |
| | 4237 | |
| 3941 | switch (machine) { | 4238 | switch (machine) { |
| 3942 | .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)), | 4239 | .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)), |
| 3943 | .X86_64 => { | 4240 | .X86_64 => { |
| ... | @@ -4015,15 +4312,6 @@ fn initHeaders( | ... | @@ -4015,15 +4312,6 @@ fn initHeaders( |
| 4015 | .SPARCV9 => {}, | 4312 | .SPARCV9 => {}, |
| 4016 | } | 4313 | } |
| 4017 | } | 4314 | } |
| 4018 | if (comp.config.any_non_single_threaded) { | | |
| 4019 | elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ | | |
| 4020 | .alignment = elf.mf.flags.block_size, | | |
| 4021 | .moved = true, | | |
| 4022 | .bubbles_moved = false, | | |
| 4023 | }); | | |
| 4024 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.tls }); | | |
| 4025 | elf.phdrs.items[phndx.tls] = elf.ni.tls; | | |
| 4026 | } | | |
| 4027 | | 4315 | |
| 4028 | // Populate reserved GOT words. | 4316 | // Populate reserved GOT words. |
| 4029 | switch (machine) { | 4317 | switch (machine) { |
| ... | @@ -4199,7 +4487,7 @@ fn initHeaders( | ... | @@ -4199,7 +4487,7 @@ fn initHeaders( |
| 4199 | if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{ | 4487 | if (comp.config.any_non_single_threaded) elf.shndx.tdata = try elf.addSection(elf.ni.tls, .{ |
| 4200 | .name = ".tdata", | 4488 | .name = ".tdata", |
| 4201 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, | 4489 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 4202 | .addralign = elf.mf.flags.block_size, | 4490 | .node_align = node_block_align, |
| 4203 | }); | 4491 | }); |
| 4204 | | 4492 | |
| 4205 | assert(elf.nodes.len == expected_nodes_len); | 4493 | assert(elf.nodes.len == expected_nodes_len); |
| ... | @@ -4465,6 +4753,28 @@ fn ehdrType(elf: *const Elf) EhdrType { | ... | @@ -4465,6 +4753,28 @@ fn ehdrType(elf: *const Elf) EhdrType { |
| 4465 | fn targetPtrSize(elf: *const Elf) u8 { | 4753 | fn targetPtrSize(elf: *const Elf) u8 { |
| 4466 | return elf.identClass().size(); | 4754 | return elf.identClass().size(); |
| 4467 | } | 4755 | } |
| | 4756 | fn targetPageAlign(elf: *const Elf) std.mem.Alignment { |
| | 4757 | return .fromByteUnits(switch (elf.ehdrMachine()) { |
| | 4758 | .AARCH64 => 0x10000, |
| | 4759 | .LOONGARCH => 0x4000, |
| | 4760 | .PPC64 => 0x10000, |
| | 4761 | .RISCV => 0x1000, |
| | 4762 | .SPARCV9 => 0x100000, |
| | 4763 | .X86_64 => 0x1000, |
| | 4764 | |
| | 4765 | //.@"68K" => 0x2000, |
| | 4766 | //.AMDGPU => 0x10000, |
| | 4767 | //.ARC_COMPACT2 => 0x2000, |
| | 4768 | //.AVR => 0x1, |
| | 4769 | //.BPF => 0x100000, |
| | 4770 | //.MIPS => 0x10000, |
| | 4771 | //.MSP430 => 0x4, |
| | 4772 | //.PPC => 0x10000, |
| | 4773 | //.QDSP6 => 0x10000, |
| | 4774 | //.SPARC => 0x10000, |
| | 4775 | //.SPARC32PLUS => 0x10000, |
| | 4776 | }); |
| | 4777 | } |
| 4468 | fn targetEndian(elf: *const Elf) std.lang.Endian { | 4778 | fn targetEndian(elf: *const Elf) std.lang.Endian { |
| 4469 | const ident_data: std.elf.DATA = @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.DATA]); | 4779 | const ident_data: std.elf.DATA = @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.DATA]); |
| 4470 | return ident_data.endian(); | 4780 | return ident_data.endian(); |
| ... | @@ -4531,6 +4841,30 @@ const PltInfo = struct { | ... | @@ -4531,6 +4841,30 @@ const PltInfo = struct { |
| 4531 | fn targetPltInfo(elf: *const Elf) PltInfo { | 4841 | fn targetPltInfo(elf: *const Elf) PltInfo { |
| 4532 | return .fromMachine(elf.ehdrMachine()); | 4842 | return .fromMachine(elf.ehdrMachine()); |
| 4533 | } | 4843 | } |
| | 4844 | const DynsymHashInfo = enum(u32) { |
| | 4845 | @"4" = 4, |
| | 4846 | @"8" = 8, |
| | 4847 | |
| | 4848 | fn Int(comptime self: DynsymHashInfo) type { |
| | 4849 | return switch (self) { |
| | 4850 | .@"4" => u32, |
| | 4851 | .@"8" => u64, |
| | 4852 | }; |
| | 4853 | } |
| | 4854 | |
| | 4855 | fn Header(comptime self: DynsymHashInfo) type { |
| | 4856 | return switch (self) { |
| | 4857 | .@"4" => std.elf.hash.Header32, |
| | 4858 | .@"8" => std.elf.hash.Header64, |
| | 4859 | }; |
| | 4860 | } |
| | 4861 | }; |
| | 4862 | fn targetDynsymHashInfo(elf: *const Elf) DynsymHashInfo { |
| | 4863 | return switch (elf.ehdrMachine()) { |
| | 4864 | else => .@"4", |
| | 4865 | // TODO: Alpha and S390x will need to use either `."@4"` or `.@"8"` depending on `elf.identClass()`. |
| | 4866 | }; |
| | 4867 | } |
| 4534 | fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { | 4868 | fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { |
| 4535 | const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer; | 4869 | const pointer_ty = @typeInfo(@TypeOf(ptr)).pointer; |
| 4536 | const Child = pointer_ty.child; | 4870 | const Child = pointer_ty.child; |
| ... | @@ -4586,14 +4920,11 @@ const PhdrSlice = union(std.elf.CLASS) { | ... | @@ -4586,14 +4920,11 @@ const PhdrSlice = union(std.elf.CLASS) { |
| 4586 | }; | 4920 | }; |
| 4587 | fn phdrSlice(elf: *Elf) PhdrSlice { | 4921 | fn phdrSlice(elf: *Elf) PhdrSlice { |
| 4588 | assert(elf.ehdrType() != .REL); | 4922 | assert(elf.ehdrType() != .REL); |
| 4589 | const slice = elf.ni.phdr.slice(&elf.mf); | | |
| 4590 | return switch (elf.identClass()) { | 4923 | return switch (elf.identClass()) { |
| 4591 | .NONE, _ => unreachable, | 4924 | .NONE, _ => unreachable, |
| 4592 | inline else => |class| @unionInit( | 4925 | inline else => |class| @unionInit(PhdrSlice, @tagName(class), @ptrCast(@alignCast( |
| 4593 | PhdrSlice, | 4926 | elf.ni.phdr.slice(&elf.mf)[0 .. elf.phdrs.items.len * @sizeOf(class.ElfN().Phdr)], |
| 4594 | @tagName(class), | 4927 | ))), |
| 4595 | @ptrCast(@alignCast(slice)), | | |
| 4596 | ), | | |
| 4597 | }; | 4928 | }; |
| 4598 | } | 4929 | } |
| 4599 | | 4930 | |
| ... | @@ -4607,7 +4938,9 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { | ... | @@ -4607,7 +4938,9 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { |
| 4607 | switch (elf.identClass()) { | 4938 | switch (elf.identClass()) { |
| 4608 | .NONE, _ => unreachable, | 4939 | .NONE, _ => unreachable, |
| 4609 | inline else => |class| { | 4940 | inline else => |class| { |
| 4610 | const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast(raw_slice)); | 4941 | const shdr_slice: []class.ElfN().Shdr = @ptrCast(@alignCast( |
| | 4942 | raw_slice[0 .. elf.shdrs.items.len * @sizeOf(class.ElfN().Shdr)], |
| | 4943 | )); |
| 4611 | const shdr_ptr = &shdr_slice[@backingInt(shndx)]; | 4944 | const shdr_ptr = &shdr_slice[@backingInt(shndx)]; |
| 4612 | return @unionInit(ShdrPtr, @tagName(class), shdr_ptr); | 4945 | return @unionInit(ShdrPtr, @tagName(class), shdr_ptr); |
| 4613 | }, | 4946 | }, |
| ... | @@ -4662,7 +4995,6 @@ fn navType(elf: *const Elf, nav_resolved: InternPool.Nav.Resolved) std.elf.STT { | ... | @@ -4662,7 +4995,6 @@ fn navType(elf: *const Elf, nav_resolved: InternPool.Nav.Resolved) std.elf.STT { |
| 4662 | fn mapInputSection(elf: *Elf, opts: struct { | 4995 | fn mapInputSection(elf: *Elf, opts: struct { |
| 4663 | name: []const u8, | 4996 | name: []const u8, |
| 4664 | flags: std.elf.SHF, | 4997 | flags: std.elf.SHF, |
| 4665 | addralign: std.elf.Xword, | | |
| 4666 | entsize: std.elf.Xword, | 4998 | entsize: std.elf.Xword, |
| 4667 | }) (Error || error{ | 4999 | }) (Error || error{ |
| 4668 | UnsupportedSectionFlags, | 5000 | UnsupportedSectionFlags, |
| ... | @@ -4734,16 +5066,12 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -4734,16 +5066,12 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 4734 | flags.COMPRESSED = false; | 5066 | flags.COMPRESSED = false; |
| 4735 | break :flags flags; | 5067 | break :flags flags; |
| 4736 | }, | 5068 | }, |
| 4737 | .node_align = .fromByteUnits(std.math.ceilPowerOfTwoAssert( | | |
| 4738 | usize, | | |
| 4739 | @intCast(@max(opts.addralign, 1)), | | |
| 4740 | )), | | |
| 4741 | .entsize = std.math.lossyCast(u32, opts.entsize), | 5069 | .entsize = std.math.lossyCast(u32, opts.entsize), |
| 4742 | }); | 5070 | }); |
| 4743 | }; | 5071 | }; |
| 4744 | // Validate that the input is compatible with this section... | | |
| 4745 | switch (elf.shdrPtr(existing_shndx)) { | 5072 | switch (elf.shdrPtr(existing_shndx)) { |
| 4746 | inline else => |shdr| { | 5073 | inline else => |shdr| { |
| | 5074 | // Validate that the input is compatible with this section |
| 4747 | const cur_flags = elf.targetLoad(&shdr.flags).shf; | 5075 | const cur_flags = elf.targetLoad(&shdr.flags).shf; |
| 4748 | if (cur_flags.EXECINSTR != opts.flags.EXECINSTR or | 5076 | if (cur_flags.EXECINSTR != opts.flags.EXECINSTR or |
| 4749 | cur_flags.WRITE != opts.flags.WRITE or | 5077 | cur_flags.WRITE != opts.flags.WRITE or |
| ... | @@ -4756,20 +5084,8 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -4756,20 +5084,8 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 4756 | .NULL, .PROGBITS => {}, | 5084 | .NULL, .PROGBITS => {}, |
| 4757 | else => return error.SectionTypeConflict, | 5085 | else => return error.SectionTypeConflict, |
| 4758 | } | 5086 | } |
| 4759 | }, | 5087 | |
| 4760 | } | 5088 | // All okay, combine the section flags |
| 4761 | // ...then realign the section's node if necessary... | | |
| 4762 | if (opts.addralign > existing_shndx.get(elf).ni.alignment(&elf.mf).toByteUnits()) { | | |
| 4763 | const new_alignment: std.mem.Alignment = .fromByteUnits( | | |
| 4764 | std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), | | |
| 4765 | ); | | |
| 4766 | try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{}); | | |
| 4767 | } | | |
| 4768 | // ...and update the shdr as needed. | | |
| 4769 | switch (elf.shdrPtr(existing_shndx)) { | | |
| 4770 | inline else => |shdr| { | | |
| 4771 | // Combine the section flags. | | |
| 4772 | const cur_flags = elf.targetLoad(&shdr.flags).shf; | | |
| 4773 | elf.targetStore(&shdr.flags, .{ .shf = .{ | 5089 | elf.targetStore(&shdr.flags, .{ .shf = .{ |
| 4774 | .EXECINSTR = cur_flags.EXECINSTR, | 5090 | .EXECINSTR = cur_flags.EXECINSTR, |
| 4775 | .WRITE = cur_flags.WRITE, | 5091 | .WRITE = cur_flags.WRITE, |
| ... | @@ -4778,11 +5094,6 @@ fn mapInputSection(elf: *Elf, opts: struct { | ... | @@ -4778,11 +5094,6 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 4778 | .STRINGS = cur_flags.STRINGS and opts.flags.STRINGS, | 5094 | .STRINGS = cur_flags.STRINGS and opts.flags.STRINGS, |
| 4779 | .MERGE = cur_flags.MERGE and opts.flags.MERGE, | 5095 | .MERGE = cur_flags.MERGE and opts.flags.MERGE, |
| 4780 | } }); | 5096 | } }); |
| 4781 | // Increase addralign to the maximum of the current value and the new value---the node | | |
| 4782 | // alignment was already increased above. | | |
| 4783 | if (opts.addralign > elf.targetLoad(&shdr.addralign)) { | | |
| 4784 | elf.targetStore(&shdr.addralign, @intCast(opts.addralign)); | | |
| 4785 | } | | |
| 4786 | }, | 5097 | }, |
| 4787 | } | 5098 | } |
| 4788 | return existing_shndx; | 5099 | return existing_shndx; |
| ... | @@ -4810,7 +5121,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node | ... | @@ -4810,7 +5121,6 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node |
| 4810 | .TLS = elf.base.comp.config.any_non_single_threaded and | 5121 | .TLS = elf.base.comp.config.any_non_single_threaded and |
| 4811 | nav.resolved.?.@"threadlocal", | 5122 | nav.resolved.?.@"threadlocal", |
| 4812 | }, | 5123 | }, |
| 4813 | .addralign = 1, | | |
| 4814 | .entsize = 0, | 5124 | .entsize = 0, |
| 4815 | })) |shndx| { | 5125 | })) |shndx| { |
| 4816 | break :section shndx; | 5126 | break :section shndx; |
| ... | @@ -4856,6 +5166,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node | ... | @@ -4856,6 +5166,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) Error!Node |
| 4856 | else => |a| a, | 5166 | else => |a| a, |
| 4857 | }, | 5167 | }, |
| 4858 | }; | 5168 | }; |
| | 5169 | try shndx.ensureAligned(elf, alignment.toStdMem()); |
| 4859 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ | 5170 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| 4860 | .alignment = alignment.toStdMem(), | 5171 | .alignment = alignment.toStdMem(), |
| 4861 | }); | 5172 | }); |
| ... | @@ -4899,6 +5210,7 @@ fn uavMapIndex( | ... | @@ -4899,6 +5210,7 @@ fn uavMapIndex( |
| 4899 | const umi: Node.UavMapIndex = @fromBackingInt(@intCast(uav_gop.index)); | 5210 | const umi: Node.UavMapIndex = @fromBackingInt(@intCast(uav_gop.index)); |
| 4900 | if (!uav_gop.found_existing) { | 5211 | if (!uav_gop.found_existing) { |
| 4901 | const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs | 5212 | const shndx: Section.Index = .data_rel_ro; // TODO: it would be better to use `.rodata` if the UAV value doesn't have relocs |
| | 5213 | try shndx.ensureAligned(elf, resolved_align.toStdMem()); |
| 4902 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ | 5214 | const node = try elf.mf.addLastChildNode(gpa, shndx.get(elf).ni, .{ |
| 4903 | .moved = true, // see assert at end of `genUav` | 5215 | .moved = true, // see assert at end of `genUav` |
| 4904 | .alignment = resolved_align.toStdMem(), | 5216 | .alignment = resolved_align.toStdMem(), |
| ... | @@ -4925,6 +5237,8 @@ fn uavMapIndex( | ... | @@ -4925,6 +5237,8 @@ fn uavMapIndex( |
| 4925 | elf.pending_uavs.appendAssumeCapacity(umi); | 5237 | elf.pending_uavs.appendAssumeCapacity(umi); |
| 4926 | } else { | 5238 | } else { |
| 4927 | const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; | 5239 | const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; |
| | 5240 | const shndx = elf.getNode(node.parent(&elf.mf)).section; |
| | 5241 | try shndx.ensureAligned(elf, resolved_align.toStdMem()); |
| 4928 | if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { | 5242 | if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { |
| 4929 | try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{}); | 5243 | try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{}); |
| 4930 | } | 5244 | } |
| ... | @@ -5225,7 +5539,6 @@ fn loadObject( | ... | @@ -5225,7 +5539,6 @@ fn loadObject( |
| 5225 | const shndx = elf.mapInputSection(.{ | 5539 | const shndx = elf.mapInputSection(.{ |
| 5226 | .name = name, | 5540 | .name = name, |
| 5227 | .flags = section.shdr.flags.shf, | 5541 | .flags = section.shdr.flags.shf, |
| 5228 | .addralign = section.shdr.addralign, | | |
| 5229 | .entsize = section.shdr.entsize, | 5542 | .entsize = section.shdr.entsize, |
| 5230 | }) catch |err| switch (err) { | 5543 | }) catch |err| switch (err) { |
| 5231 | error.StripSection => continue, | 5544 | error.StripSection => continue, |
| ... | @@ -5313,7 +5626,7 @@ fn loadObject( | ... | @@ -5313,7 +5626,7 @@ fn loadObject( |
| 5313 | const old_size = elf.targetLoad(&shdr.size); | 5626 | const old_size = elf.targetLoad(&shdr.size); |
| 5314 | const new_size = old_size + section.shdr.size; | 5627 | const new_size = old_size + section.shdr.size; |
| 5315 | elf.targetStore(&shdr.size, @intCast(new_size)); | 5628 | elf.targetStore(&shdr.size, @intCast(new_size)); |
| 5316 | elf.updateInitFiniArraySectionSize(shndx.*, init_fini_section_name, @"type", new_size); | 5629 | elf.updateInitFiniArraySectionSize(shndx.*, init_fini_section_name); |
| 5317 | }, | 5630 | }, |
| 5318 | } | 5631 | } |
| 5319 | break :shndx shndx.*; | 5632 | break :shndx shndx.*; |
| ... | @@ -5324,12 +5637,13 @@ fn loadObject( | ... | @@ -5324,12 +5637,13 @@ fn loadObject( |
| 5324 | .node_fixed = true, | 5637 | .node_fixed = true, |
| 5325 | }, | 5638 | }, |
| 5326 | }; | 5639 | }; |
| | 5640 | const need_align: std.mem.Alignment = .fromByteUnits( |
| | 5641 | std.math.ceilPowerOfTwoAssert(usize, @intCast(@max(section.shdr.addralign, 1))), |
| | 5642 | ); |
| | 5643 | try opts.shndx.ensureAligned(elf, need_align); |
| 5327 | const ni = try elf.mf.addLastChildNode(gpa, opts.shndx.get(elf).ni, .{ | 5644 | const ni = try elf.mf.addLastChildNode(gpa, opts.shndx.get(elf).ni, .{ |
| 5328 | .size = section.shdr.size, | 5645 | .size = section.shdr.size, |
| 5329 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( | 5646 | .alignment = need_align, |
| 5330 | usize, | | |
| 5331 | @intCast(@max(section.shdr.addralign, 1)), | | |
| 5332 | )), | | |
| 5333 | .moved = true, // see assert at end of `flushInputSection` | 5647 | .moved = true, // see assert at end of `flushInputSection` |
| 5334 | .fixed = opts.node_fixed, | 5648 | .fixed = opts.node_fixed, |
| 5335 | }); | 5649 | }); |
| ... | @@ -5699,6 +6013,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars | ... | @@ -5699,6 +6013,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars |
| 5699 | if (elf.copied_globals.get(name)) |copied_global| { | 6013 | if (elf.copied_globals.get(name)) |copied_global| { |
| 5700 | // We have a copy relocation for this global, but the amount of space we | 6014 | // We have a copy relocation for this global, but the amount of space we |
| 5701 | // reserved for it could be too small or underaligned! | 6015 | // reserved for it could be too small or underaligned! |
| | 6016 | try Section.Index.data.ensureAligned(elf, gop.value_ptr.alignment); |
| 5702 | try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); | 6017 | try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); |
| 5703 | try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{}); | 6018 | try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{}); |
| 5704 | const global_ptr = elf.globalByName(name).?; | 6019 | const global_ptr = elf.globalByName(name).?; |
| ... | @@ -5878,19 +6193,7 @@ fn updateInitFiniArraySectionSize( | ... | @@ -5878,19 +6193,7 @@ fn updateInitFiniArraySectionSize( |
| 5878 | elf: *Elf, | 6193 | elf: *Elf, |
| 5879 | shndx: Section.Index, | 6194 | shndx: Section.Index, |
| 5880 | comptime name: []const u8, | 6195 | comptime name: []const u8, |
| 5881 | @"type": std.elf.SHT, | | |
| 5882 | new_size: u64, | | |
| 5883 | ) void { | 6196 | ) void { |
| 5884 | if (elf.shndx.dynamic != .UNDEF) { | | |
| 5885 | const arraysz_dyn_key: u32 = switch (@"type") { | | |
| 5886 | .INIT_ARRAY => std.elf.DT_INIT_ARRAYSZ, | | |
| 5887 | .FINI_ARRAY => std.elf.DT_FINI_ARRAYSZ, | | |
| 5888 | .PREINIT_ARRAY => std.elf.DT_PREINIT_ARRAYSZ, | | |
| 5889 | else => unreachable, | | |
| 5890 | }; | | |
| 5891 | elf.updateDynamicEntry(arraysz_dyn_key, new_size); | | |
| 5892 | } | | |
| 5893 | | | |
| 5894 | const end_vaddr: u64 = switch (elf.shdrPtr(shndx)) { | 6197 | const end_vaddr: u64 = switch (elf.shdrPtr(shndx)) { |
| 5895 | inline else => |shdr| shndx.vaddr(elf) + elf.targetLoad(&shdr.size), | 6198 | inline else => |shdr| shndx.vaddr(elf) + elf.targetLoad(&shdr.size), |
| 5896 | }; | 6199 | }; |
| ... | @@ -5955,7 +6258,7 @@ fn prepareDynamic(elf: *Elf) Error!void { | ... | @@ -5955,7 +6258,7 @@ fn prepareDynamic(elf: *Elf) Error!void { |
| 5955 | @as(usize, @intFromBool(elf.shndx.preinit_array != .UNDEF)) * 2 + | 6258 | @as(usize, @intFromBool(elf.shndx.preinit_array != .UNDEF)) * 2 + |
| 5956 | @as(usize, @intFromBool(use_plt)) * 4 + | 6259 | @as(usize, @intFromBool(use_plt)) * 4 + |
| 5957 | @intFromBool(comp.config.output_mode == .Exe) + | 6260 | @intFromBool(comp.config.output_mode == .Exe) + |
| 5958 | @intFromBool(elf.textrel_count > 0) + 8; | 6261 | @intFromBool(elf.textrel_count > 0) + 9; |
| 5959 | | 6262 | |
| 5960 | const dynamic_size = dynamic_len * 2 * elf.targetPtrSize(); | 6263 | const dynamic_size = dynamic_len * 2 * elf.targetPtrSize(); |
| 5961 | | 6264 | |
| ... | @@ -6055,7 +6358,7 @@ fn flushDynamic(elf: *Elf) void { | ... | @@ -6055,7 +6358,7 @@ fn flushDynamic(elf: *Elf) void { |
| 6055 | dynamic_index += 4; | 6358 | dynamic_index += 4; |
| 6056 | } | 6359 | } |
| 6057 | | 6360 | |
| 6058 | dynamic_entries[dynamic_index..][0..8].* = .{ | 6361 | dynamic_entries[dynamic_index..][0..9].* = .{ |
| 6059 | .{ std.elf.DT_RELA, @intCast(elf.shndx.rela_dyn.vaddr(elf)) }, | 6362 | .{ std.elf.DT_RELA, @intCast(elf.shndx.rela_dyn.vaddr(elf)) }, |
| 6060 | .{ std.elf.DT_RELASZ, @intCast(elf.shndx.rela_dyn.size(elf)) }, | 6363 | .{ std.elf.DT_RELASZ, @intCast(elf.shndx.rela_dyn.size(elf)) }, |
| 6061 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, | 6364 | .{ std.elf.DT_RELAENT, @sizeOf(ElfN.Rela) }, |
| ... | @@ -6063,9 +6366,10 @@ fn flushDynamic(elf: *Elf) void { | ... | @@ -6063,9 +6366,10 @@ fn flushDynamic(elf: *Elf) void { |
| 6063 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, | 6366 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 6064 | .{ std.elf.DT_STRTAB, @intCast(elf.shndx.dynstr.vaddr(elf)) }, | 6367 | .{ std.elf.DT_STRTAB, @intCast(elf.shndx.dynstr.vaddr(elf)) }, |
| 6065 | .{ std.elf.DT_STRSZ, @intCast(elf.shndx.dynstr.size(elf)) }, | 6368 | .{ std.elf.DT_STRSZ, @intCast(elf.shndx.dynstr.size(elf)) }, |
| | 6369 | .{ std.elf.DT_HASH, @intCast(elf.shndx.hash.vaddr(elf)) }, |
| 6066 | .{ std.elf.DT_NULL, 0 }, | 6370 | .{ std.elf.DT_NULL, 0 }, |
| 6067 | }; | 6371 | }; |
| 6068 | dynamic_index += 8; | 6372 | dynamic_index += 9; |
| 6069 | | 6373 | |
| 6070 | assert(dynamic_index == dynamic_entries.len); | 6374 | assert(dynamic_index == dynamic_entries.len); |
| 6071 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| | 6375 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| ... | @@ -6092,7 +6396,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -6092,7 +6396,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6092 | else => {}, | 6396 | else => {}, |
| 6093 | } | 6397 | } |
| 6094 | if (opts.flags.ALLOC and elf.ehdrType() != .REL) { | 6398 | if (opts.flags.ALLOC and elf.ehdrType() != .REL) { |
| 6095 | assert(elf.getNode(segment_ni) == .segment); | 6399 | const phndx = elf.getNode(segment_ni).segment; |
| | 6400 | try elf.ensureSegmentAligned(phndx, opts.addralign); |
| 6096 | } | 6401 | } |
| 6097 | const gpa = elf.base.comp.gpa; | 6402 | const gpa = elf.base.comp.gpa; |
| 6098 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 6403 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -6427,7 +6732,7 @@ fn addRelocAssumeCapacity( | ... | @@ -6427,7 +6732,7 @@ fn addRelocAssumeCapacity( |
| 6427 | | 6732 | |
| 6428 | .WDISP30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), | 6733 | .WDISP30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), |
| 6429 | .WPLT30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), | 6734 | .WPLT30 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.pltrel, .{ .dest = .@"32[29:0]", .cast = .signed, .shift = .@"2_exact" })), |
| 6430 | .PC22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[21:0]", .cast = .signed, .shift = .@"10" })), | 6735 | .PC22 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"10" })), |
| 6431 | .H44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"22" })), | 6736 | .H44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[21:0]", .cast = .unsigned, .shift = .@"22" })), |
| 6432 | .M44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"12" })), | 6737 | .M44 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"12" })), |
| 6433 | | 6738 | |
| ... | @@ -6457,36 +6762,36 @@ fn addRelocAssumeCapacity( | ... | @@ -6457,36 +6762,36 @@ fn addRelocAssumeCapacity( |
| 6457 | | 6762 | |
| 6458 | // The following relocations are all represented by the ABI as writing to a 13 bit | 6763 | // The following relocations are all represented by the ABI as writing to a 13 bit |
| 6459 | // field (32[12:0]), but masking out some bits of the value. To simplify our logic | 6764 | // field (32[12:0]), but masking out some bits of the value. To simplify our logic |
| 6460 | // for applying relocations, we instead [un]set any fixed bits right now, then model | 6765 | // for applying relocations, we split this action up: we create a relocation writing |
| 6461 | // the relocation as only writing to a smaller 10--12 bit field. | 6766 | // to the 10--12 bit long field which is actually variable, and queue a one-shot |
| 6462 | // TODO: because we flush input sections lazily, we can't actually write these bits | 6767 | // task to set the constant bits. We can't just write the bits now unfortunately |
| 6463 | // immediately---we'll instead have to queue the writes somehow. | 6768 | // because they may be in an input section which has not yet been loaded. |
| 6464 | .PC10 => { | 6769 | .PC10 => { |
| 6465 | // TODO: 32[12:10] = 0b000 | 6770 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" }); |
| 6466 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6771 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6467 | }, | 6772 | }, |
| 6468 | .L44 => { | 6773 | .L44 => { |
| 6469 | // TODO: 32[12:12] = 0b0 | 6774 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:12] = 0b0" }); |
| 6470 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[11:0]", .cast = .trunc, .shift = .@"0" })); | 6775 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[11:0]", .cast = .trunc, .shift = .@"0" })); |
| 6471 | }, | 6776 | }, |
| 6472 | .TLS_LDO_LOX10 => { | 6777 | .TLS_LDO_LOX10 => { |
| 6473 | // TODO: 32[12:10] = 0b000 | 6778 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" }); |
| 6474 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6779 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6475 | }, | 6780 | }, |
| 6476 | .TLS_LE_LOX10 => { | 6781 | .TLS_LE_LOX10 => { |
| 6477 | // TODO: 32[12:10] = 0b111 | 6782 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b111" }); |
| 6478 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6783 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6479 | }, | 6784 | }, |
| 6480 | .GOT10 => { | 6785 | .GOT10 => { |
| 6481 | // TODO: 32[12:10] = 0b000 | 6786 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" }); |
| 6482 | elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6787 | elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6483 | }, | 6788 | }, |
| 6484 | .TLS_GD_LO10 => { | 6789 | .TLS_GD_LO10 => { |
| 6485 | // TODO: 32[12:10] = 0b000 | 6790 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" }); |
| 6486 | elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6791 | elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6487 | }, | 6792 | }, |
| 6488 | .TLS_LDM_LO10 => { | 6793 | .TLS_LDM_LO10 => { |
| 6489 | // TODO: 32[12:10] = 0b000 | 6794 | try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" }); |
| 6490 | elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); | 6795 | elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6491 | }, | 6796 | }, |
| 6492 | }, | 6797 | }, |
| ... | @@ -6887,7 +7192,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -6887,7 +7192,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 6887 | const entry_ptr: *class.ElfN().Addr = @ptrCast(@alignCast( | 7192 | const entry_ptr: *class.ElfN().Addr = @ptrCast(@alignCast( |
| 6888 | elf.shndx.got.get(elf).ni.slice(&elf.mf)[offset..][0..addr_size], | 7193 | elf.shndx.got.get(elf).ni.slice(&elf.mf)[offset..][0..addr_size], |
| 6889 | )); | 7194 | )); |
| 6890 | entry_ptr.* = switch (entry_value) { | 7195 | elf.targetStore(entry_ptr, switch (entry_value) { |
| 6891 | .unsigned => |x| @intCast(x), | 7196 | .unsigned => |x| @intCast(x), |
| 6892 | .signed => |x| switch (class) { | 7197 | .signed => |x| switch (class) { |
| 6893 | .NONE, _ => comptime unreachable, | 7198 | .NONE, _ => comptime unreachable, |
| ... | @@ -6895,7 +7200,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { | ... | @@ -6895,7 +7200,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { |
| 6895 | .@"64" => @bitCast(x), | 7200 | .@"64" => @bitCast(x), |
| 6896 | }, | 7201 | }, |
| 6897 | .reloc => 0, | 7202 | .reloc => 0, |
| 6898 | }; | 7203 | }); |
| 6899 | break :got_entry_addr elf.targetLoad(&got_shdr.addr) + offset; | 7204 | break :got_entry_addr elf.targetLoad(&got_shdr.addr) + offset; |
| 6900 | }, | 7205 | }, |
| 6901 | }; | 7206 | }; |
| ... | @@ -6950,6 +7255,9 @@ fn nodeWantsDsoRelocation(elf: *Elf, node: MappedFile.Node.Index) enum { yes, ye | ... | @@ -6950,6 +7255,9 @@ fn nodeWantsDsoRelocation(elf: *Elf, node: MappedFile.Node.Index) enum { yes, ye |
| 6950 | fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { | 7255 | fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { |
| 6951 | assert(elf.shndx.dynamic != .UNDEF); | 7256 | assert(elf.shndx.dynamic != .UNDEF); |
| 6952 | | 7257 | |
| | 7258 | // Only dynamic executables may contain `R_*_COPY` relocations. |
| | 7259 | if (elf.base.comp.config.output_mode != .Exe) return false; |
| | 7260 | |
| 6953 | const gpa = elf.base.comp.gpa; | 7261 | const gpa = elf.base.comp.gpa; |
| 6954 | | 7262 | |
| 6955 | const global_ptr = elf.globals.strong_undef.getPtr(global_name) orelse | 7263 | const global_ptr = elf.globals.strong_undef.getPtr(global_name) orelse |
| ... | @@ -6957,10 +7265,6 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { | ... | @@ -6957,10 +7265,6 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { |
| 6957 | | 7265 | |
| 6958 | assert(global_ptr.dynsym_index != 0); | 7266 | assert(global_ptr.dynsym_index != 0); |
| 6959 | | 7267 | |
| 6960 | // Only dynamic executables may contain `R_*_COPY` relocations. | | |
| 6961 | if (elf.shndx.dynamic == .UNDEF) return false; | | |
| 6962 | if (elf.base.comp.config.output_mode != .Exe) return false; | | |
| 6963 | | | |
| 6964 | const dso_global = elf.dso_globals.get(global_name) orelse { | 7268 | const dso_global = elf.dso_globals.get(global_name) orelse { |
| 6965 | // We do not have a definition to provide the correct size for the symbol. If a definition | 7269 | // We do not have a definition to provide the correct size for the symbol. If a definition |
| 6966 | // is discovered in a later DSO, we may at that point be able to add a copy relocation. | 7270 | // is discovered in a later DSO, we may at that point be able to add a copy relocation. |
| ... | @@ -6974,6 +7278,8 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { | ... | @@ -6974,6 +7278,8 @@ fn maybeAddCopyRelocation(elf: *Elf, global_name: String(.strtab)) Error!bool { |
| 6974 | if (gop.found_existing) return true; | 7278 | if (gop.found_existing) return true; |
| 6975 | errdefer assert(elf.copied_globals.pop().?.key == global_name); | 7279 | errdefer assert(elf.copied_globals.pop().?.key == global_name); |
| 6976 | | 7280 | |
| | 7281 | try Section.Index.data.ensureAligned(elf, dso_global.alignment); |
| | 7282 | |
| 6977 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 7283 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 6978 | const node = try elf.mf.addLastChildNode(gpa, Section.Index.data.get(elf).ni, .{ | 7284 | const node = try elf.mf.addLastChildNode(gpa, Section.Index.data.get(elf).ni, .{ |
| 6979 | .size = dso_global.size, | 7285 | .size = dso_global.size, |
| ... | @@ -7234,6 +7540,25 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { | ... | @@ -7234,6 +7540,25 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7234 | }; | 7540 | }; |
| 7235 | break :task; | 7541 | break :task; |
| 7236 | } | 7542 | } |
| | 7543 | if (elf.one_shot_fixups.items.len > 0) { |
| | 7544 | // Each of these is very simple, so an unreasonable amount of overhead would be |
| | 7545 | // introduced if we only did one per `idle` call. Also, there is no risk of this work |
| | 7546 | // being invalidated. So let's just flush the entire queue at once. |
| | 7547 | for (elf.one_shot_fixups.items) |isw| { |
| | 7548 | const dest_slice = isw.node.slice(&elf.mf)[@intCast(isw.offset)..][0..4]; |
| | 7549 | const old: u32 = std.mem.readInt(u32, dest_slice, elf.targetEndian()); |
| | 7550 | const new: u32 = switch (isw.action) { |
| | 7551 | // zig fmt: off |
| | 7552 | .@"32[12:10] = 0b000" => old & 0b11111111_11111111_11100011_11111111, |
| | 7553 | .@"32[12:10] = 0b111" => old | 0b00000000_00000000_00011100_00000000, |
| | 7554 | .@"32[12:12] = 0b0" => old & 0b11111111_11111111_11101111_11111111, |
| | 7555 | // zig fmt: on |
| | 7556 | }; |
| | 7557 | std.mem.writeInt(u32, dest_slice, new, elf.targetEndian()); |
| | 7558 | } |
| | 7559 | elf.one_shot_fixups.clearRetainingCapacity(); |
| | 7560 | break :task; |
| | 7561 | } |
| 7237 | if (elf.changed_symtab_index.pop()) |kv| { | 7562 | if (elf.changed_symtab_index.pop()) |kv| { |
| 7238 | const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0); | 7563 | const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0); |
| 7239 | defer sub_prog_node.end(); | 7564 | defer sub_prog_node.end(); |
| ... | @@ -7324,6 +7649,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { | ... | @@ -7324,6 +7649,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7324 | } | 7649 | } |
| 7325 | } | 7650 | } |
| 7326 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; | 7651 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| | 7652 | if (elf.one_shot_fixups.items.len > 0) return true; |
| 7327 | if (elf.changed_symtab_index.count() > 0) return true; | 7653 | if (elf.changed_symtab_index.count() > 0) return true; |
| 7328 | if (elf.mf.updates.items.len > 0) return true; | 7654 | if (elf.mf.updates.items.len > 0) return true; |
| 7329 | return false; | 7655 | return false; |
| ... | @@ -7586,17 +7912,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -7586,17 +7912,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7586 | const ph = &phdr[phndx]; | 7912 | const ph = &phdr[phndx]; |
| 7587 | switch (elf.targetLoad(&ph.type)) { | 7913 | switch (elf.targetLoad(&ph.type)) { |
| 7588 | else => unreachable, | 7914 | else => unreachable, |
| 7589 | .NULL, .LOAD => return, | 7915 | |
| | 7916 | .NULL, .LOAD => { |
| | 7917 | try elf.allocateSegmentLoadAddress(phndx); |
| | 7918 | }, |
| 7590 | | 7919 | |
| 7591 | .DYNAMIC, | 7920 | .DYNAMIC, |
| 7592 | .INTERP, | 7921 | .INTERP, |
| 7593 | .PHDR, | 7922 | .PHDR, |
| 7594 | .TLS, | 7923 | .TLS, |
| 7595 | .GNU_RELRO, | 7924 | .GNU_RELRO, |
| 7596 | => {}, | 7925 | => { |
| | 7926 | const new_vaddr = elf.computeNodeVAddr(ni); |
| | 7927 | elf.targetStore(&ph.vaddr, @intCast(new_vaddr)); |
| | 7928 | elf.targetStore(&ph.paddr, @intCast(new_vaddr)); |
| | 7929 | }, |
| 7597 | } | 7930 | } |
| 7598 | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); | | |
| 7599 | ph.paddr = ph.vaddr; | | |
| 7600 | }, | 7931 | }, |
| 7601 | } | 7932 | } |
| 7602 | }, | 7933 | }, |
| ... | @@ -7648,8 +7979,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -7648,8 +7979,6 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7648 | elf.flushMovedPltSection(.got_plt, old_addr, addr); | 7979 | elf.flushMovedPltSection(.got_plt, old_addr, addr); |
| 7649 | } else if (shndx == elf.shndx.plt_sec) { | 7980 | } else if (shndx == elf.shndx.plt_sec) { |
| 7650 | elf.flushMovedPltSection(.plt_sec, old_addr, addr); | 7981 | elf.flushMovedPltSection(.plt_sec, old_addr, addr); |
| 7651 | } else if (shndx == elf.shndx.dynamic) { | | |
| 7652 | elf.flushMovedNodeRelocs(ni, addr, elf.dynamic_first_symbol_reloc, .none); | | |
| 7653 | } | 7982 | } |
| 7654 | }, | 7983 | }, |
| 7655 | .input_member => {}, | 7984 | .input_member => {}, |
| ... | @@ -7739,6 +8068,114 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void | ... | @@ -7739,6 +8068,114 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7739 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 8068 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 7740 | } | 8069 | } |
| 7741 | | 8070 | |
| | 8071 | /// Given the index of a `PT_LOAD`/`PT_NULL` segment, assumes that the phdr's `offset` and `filesz` |
| | 8072 | /// have been updated as needed by the caller, and updates the `@"align"`, `vaddr`, `paddr`, and |
| | 8073 | /// `memsz` fields of the segment, in order to place it at a valid virtual address. |
| | 8074 | /// |
| | 8075 | /// TODO: this function is currently a source of non-determinism in the linker, because handling the |
| | 8076 | /// moving or resizing of a segment could reorder them and thereby affect how we handle *future* |
| | 8077 | /// changes to segments. |
| | 8078 | fn allocateSegmentLoadAddress(elf: *Elf, orig_phndx: u32) std.mem.Allocator.Error!void { |
| | 8079 | const segment_ni = elf.phdrs.items[orig_phndx]; |
| | 8080 | assert(elf.getNode(segment_ni).segment == orig_phndx); |
| | 8081 | const page_align = elf.targetPageAlign(); |
| | 8082 | const node_align = segment_ni.alignment(&elf.mf); |
| | 8083 | const ph_align = page_align.max(node_align); |
| | 8084 | switch (elf.phdrSlice()) { |
| | 8085 | inline else => |phdr| { |
| | 8086 | const offset = elf.targetLoad(&phdr[orig_phndx].offset); |
| | 8087 | const size = elf.targetLoad(&phdr[orig_phndx].filesz); |
| | 8088 | |
| | 8089 | if (size == 0) { |
| | 8090 | assert(elf.targetLoad(&phdr[orig_phndx].type) == .NULL); |
| | 8091 | } else { |
| | 8092 | assert(elf.targetLoad(&phdr[orig_phndx].type) == .LOAD); |
| | 8093 | } |
| | 8094 | |
| | 8095 | elf.targetStore(&phdr[orig_phndx].memsz, size); |
| | 8096 | elf.targetStore(&phdr[orig_phndx].@"align", @intCast(ph_align.toByteUnits())); |
| | 8097 | |
| | 8098 | const orig_vaddr = elf.targetLoad(&phdr[orig_phndx].vaddr); |
| | 8099 | assert(elf.targetLoad(&phdr[orig_phndx].paddr) == orig_vaddr); |
| | 8100 | |
| | 8101 | var vaddr: u64 = orig_vaddr; |
| | 8102 | |
| | 8103 | // First, we will shift the virtual address as needed in order to maintain the required |
| | 8104 | // property that vaddr is congruent to offset modulo the phdr alignment. |
| | 8105 | { |
| | 8106 | // Compute the candidate address by undoing the current offset and then re-offsetting |
| | 8107 | vaddr = std.mem.alignBackward(u64, vaddr, ph_align.toByteUnits()) + offset % ph_align.toByteUnits(); |
| | 8108 | // If `node_align` is greater than `page_align`, the address we just set might be in |
| | 8109 | // the previous segment. The first page we "own" is the one in which the old vaddr |
| | 8110 | // resides, so check against that. |
| | 8111 | const first_good_vaddr = std.mem.alignBackward(u64, orig_vaddr, page_align.toByteUnits()); |
| | 8112 | if (vaddr < first_good_vaddr) { |
| | 8113 | // Yep, we crossed into the previous segment's pages, so correct for that by |
| | 8114 | // offsetting our address by another `ph_align`. |
| | 8115 | vaddr += ph_align.toByteUnits(); |
| | 8116 | assert(vaddr >= first_good_vaddr); |
| | 8117 | } |
| | 8118 | } |
| | 8119 | |
| | 8120 | // If our size has changed, or if the address shift above caused our "end" address to |
| | 8121 | // cross a page boundary, then we might be overlapping with the next segment's pages. In |
| | 8122 | // that case, we will jump past that segment and give ourselves a new address after it. |
| | 8123 | // We'll need to repeat this for every loadable phdr after us, until we're no longer |
| | 8124 | // overlapping anything. |
| | 8125 | var phndx = orig_phndx; |
| | 8126 | for (phdr[orig_phndx + 1 ..], orig_phndx + 1..) |*next_ph, next_phndx| { |
| | 8127 | switch (elf.targetLoad(&next_ph.type)) { |
| | 8128 | .NULL, .LOAD => {}, |
| | 8129 | else => { |
| | 8130 | // All loadable segments have contiguous indices, so this indicates we have |
| | 8131 | // become the last loadable segment, meaning we definitely don't overlap any |
| | 8132 | // other loadable segment. |
| | 8133 | break; |
| | 8134 | }, |
| | 8135 | } |
| | 8136 | |
| | 8137 | const next_vaddr = elf.targetLoad(&next_ph.vaddr); |
| | 8138 | // Find the first virtual address which the next phdr "owns" by aligning its vaddr |
| | 8139 | // backwards to the start of the page. |
| | 8140 | const next_page_vaddr = std.mem.alignBackward(u64, next_vaddr, page_align.toByteUnits()); |
| | 8141 | |
| | 8142 | // If we're at the same vaddr we started at, then all we're worried about is the |
| | 8143 | // segment fitting here. However, if we've already changed our virtual address, then |
| | 8144 | // we might as well try to reserve a bit *more* virtual address space while we're at |
| | 8145 | // it, because changing virtual address is quite disruptive (we need to re-flush a |
| | 8146 | // lot of stuff!) and giving ourselves more space will make it less likely to happen |
| | 8147 | // again. |
| | 8148 | const target_size = if (vaddr == orig_vaddr) size else size * 4; |
| | 8149 | if (vaddr + target_size <= next_page_vaddr) { |
| | 8150 | break; // hooray, we fit here! |
| | 8151 | } |
| | 8152 | |
| | 8153 | // We don't fit here, so shift ourselves forward (i.e. swap with `next_phndx`). But |
| | 8154 | // first we need to adjust `vaddr` to come after it. |
| | 8155 | const next_size = elf.targetLoad(&next_ph.memsz); |
| | 8156 | // Instead of putting ourselves right after `next_ph`, we'll go a bit later in the |
| | 8157 | // address space so that `next_ph` has address space to grow into (like above). |
| | 8158 | vaddr = ph_align.forward(@intCast(next_vaddr + next_size * 4)) + offset % ph_align.toByteUnits(); |
| | 8159 | |
| | 8160 | // Now just swap the phdrs and update our `phndx`. |
| | 8161 | std.mem.swap(@TypeOf(next_ph.*), &phdr[phndx], next_ph); |
| | 8162 | const next_ni = elf.phdrs.items[next_phndx]; |
| | 8163 | elf.phdrs.items[phndx] = next_ni; |
| | 8164 | elf.nodes.items(.data)[@backingInt(next_ni)] = .{ .segment = phndx }; |
| | 8165 | elf.phdrs.items[next_phndx] = segment_ni; |
| | 8166 | elf.nodes.items(.data)[@backingInt(segment_ni)] = .{ .segment = @intCast(next_phndx) }; |
| | 8167 | phndx = @intCast(next_phndx); |
| | 8168 | } |
| | 8169 | |
| | 8170 | if (vaddr != orig_vaddr) { |
| | 8171 | elf.targetStore(&phdr[phndx].vaddr, @intCast(vaddr)); |
| | 8172 | elf.targetStore(&phdr[phndx].paddr, @intCast(vaddr)); |
| | 8173 | try segment_ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| | 8174 | } |
| | 8175 | }, |
| | 8176 | } |
| | 8177 | } |
| | 8178 | |
| 7742 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { | 8179 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { |
| 7743 | const trace = tracy.trace(@src()); | 8180 | const trace = tracy.trace(@src()); |
| 7744 | defer trace.end(); | 8181 | defer trace.end(); |
| ... | @@ -7766,68 +8203,40 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -7766,68 +8203,40 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 7766 | assert(elf.phdrs.items[phndx] == ni); | 8203 | assert(elf.phdrs.items[phndx] == ni); |
| 7767 | const ph = &phdr[phndx]; | 8204 | const ph = &phdr[phndx]; |
| 7768 | elf.targetStore(&ph.filesz, @intCast(size)); | 8205 | elf.targetStore(&ph.filesz, @intCast(size)); |
| 7769 | if (size > elf.targetLoad(&ph.memsz)) { | 8206 | switch (elf.targetLoad(&ph.type)) { |
| 7770 | switch (elf.targetLoad(&ph.type)) { | 8207 | else => unreachable, |
| 7771 | else => unreachable, | 8208 | .NULL, .LOAD => { |
| 7772 | .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD), | 8209 | elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL); |
| 7773 | .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL), | 8210 | try elf.allocateSegmentLoadAddress(phndx); |
| 7774 | .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => { | 8211 | }, |
| 7775 | elf.targetStore(&ph.memsz, @intCast(size)); | 8212 | .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => { |
| 7776 | return; | 8213 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 7777 | }, | 8214 | }, |
| 7778 | .TLS => { | 8215 | .TLS => { |
| 7779 | elf.targetStore(&ph.memsz, @intCast(size)); | 8216 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 7780 | // TPOFF relocations care about the size of the TLS segment. Re-apply | 8217 | // TPOFF relocations care about the size of the TLS segment. Re-apply |
| 7781 | // those, and also update any GOT entries from GOTTPOFF relocations. | 8218 | // those, and also update any GOT entries from GOTTPOFF relocations. |
| 7782 | for (elf.tls_size_symbol_relocs.keys()) |reloc| { | 8219 | for (elf.tls_size_symbol_relocs.keys()) |reloc| { |
| 7783 | reloc.get(elf).apply(elf); | 8220 | reloc.get(elf).apply(elf); |
| 7784 | } | 8221 | } |
| 7785 | for (elf.got.keys(), 0..) |got_key, got_index| { | 8222 | for (elf.got.keys(), 0..) |got_key, got_index| { |
| 7786 | switch (got_key) { | 8223 | switch (got_key) { |
| 7787 | .reserved, | 8224 | .reserved, |
| 7788 | .symbol, | 8225 | .symbol, |
| 7789 | .tlsld0, | 8226 | .tlsld0, |
| 7790 | .tlsld1, | 8227 | .tlsld1, |
| 7791 | .tlsgd0, | 8228 | .tlsgd0, |
| 7792 | .tlsgd1, | 8229 | .tlsgd1, |
| 7793 | => { | 8230 | => { |
| 7794 | @branchHint(.likely); | 8231 | @branchHint(.likely); |
| 7795 | continue; | 8232 | continue; |
| 7796 | }, | 8233 | }, |
| 7797 | | 8234 | |
| 7798 | .tpoff => elf.updateGotEntry(got_index), | 8235 | .tpoff => elf.updateGotEntry(got_index), |
| 7799 | } | | |
| 7800 | } | 8236 | } |
| 7801 | return ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | | |
| 7802 | }, | | |
| 7803 | } | | |
| 7804 | const memsz = ni.alignment(&elf.mf).forward(@intCast(size * 4)); | | |
| 7805 | elf.targetStore(&ph.memsz, @intCast(memsz)); | | |
| 7806 | var vaddr = elf.targetLoad(&ph.vaddr); | | |
| 7807 | var new_phndx = phndx; | | |
| 7808 | for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| { | | |
| 7809 | switch (elf.targetLoad(&next_ph.type)) { | | |
| 7810 | else => unreachable, | | |
| 7811 | .NULL, .LOAD => {}, | | |
| 7812 | .DYNAMIC, .INTERP, .PHDR, .TLS, .GNU_RELRO, .GNU_STACK => break, | | |
| 7813 | } | 8237 | } |
| 7814 | const next_vaddr = elf.targetLoad(&next_ph.vaddr); | | |
| 7815 | if (vaddr + memsz <= next_vaddr) break; | | |
| 7816 | vaddr = next_vaddr + elf.targetLoad(&next_ph.memsz); | | |
| 7817 | std.mem.swap(@TypeOf(ph.*), &phdr[new_phndx], next_ph); | | |
| 7818 | const next_ni = elf.phdrs.items[next_phndx]; | | |
| 7819 | elf.phdrs.items[new_phndx] = next_ni; | | |
| 7820 | elf.nodes.items(.data)[@backingInt(next_ni)] = .{ .segment = new_phndx }; | | |
| 7821 | new_phndx = @intCast(next_phndx); | | |
| 7822 | } | | |
| 7823 | if (new_phndx != phndx) { | | |
| 7824 | const new_ph = &phdr[new_phndx]; | | |
| 7825 | elf.targetStore(&new_ph.vaddr, vaddr); | | |
| 7826 | new_ph.paddr = new_ph.vaddr; | | |
| 7827 | elf.phdrs.items[new_phndx] = ni; | | |
| 7828 | elf.nodes.items(.data)[@backingInt(ni)] = .{ .segment = new_phndx }; | | |
| 7829 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 8238 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 7830 | } | 8239 | }, |
| 7831 | } | 8240 | } |
| 7832 | }, | 8241 | }, |
| 7833 | }, | 8242 | }, |
| ... | @@ -7848,6 +8257,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo | ... | @@ -7848,6 +8257,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 7848 | .REL, | 8257 | .REL, |
| 7849 | .RELA, | 8258 | .RELA, |
| 7850 | .DYNSYM, | 8259 | .DYNSYM, |
| | 8260 | .HASH, |
| 7851 | => return, | 8261 | => return, |
| 7852 | } | 8262 | } |
| 7853 | if (shndx != elf.shndx.plt and | 8263 | if (shndx != elf.shndx.plt and |
| ... | @@ -7940,21 +8350,6 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! | ... | @@ -7940,21 +8350,6 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! |
| 7940 | } | 8350 | } |
| 7941 | } | 8351 | } |
| 7942 | | 8352 | |
| 7943 | fn updateDynamicEntry(elf: *Elf, key: u32, new_val: u64) void { | | |
| 7944 | switch (elf.shdrPtr(elf.shndx.dynamic)) { | | |
| 7945 | inline else => |shdr, class| { | | |
| 7946 | const dynamic_size = elf.targetLoad(&shdr.size); | | |
| 7947 | const dynamic_entries: [][2]class.ElfN().Addr = @ptrCast(@alignCast( | | |
| 7948 | elf.shndx.dynamic.get(elf).ni.slice(&elf.mf)[0..@intCast(dynamic_size)], | | |
| 7949 | )); | | |
| 7950 | for (dynamic_entries) |*dynamic_entry| { | | |
| 7951 | if (elf.targetLoad(&dynamic_entry[0]) == key) { | | |
| 7952 | elf.targetStore(&dynamic_entry[1], @intCast(new_val)); | | |
| 7953 | } | | |
| 7954 | } | | |
| 7955 | }, | | |
| 7956 | } | | |
| 7957 | } | | |
| 7958 | fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void { | 8353 | fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void { |
| 7959 | const target_endian = elf.targetEndian(); | 8354 | const target_endian = elf.targetEndian(); |
| 7960 | | 8355 | |
| ... | @@ -8126,9 +8521,9 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -8126,9 +8521,9 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 8126 | const plt_slice: []Inst = @ptrCast(@alignCast(plt_ni.slice(&elf.mf)[@intCast(got_plt_offset)..][0..32])); | 8521 | const plt_slice: []Inst = @ptrCast(@alignCast(plt_ni.slice(&elf.mf)[@intCast(got_plt_offset)..][0..32])); |
| 8127 | @memcpy(plt_slice, &[8]Inst{ | 8522 | @memcpy(plt_slice, &[8]Inst{ |
| 8128 | // sethi (. - .plt[0]), %g1 | 8523 | // sethi (. - .plt[0]), %g1 |
| 8129 | .{ .imm22 = .{ .imm = @truncate(got_plt_offset), .op = 0b0000000011 } }, | 8524 | .{ .imm22 = .{ .imm = @truncate(got_plt_offset), .op = 0b0000001100 } }, |
| 8130 | // ba,a %xcc, .plt[1] | 8525 | // ba,a %xcc, .plt[1] |
| 8131 | .{ .disp19 = .{ .disp = @truncate((got_plt_offset + 4 - 32) >> 2), .op = 0b1100001101000 } }, | 8526 | .{ .disp19 = .{ .disp = @truncate((got_plt_offset + 4 - 32) >> 2), .op = 0b0011000001101 } }, |
| 8132 | // nop | 8527 | // nop |
| 8133 | .{ .raw = 0x0100_0000 }, | 8528 | .{ .raw = 0x0100_0000 }, |
| 8134 | // nop | 8529 | // nop |
| ... | @@ -8142,6 +8537,9 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void | ... | @@ -8142,6 +8537,9 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 8142 | // nop | 8537 | // nop |
| 8143 | .{ .raw = 0x0100_0000 }, | 8538 | .{ .raw = 0x0100_0000 }, |
| 8144 | }); | 8539 | }); |
| | 8540 | if (elf.targetEndian() != std.lang.Endian.native) { |
| | 8541 | std.mem.byteSwapAllElements(Inst, plt_slice); |
| | 8542 | } |
| 8145 | }, | 8543 | }, |
| 8146 | } | 8544 | } |
| 8147 | }, | 8545 | }, |
| ... | @@ -8212,6 +8610,13 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad | ... | @@ -8212,6 +8610,13 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 8212 | .LOONGARCH => { | 8610 | .LOONGARCH => { |
| 8213 | switch (which) { | 8611 | switch (which) { |
| 8214 | .plt => { | 8612 | .plt => { |
| | 8613 | // Re-apply all PLT relocations. If a symbol is in the PLT then the majority of |
| | 8614 | // its relocations are probably going through the PLT, so we don't bother with |
| | 8615 | // specific tracking for PLT relocations---instead just re-apply all relocations |
| | 8616 | // targeting symbols with PLT entries. |
| | 8617 | for (elf.plt.keys()) |name| { |
| | 8618 | Symbol.Id.global(name).applyTargetRelocs(elf); |
| | 8619 | } |
| 8215 | // We also need to update all of the references from `.plt` to `.got.plt`. | 8620 | // We also need to update all of the references from `.plt` to `.got.plt`. |
| 8216 | // However, if there's also a flush pending for `.got.plt`, don't bother doing | 8621 | // However, if there's also a flush pending for `.got.plt`, don't bother doing |
| 8217 | // this now, because we'll do it when `.got.plt` is flushed anyway. | 8622 | // this now, because we'll do it when `.got.plt` is flushed anyway. |
| ... | @@ -8272,6 +8677,13 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad | ... | @@ -8272,6 +8677,13 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad |
| 8272 | }, | 8677 | }, |
| 8273 | .SPARCV9 => switch (which) { | 8678 | .SPARCV9 => switch (which) { |
| 8274 | .plt => { | 8679 | .plt => { |
| | 8680 | // Re-apply all PLT relocations. If a symbol is in the PLT then the majority of |
| | 8681 | // its relocations are probably going through the PLT, so we don't bother with |
| | 8682 | // specific tracking for PLT relocations---instead just re-apply all relocations |
| | 8683 | // targeting symbols with PLT entries. |
| | 8684 | for (elf.plt.keys()) |name| { |
| | 8685 | Symbol.Id.global(name).applyTargetRelocs(elf); |
| | 8686 | } |
| 8275 | // Update the offsets of the relocation entries in `.rela.plt`. | 8687 | // Update the offsets of the relocation entries in `.rela.plt`. |
| 8276 | const rela_plt_shndx = elf.shndx.rela_plt; | 8688 | const rela_plt_shndx = elf.shndx.rela_plt; |
| 8277 | for (0..elf.plt.count()) |plt_index| { | 8689 | for (0..elf.plt.count()) |plt_index| { |
| ... | @@ -8315,31 +8727,31 @@ fn updateExportInner( | ... | @@ -8315,31 +8727,31 @@ fn updateExportInner( |
| 8315 | }), | 8727 | }), |
| 8316 | } | 8728 | } |
| 8317 | try elf.ensureUnusedSymbolCapacity(1, .maybe_global); | 8729 | try elf.ensureUnusedSymbolCapacity(1, .maybe_global); |
| 8318 | const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (@"export".exported) { | 8730 | const exported_lsi: Symbol.LocalIndex = switch (@"export".exported) { |
| 8319 | .nav => |nav| .{ | 8731 | .nav => |nav| (try elf.navMapIndex(zcu, nav)).symbol(elf), |
| 8320 | (try elf.navMapIndex(zcu, nav)).symbol(elf), | 8732 | .uav => |uav| (try elf.uavMapIndex(uav, .none)).symbol(elf), |
| 8321 | elf.navType(ip.getNav(nav).resolved.?), | | |
| 8322 | }, | | |
| 8323 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, | | |
| 8324 | }; | 8733 | }; |
| 8325 | | 8734 | |
| 8326 | try elf.ensureElfNodeSize(); | 8735 | try elf.ensureElfNodeSize(); |
| 8327 | while (try elf.idle(pt.tid)) {} | | |
| 8328 | | 8736 | |
| 8329 | const value: u64 = Symbol.Id.local(exported_lsi).value(elf); | 8737 | // Initialize the global symbol with the same values that the local one currently has. If the |
| 8330 | const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { | 8738 | // NAV/UAV is updated, then `updateNavInner` or `genUav` will update the global symbol sizes, |
| | 8739 | // and `flushMoved` will update their values. |
| | 8740 | const cur_value: u64, const cur_size: u64, const @"type": std.elf.STT, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { |
| 8331 | inline else => |exported_sym| .{ | 8741 | inline else => |exported_sym| .{ |
| | 8742 | elf.targetLoad(&exported_sym.value), |
| 8332 | elf.targetLoad(&exported_sym.size), | 8743 | elf.targetLoad(&exported_sym.size), |
| | 8744 | elf.targetLoad(&exported_sym.info).type, |
| 8333 | .fromSection(elf.targetLoad(&exported_sym.shndx)), | 8745 | .fromSection(elf.targetLoad(&exported_sym.shndx)), |
| 8334 | }, | 8746 | }, |
| 8335 | }; | 8747 | }; |
| 8336 | | 8748 | |
| 8337 | const name = @"export".opts.name.toSlice(ip); | 8749 | const name = @"export".opts.name.toSlice(ip); |
| 8338 | _ = elf.addGlobalSymbolAssumeCapacity(.{ | 8750 | _ = elf.addGlobalSymbolAssumeCapacity(.{ |
| 8339 | .node = .none, | 8751 | .node = exported_lsi.index().ptr(elf).node, |
| 8340 | .name = try .string(elf, name), | 8752 | .name = try .string(elf, name), |
| 8341 | .value = value, | 8753 | .value = cur_value, |
| 8342 | .size = @intCast(size), | 8754 | .size = cur_size, |
| 8343 | .type = @"type", | 8755 | .type = @"type", |
| 8344 | .bind = switch (@"export".opts.linkage) { | 8756 | .bind = switch (@"export".opts.linkage) { |
| 8345 | .strong => .strong, | 8757 | .strong => .strong, |
| ... | @@ -8501,6 +8913,46 @@ pub fn printNode( | ... | @@ -8501,6 +8913,46 @@ pub fn printNode( |
| 8501 | } | 8913 | } |
| 8502 | } | 8914 | } |
| 8503 | | 8915 | |
| | 8916 | fn ensureSegmentAligned(elf: *Elf, start_phndx: u32, min_align: std.mem.Alignment) Error!void { |
| | 8917 | const gpa = elf.base.comp.gpa; |
| | 8918 | // We need to loop through parent nodes because segments may be nested (e.g. a PT_TLS segment |
| | 8919 | // inside a PT_LOAD segment). |
| | 8920 | var phndx = start_phndx; |
| | 8921 | while (true) { |
| | 8922 | // Align the actual node |
| | 8923 | const seg_ni = elf.phdrs.items[phndx]; |
| | 8924 | if (min_align.compare(.gt, seg_ni.alignment(&elf.mf))) { |
| | 8925 | try seg_ni.realign(&elf.mf, gpa, min_align, .{}); |
| | 8926 | } |
| | 8927 | // Update the phdr `@"align"` field if necessary |
| | 8928 | switch (elf.phdrSlice()) { |
| | 8929 | inline else => |phdr| switch (elf.targetLoad(&phdr[phndx].type)) { |
| | 8930 | .NULL, .LOAD => { |
| | 8931 | // The `@"align"` field is managed by `allocateSegmentLoadAddress`. |
| | 8932 | // |
| | 8933 | // It's very likely that the node was moved and/or resized when we realigned it |
| | 8934 | // just above, but it is possible that it was not moved *but* still has an |
| | 8935 | // unaligned virtual address. In that case, we need to ensure the segment's |
| | 8936 | // virtual address range will be recomputed. |
| | 8937 | if (!min_align.check(@intCast(elf.targetLoad(&phdr[phndx].vaddr)))) { |
| | 8938 | try seg_ni.moved(gpa, &elf.mf); |
| | 8939 | } |
| | 8940 | }, |
| | 8941 | else => elf.targetStore(&phdr[phndx].@"align", @intCast(@max( |
| | 8942 | elf.targetLoad(&phdr[phndx].@"align"), |
| | 8943 | min_align.toByteUnits(), |
| | 8944 | ))), |
| | 8945 | }, |
| | 8946 | } |
| | 8947 | // Continue on to the parent segment, if any |
| | 8948 | switch (elf.getNode(seg_ni.parent(&elf.mf))) { |
| | 8949 | .segment => |parent_phndx| phndx = parent_phndx, |
| | 8950 | .elf => return, |
| | 8951 | else => unreachable, |
| | 8952 | } |
| | 8953 | } |
| | 8954 | } |
| | 8955 | |
| 8504 | /// Must be called deterministically after any call to `MappedFile.Node.Index.resize` | 8956 | /// Must be called deterministically after any call to `MappedFile.Node.Index.resize` |
| 8505 | /// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`. | 8957 | /// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`. |
| 8506 | fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void { | 8958 | fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void { |