| author | |
| committer | |
| log | d1446565a1449d1f79edb848bbd8db21ce05c70b |
| tree | b3f846e70f76ca2699bc6e38897e244f0e759d5d |
| parent | 04a8f217c651f56a2e185d87dd40c0a87ee78bc5 |
6 files changed, 2189 insertions(+), 407 deletions(-)
CMakeLists.txt+1| ... | @@ -591,6 +591,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -591,6 +591,7 @@ set(ZIG_STAGE2_SOURCES |
| 591 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Atom.zig" | 591 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Atom.zig" |
| 592 | "${CMAKE_SOURCE_DIR}/src/link/Elf/LinkerDefined.zig" | 592 | "${CMAKE_SOURCE_DIR}/src/link/Elf/LinkerDefined.zig" |
| 593 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig" | 593 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig" |
| 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig" | ||
| 594 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig" | 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig" |
| 595 | "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig" | 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig" |
| 596 | "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig" | 597 | "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig" |
src/link/Elf.zig+582-65| ... | @@ -14,6 +14,7 @@ files: std.MultiArrayList(File.Entry) = .{}, | ... | @@ -14,6 +14,7 @@ files: std.MultiArrayList(File.Entry) = .{}, |
| 14 | zig_module_index: ?File.Index = null, | 14 | zig_module_index: ?File.Index = null, |
| 15 | linker_defined_index: ?File.Index = null, | 15 | linker_defined_index: ?File.Index = null, |
| 16 | objects: std.ArrayListUnmanaged(File.Index) = .{}, | 16 | objects: std.ArrayListUnmanaged(File.Index) = .{}, |
| 17 | shared_objects: std.ArrayListUnmanaged(File.Index) = .{}, | ||
| 17 | 18 | ||
| 18 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. | 19 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. |
| 19 | /// Same order as in the file. | 20 | /// Same order as in the file. |
| ... | @@ -61,10 +62,34 @@ default_sym_version: elf.Elf64_Versym, | ... | @@ -61,10 +62,34 @@ default_sym_version: elf.Elf64_Versym, |
| 61 | shstrtab: StringTable(.strtab) = .{}, | 62 | shstrtab: StringTable(.strtab) = .{}, |
| 62 | /// .strtab buffer | 63 | /// .strtab buffer |
| 63 | strtab: StringTable(.strtab) = .{}, | 64 | strtab: StringTable(.strtab) = .{}, |
| 64 | 65 | /// Dynamic symbol table. Only populated and emitted when linking dynamically. | |
| 65 | /// Representation of the GOT table as committed to the file. | 66 | dynsym: DynsymSection = .{}, |
| 67 | /// .dynstrtab buffer | ||
| 68 | dynstrtab: StringTable(.dynstrtab) = .{}, | ||
| 69 | /// Version symbol table. Only populated and emitted when linking dynamically. | ||
| 70 | versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, | ||
| 71 | /// .verneed section | ||
| 72 | verneed: VerneedSection = .{}, | ||
| 73 | /// .got section | ||
| 66 | got: GotSection = .{}, | 74 | got: GotSection = .{}, |
| 75 | /// .rela.dyn section | ||
| 67 | rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | 76 | rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 77 | /// .dynamic section | ||
| 78 | dynamic: DynamicSection = .{}, | ||
| 79 | /// .hash section | ||
| 80 | hash: HashSection = .{}, | ||
| 81 | /// .gnu.hash section | ||
| 82 | gnu_hash: GnuHashSection = .{}, | ||
| 83 | /// .plt section | ||
| 84 | plt: PltSection = .{}, | ||
| 85 | /// .got.plt section | ||
| 86 | got_plt: GotPltSection = .{}, | ||
| 87 | /// .plt.got section | ||
| 88 | plt_got: PltGotSection = .{}, | ||
| 89 | /// .copyrel section | ||
| 90 | copy_rel: CopyRelSection = .{}, | ||
| 91 | /// .rela.plt section | ||
| 92 | rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, | ||
| 68 | 93 | ||
| 69 | /// Tracked section headers | 94 | /// Tracked section headers |
| 70 | text_section_index: ?u16 = null, | 95 | text_section_index: ?u16 = null, |
| ... | @@ -73,18 +98,30 @@ data_section_index: ?u16 = null, | ... | @@ -73,18 +98,30 @@ data_section_index: ?u16 = null, |
| 73 | bss_section_index: ?u16 = null, | 98 | bss_section_index: ?u16 = null, |
| 74 | tdata_section_index: ?u16 = null, | 99 | tdata_section_index: ?u16 = null, |
| 75 | tbss_section_index: ?u16 = null, | 100 | tbss_section_index: ?u16 = null, |
| 101 | debug_info_section_index: ?u16 = null, | ||
| 102 | debug_abbrev_section_index: ?u16 = null, | ||
| 103 | debug_str_section_index: ?u16 = null, | ||
| 104 | debug_aranges_section_index: ?u16 = null, | ||
| 105 | debug_line_section_index: ?u16 = null, | ||
| 106 | |||
| 107 | copy_rel_section_index: ?u16 = null, | ||
| 108 | dynamic_section_index: ?u16 = null, | ||
| 109 | dynstrtab_section_index: ?u16 = null, | ||
| 110 | dynsymtab_section_index: ?u16 = null, | ||
| 76 | eh_frame_section_index: ?u16 = null, | 111 | eh_frame_section_index: ?u16 = null, |
| 77 | eh_frame_hdr_section_index: ?u16 = null, | 112 | eh_frame_hdr_section_index: ?u16 = null, |
| 78 | dynamic_section_index: ?u16 = null, | 113 | hash_section_index: ?u16 = null, |
| 114 | gnu_hash_section_index: ?u16 = null, | ||
| 79 | got_section_index: ?u16 = null, | 115 | got_section_index: ?u16 = null, |
| 80 | got_plt_section_index: ?u16 = null, | 116 | got_plt_section_index: ?u16 = null, |
| 117 | interp_section_index: ?u16 = null, | ||
| 81 | plt_section_index: ?u16 = null, | 118 | plt_section_index: ?u16 = null, |
| 119 | plt_got_section_index: ?u16 = null, | ||
| 82 | rela_dyn_section_index: ?u16 = null, | 120 | rela_dyn_section_index: ?u16 = null, |
| 83 | debug_info_section_index: ?u16 = null, | 121 | rela_plt_section_index: ?u16 = null, |
| 84 | debug_abbrev_section_index: ?u16 = null, | 122 | versym_section_index: ?u16 = null, |
| 85 | debug_str_section_index: ?u16 = null, | 123 | verneed_section_index: ?u16 = null, |
| 86 | debug_aranges_section_index: ?u16 = null, | 124 | |
| 87 | debug_line_section_index: ?u16 = null, | ||
| 88 | shstrtab_section_index: ?u16 = null, | 125 | shstrtab_section_index: ?u16 = null, |
| 89 | strtab_section_index: ?u16 = null, | 126 | strtab_section_index: ?u16 = null, |
| 90 | symtab_section_index: ?u16 = null, | 127 | symtab_section_index: ?u16 = null, |
| ... | @@ -316,10 +353,11 @@ pub fn deinit(self: *Elf) void { | ... | @@ -316,10 +353,11 @@ pub fn deinit(self: *Elf) void { |
| 316 | .zig_module => data.zig_module.deinit(gpa), | 353 | .zig_module => data.zig_module.deinit(gpa), |
| 317 | .linker_defined => data.linker_defined.deinit(gpa), | 354 | .linker_defined => data.linker_defined.deinit(gpa), |
| 318 | .object => data.object.deinit(gpa), | 355 | .object => data.object.deinit(gpa), |
| 319 | // .shared_object => data.shared_object.deinit(gpa), | 356 | .shared_object => data.shared_object.deinit(gpa), |
| 320 | }; | 357 | }; |
| 321 | self.files.deinit(gpa); | 358 | self.files.deinit(gpa); |
| 322 | self.objects.deinit(gpa); | 359 | self.objects.deinit(gpa); |
| 360 | self.shared_objects.deinit(gpa); | ||
| 323 | 361 | ||
| 324 | self.shdrs.deinit(gpa); | 362 | self.shdrs.deinit(gpa); |
| 325 | self.phdr_to_shdr_table.deinit(gpa); | 363 | self.phdr_to_shdr_table.deinit(gpa); |
| ... | @@ -333,7 +371,6 @@ pub fn deinit(self: *Elf) void { | ... | @@ -333,7 +371,6 @@ pub fn deinit(self: *Elf) void { |
| 333 | self.symbols.deinit(gpa); | 371 | self.symbols.deinit(gpa); |
| 334 | self.symbols_extra.deinit(gpa); | 372 | self.symbols_extra.deinit(gpa); |
| 335 | self.symbols_free_list.deinit(gpa); | 373 | self.symbols_free_list.deinit(gpa); |
| 336 | self.got.deinit(gpa); | ||
| 337 | self.resolver.deinit(gpa); | 374 | self.resolver.deinit(gpa); |
| 338 | self.start_stop_indexes.deinit(gpa); | 375 | self.start_stop_indexes.deinit(gpa); |
| 339 | 376 | ||
| ... | @@ -369,7 +406,19 @@ pub fn deinit(self: *Elf) void { | ... | @@ -369,7 +406,19 @@ pub fn deinit(self: *Elf) void { |
| 369 | self.comdat_groups.deinit(gpa); | 406 | self.comdat_groups.deinit(gpa); |
| 370 | self.comdat_groups_owners.deinit(gpa); | 407 | self.comdat_groups_owners.deinit(gpa); |
| 371 | self.comdat_groups_table.deinit(gpa); | 408 | self.comdat_groups_table.deinit(gpa); |
| 409 | |||
| 410 | self.got.deinit(gpa); | ||
| 411 | self.plt.deinit(gpa); | ||
| 412 | self.plt_got.deinit(gpa); | ||
| 413 | self.dynsym.deinit(gpa); | ||
| 414 | self.dynstrtab.deinit(gpa); | ||
| 415 | self.dynamic.deinit(gpa); | ||
| 416 | self.hash.deinit(gpa); | ||
| 417 | self.versym.deinit(gpa); | ||
| 418 | self.verneed.deinit(gpa); | ||
| 419 | self.copy_rel.deinit(gpa); | ||
| 372 | self.rela_dyn.deinit(gpa); | 420 | self.rela_dyn.deinit(gpa); |
| 421 | self.rela_plt.deinit(gpa); | ||
| 373 | } | 422 | } |
| 374 | 423 | ||
| 375 | pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { | 424 | pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { |
| ... | @@ -1268,6 +1317,24 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1268,6 +1317,24 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1268 | try dw.flushModule(self.base.options.module.?); | 1317 | try dw.flushModule(self.base.options.module.?); |
| 1269 | } | 1318 | } |
| 1270 | 1319 | ||
| 1320 | // Dedup shared objects | ||
| 1321 | { | ||
| 1322 | var seen_dsos = std.StringHashMap(void).init(gpa); | ||
| 1323 | defer seen_dsos.deinit(); | ||
| 1324 | try seen_dsos.ensureTotalCapacity(@as(u32, @intCast(self.shared_objects.items.len))); | ||
| 1325 | |||
| 1326 | var i: usize = 0; | ||
| 1327 | while (i < self.shared_objects.items.len) { | ||
| 1328 | const index = self.shared_objects.items[i]; | ||
| 1329 | const shared_object = self.file(index).?.shared_object; | ||
| 1330 | const soname = shared_object.soname(); | ||
| 1331 | const gop = seen_dsos.getOrPutAssumeCapacity(soname); | ||
| 1332 | if (gop.found_existing) { | ||
| 1333 | _ = self.shared_objects.orderedRemove(i); | ||
| 1334 | } else i += 1; | ||
| 1335 | } | ||
| 1336 | } | ||
| 1337 | |||
| 1271 | // If we haven't already, create a linker-generated input file comprising of | 1338 | // If we haven't already, create a linker-generated input file comprising of |
| 1272 | // linker-defined synthetic symbols only such as `_DYNAMIC`, etc. | 1339 | // linker-defined synthetic symbols only such as `_DYNAMIC`, etc. |
| 1273 | if (self.linker_defined_index == null) { | 1340 | if (self.linker_defined_index == null) { |
| ... | @@ -1677,6 +1744,7 @@ fn resolveSymbols(self: *Elf) void { | ... | @@ -1677,6 +1744,7 @@ fn resolveSymbols(self: *Elf) void { |
| 1677 | if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); | 1744 | if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); |
| 1678 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). | 1745 | // Resolve symbols on the set of all objects and shared objects (even if some are unneeded). |
| 1679 | for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); | 1746 | for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); |
| 1747 | for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); | ||
| 1680 | 1748 | ||
| 1681 | // Mark live objects. | 1749 | // Mark live objects. |
| 1682 | self.markLive(); | 1750 | self.markLive(); |
| ... | @@ -1684,6 +1752,7 @@ fn resolveSymbols(self: *Elf) void { | ... | @@ -1684,6 +1752,7 @@ fn resolveSymbols(self: *Elf) void { |
| 1684 | // Reset state of all globals after marking live objects. | 1752 | // Reset state of all globals after marking live objects. |
| 1685 | if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self); | 1753 | if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self); |
| 1686 | for (self.objects.items) |index| self.file(index).?.resetGlobals(self); | 1754 | for (self.objects.items) |index| self.file(index).?.resetGlobals(self); |
| 1755 | for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self); | ||
| 1687 | 1756 | ||
| 1688 | // Prune dead objects and shared objects. | 1757 | // Prune dead objects and shared objects. |
| 1689 | var i: usize = 0; | 1758 | var i: usize = 0; |
| ... | @@ -1693,6 +1762,13 @@ fn resolveSymbols(self: *Elf) void { | ... | @@ -1693,6 +1762,13 @@ fn resolveSymbols(self: *Elf) void { |
| 1693 | _ = self.objects.orderedRemove(i); | 1762 | _ = self.objects.orderedRemove(i); |
| 1694 | } else i += 1; | 1763 | } else i += 1; |
| 1695 | } | 1764 | } |
| 1765 | i = 0; | ||
| 1766 | while (i < self.shared_objects.items.len) { | ||
| 1767 | const index = self.shared_objects.items[i]; | ||
| 1768 | if (!self.file(index).?.isAlive()) { | ||
| 1769 | _ = self.shared_objects.orderedRemove(i); | ||
| 1770 | } else i += 1; | ||
| 1771 | } | ||
| 1696 | 1772 | ||
| 1697 | // Dedup comdat groups. | 1773 | // Dedup comdat groups. |
| 1698 | for (self.objects.items) |index| { | 1774 | for (self.objects.items) |index| { |
| ... | @@ -1728,6 +1804,7 @@ fn resolveSymbols(self: *Elf) void { | ... | @@ -1728,6 +1804,7 @@ fn resolveSymbols(self: *Elf) void { |
| 1728 | // Re-resolve the symbols. | 1804 | // Re-resolve the symbols. |
| 1729 | if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); | 1805 | if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self); |
| 1730 | for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); | 1806 | for (self.objects.items) |index| self.file(index).?.resolveSymbols(self); |
| 1807 | for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self); | ||
| 1731 | } | 1808 | } |
| 1732 | 1809 | ||
| 1733 | /// Traverses all objects and shared objects marking any object referenced by | 1810 | /// Traverses all objects and shared objects marking any object referenced by |
| ... | @@ -1740,6 +1817,10 @@ fn markLive(self: *Elf) void { | ... | @@ -1740,6 +1817,10 @@ fn markLive(self: *Elf) void { |
| 1740 | const file_ptr = self.file(index).?; | 1817 | const file_ptr = self.file(index).?; |
| 1741 | if (file_ptr.isAlive()) file_ptr.markLive(self); | 1818 | if (file_ptr.isAlive()) file_ptr.markLive(self); |
| 1742 | } | 1819 | } |
| 1820 | for (self.shared_objects.items) |index| { | ||
| 1821 | const file_ptr = self.file(index).?; | ||
| 1822 | if (file_ptr.isAlive()) file_ptr.markLive(self); | ||
| 1823 | } | ||
| 1743 | } | 1824 | } |
| 1744 | 1825 | ||
| 1745 | fn markEhFrameAtomsDead(self: *Elf) void { | 1826 | fn markEhFrameAtomsDead(self: *Elf) void { |
| ... | @@ -1759,10 +1840,10 @@ fn markImportsExports(self: *Elf) void { | ... | @@ -1759,10 +1840,10 @@ fn markImportsExports(self: *Elf) void { |
| 1759 | const file_ptr = global.file(elf_file) orelse continue; | 1840 | const file_ptr = global.file(elf_file) orelse continue; |
| 1760 | const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other)); | 1841 | const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other)); |
| 1761 | if (vis == .HIDDEN) continue; | 1842 | if (vis == .HIDDEN) continue; |
| 1762 | // if (file == .shared and !global.isAbs(self)) { | 1843 | if (file_ptr == .shared_object and !global.isAbs(elf_file)) { |
| 1763 | // global.flags.import = true; | 1844 | global.flags.import = true; |
| 1764 | // continue; | 1845 | continue; |
| 1765 | // } | 1846 | } |
| 1766 | if (file_ptr.index() == file_index) { | 1847 | if (file_ptr.index() == file_index) { |
| 1767 | global.flags.@"export" = true; | 1848 | global.flags.@"export" = true; |
| 1768 | if (elf_file.isDynLib() and vis != .PROTECTED) { | 1849 | if (elf_file.isDynLib() and vis != .PROTECTED) { |
| ... | @@ -1773,6 +1854,17 @@ fn markImportsExports(self: *Elf) void { | ... | @@ -1773,6 +1854,17 @@ fn markImportsExports(self: *Elf) void { |
| 1773 | } | 1854 | } |
| 1774 | }.mark; | 1855 | }.mark; |
| 1775 | 1856 | ||
| 1857 | if (!self.isDynLib()) { | ||
| 1858 | for (self.shared_objects.items) |index| { | ||
| 1859 | for (self.file(index).?.globals()) |global_index| { | ||
| 1860 | const global = self.symbol(global_index); | ||
| 1861 | const file_ptr = global.file(self) orelse continue; | ||
| 1862 | const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other)); | ||
| 1863 | if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true; | ||
| 1864 | } | ||
| 1865 | } | ||
| 1866 | } | ||
| 1867 | |||
| 1776 | if (self.zig_module_index) |index| { | 1868 | if (self.zig_module_index) |index| { |
| 1777 | mark(self, index); | 1869 | mark(self, index); |
| 1778 | } | 1870 | } |
| ... | @@ -1820,12 +1912,51 @@ fn scanRelocs(self: *Elf) !void { | ... | @@ -1820,12 +1912,51 @@ fn scanRelocs(self: *Elf) !void { |
| 1820 | 1912 | ||
| 1821 | try self.reportUndefined(&undefs); | 1913 | try self.reportUndefined(&undefs); |
| 1822 | 1914 | ||
| 1823 | for (self.symbols.items, 0..) |*sym, sym_index| { | 1915 | for (self.symbols.items, 0..) |*sym, i| { |
| 1916 | const index = @as(u32, @intCast(i)); | ||
| 1917 | if (!sym.isLocal() and !sym.flags.has_dynamic) { | ||
| 1918 | log.debug("'{s}' is non-local", .{sym.name(self)}); | ||
| 1919 | try self.dynsym.addSymbol(index, self); | ||
| 1920 | } | ||
| 1824 | if (sym.flags.needs_got) { | 1921 | if (sym.flags.needs_got) { |
| 1825 | log.debug("'{s}' needs GOT", .{sym.name(self)}); | 1922 | log.debug("'{s}' needs GOT", .{sym.name(self)}); |
| 1826 | _ = try self.got.addGotSymbol(@intCast(sym_index), self); | 1923 | _ = try self.got.addGotSymbol(index, self); |
| 1827 | sym.flags.has_got = true; | 1924 | } |
| 1925 | if (sym.flags.needs_plt) { | ||
| 1926 | if (sym.flags.is_canonical) { | ||
| 1927 | log.debug("'{s}' needs CPLT", .{sym.name(self)}); | ||
| 1928 | sym.flags.@"export" = true; | ||
| 1929 | try self.plt.addSymbol(index, self); | ||
| 1930 | } else if (sym.flags.needs_got) { | ||
| 1931 | log.debug("'{s}' needs PLTGOT", .{sym.name(self)}); | ||
| 1932 | try self.plt_got.addSymbol(index, self); | ||
| 1933 | } else { | ||
| 1934 | log.debug("'{s}' needs PLT", .{sym.name(self)}); | ||
| 1935 | try self.plt.addSymbol(index, self); | ||
| 1936 | } | ||
| 1937 | } | ||
| 1938 | if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) { | ||
| 1939 | log.debug("'{s}' needs COPYREL", .{sym.name(self)}); | ||
| 1940 | try self.copy_rel.addSymbol(index, self); | ||
| 1941 | } | ||
| 1942 | if (sym.flags.needs_tlsgd) { | ||
| 1943 | log.debug("'{s}' needs TLSGD", .{sym.name(self)}); | ||
| 1944 | try self.got.addTlsGdSymbol(index, self); | ||
| 1828 | } | 1945 | } |
| 1946 | if (sym.flags.needs_gottp) { | ||
| 1947 | log.debug("'{s}' needs GOTTP", .{sym.name(self)}); | ||
| 1948 | try self.got.addGotTpSymbol(index, self); | ||
| 1949 | } | ||
| 1950 | if (sym.flags.needs_tlsdesc) { | ||
| 1951 | log.debug("'{s}' needs TLSDESC", .{sym.name(self)}); | ||
| 1952 | try self.dynsym.addSymbol(index, self); | ||
| 1953 | try self.got.addTlsDescSymbol(index, self); | ||
| 1954 | } | ||
| 1955 | } | ||
| 1956 | |||
| 1957 | if (self.got.flags.needs_tlsld) { | ||
| 1958 | log.debug("program needs TLSLD", .{}); | ||
| 1959 | try self.got.addTlsLdSymbol(self); | ||
| 1829 | } | 1960 | } |
| 1830 | } | 1961 | } |
| 1831 | 1962 | ||
| ... | @@ -2567,12 +2698,12 @@ fn writeHeader(self: *Elf) !void { | ... | @@ -2567,12 +2698,12 @@ fn writeHeader(self: *Elf) !void { |
| 2567 | 2698 | ||
| 2568 | assert(index == 16); | 2699 | assert(index == 16); |
| 2569 | 2700 | ||
| 2570 | const elf_type = switch (self.base.options.effectiveOutputMode()) { | 2701 | const elf_type: elf.ET = switch (self.base.options.effectiveOutputMode()) { |
| 2571 | .Exe => elf.ET.EXEC, | 2702 | .Exe => if (self.base.options.pic) .DYN else .EXEC, |
| 2572 | .Obj => elf.ET.REL, | 2703 | .Obj => .REL, |
| 2573 | .Lib => switch (self.base.options.link_mode) { | 2704 | .Lib => switch (self.base.options.link_mode) { |
| 2574 | .Static => elf.ET.REL, | 2705 | .Static => @as(elf.ET, .REL), |
| 2575 | .Dynamic => elf.ET.DYN, | 2706 | .Dynamic => .DYN, |
| 2576 | }, | 2707 | }, |
| 2577 | }; | 2708 | }; |
| 2578 | mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian); | 2709 | mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian); |
| ... | @@ -2819,8 +2950,8 @@ fn updateDeclCode( | ... | @@ -2819,8 +2950,8 @@ fn updateDeclCode( |
| 2819 | esym.st_value = atom_ptr.value; | 2950 | esym.st_value = atom_ptr.value; |
| 2820 | 2951 | ||
| 2821 | log.debug(" (writing new offset table entry)", .{}); | 2952 | log.debug(" (writing new offset table entry)", .{}); |
| 2822 | const extra = sym.extra(self).?; | 2953 | // const extra = sym.extra(self).?; |
| 2823 | try self.got.writeEntry(self, extra.got); | 2954 | // try self.got.writeEntry(self, extra.got); |
| 2824 | } | 2955 | } |
| 2825 | } else if (code.len < old_size) { | 2956 | } else if (code.len < old_size) { |
| 2826 | atom_ptr.shrink(self); | 2957 | atom_ptr.shrink(self); |
| ... | @@ -2834,7 +2965,8 @@ fn updateDeclCode( | ... | @@ -2834,7 +2965,8 @@ fn updateDeclCode( |
| 2834 | 2965 | ||
| 2835 | sym.flags.needs_got = true; | 2966 | sym.flags.needs_got = true; |
| 2836 | const gop = try sym.getOrCreateGotEntry(sym_index, self); | 2967 | const gop = try sym.getOrCreateGotEntry(sym_index, self); |
| 2837 | try self.got.writeEntry(self, gop.index); | 2968 | _ = gop; |
| 2969 | // try self.got.writeEntry(self, gop.index); | ||
| 2838 | } | 2970 | } |
| 2839 | 2971 | ||
| 2840 | if (self.base.child_pid) |pid| { | 2972 | if (self.base.child_pid) |pid| { |
| ... | @@ -3070,7 +3202,8 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. | ... | @@ -3070,7 +3202,8 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 3070 | 3202 | ||
| 3071 | local_sym.flags.needs_got = true; | 3203 | local_sym.flags.needs_got = true; |
| 3072 | const gop = try local_sym.getOrCreateGotEntry(symbol_index, self); | 3204 | const gop = try local_sym.getOrCreateGotEntry(symbol_index, self); |
| 3073 | try self.got.writeEntry(self, gop.index); | 3205 | _ = gop; |
| 3206 | // try self.got.writeEntry(self, gop.index); | ||
| 3074 | 3207 | ||
| 3075 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; | 3208 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; |
| 3076 | const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset; | 3209 | const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset; |
| ... | @@ -3480,13 +3613,145 @@ fn initSections(self: *Elf) !void { | ... | @@ -3480,13 +3613,145 @@ fn initSections(self: *Elf) !void { |
| 3480 | } | 3613 | } |
| 3481 | } | 3614 | } |
| 3482 | 3615 | ||
| 3483 | if (self.got.entries.items.len > 0 and self.got_section_index == null) { | 3616 | if (self.got.entries.items.len > 0) { |
| 3484 | self.got_section_index = try self.addSection(.{ | 3617 | self.got_section_index = try self.addSection(.{ |
| 3485 | .name = ".got", | 3618 | .name = ".got", |
| 3486 | .type = elf.SHT_PROGBITS, | 3619 | .type = elf.SHT_PROGBITS, |
| 3487 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | 3620 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, |
| 3488 | .addralign = ptr_size, | 3621 | .addralign = ptr_size, |
| 3489 | }); | 3622 | }); |
| 3623 | self.got_plt_section_index = try self.addSection(.{ | ||
| 3624 | .name = ".got.plt", | ||
| 3625 | .type = elf.SHT_PROGBITS, | ||
| 3626 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | ||
| 3627 | .addralign = @alignOf(u64), | ||
| 3628 | }); | ||
| 3629 | } | ||
| 3630 | |||
| 3631 | const needs_rela_dyn = blk: { | ||
| 3632 | if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or | ||
| 3633 | self.copy_rel.symbols.items.len > 0) break :blk true; | ||
| 3634 | for (self.objects.items) |index| { | ||
| 3635 | if (self.file(index).?.object.num_dynrelocs > 0) break :blk true; | ||
| 3636 | } | ||
| 3637 | break :blk false; | ||
| 3638 | }; | ||
| 3639 | if (needs_rela_dyn) { | ||
| 3640 | self.rela_dyn_section_index = try self.addSection(.{ | ||
| 3641 | .name = ".rela.dyn", | ||
| 3642 | .type = elf.SHT_RELA, | ||
| 3643 | .flags = elf.SHF_ALLOC, | ||
| 3644 | .addralign = @alignOf(elf.Elf64_Rela), | ||
| 3645 | .entsize = @sizeOf(elf.Elf64_Rela), | ||
| 3646 | }); | ||
| 3647 | } | ||
| 3648 | |||
| 3649 | if (self.plt.symbols.items.len > 0) { | ||
| 3650 | self.plt_section_index = try self.addSection(.{ | ||
| 3651 | .name = ".plt", | ||
| 3652 | .type = elf.SHT_PROGBITS, | ||
| 3653 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | ||
| 3654 | .addralign = 16, | ||
| 3655 | }); | ||
| 3656 | self.rela_plt_section_index = try self.addSection(.{ | ||
| 3657 | .name = ".rela.plt", | ||
| 3658 | .type = elf.SHT_RELA, | ||
| 3659 | .flags = elf.SHF_ALLOC, | ||
| 3660 | .addralign = @alignOf(elf.Elf64_Rela), | ||
| 3661 | .entsize = @sizeOf(elf.Elf64_Rela), | ||
| 3662 | }); | ||
| 3663 | } | ||
| 3664 | |||
| 3665 | if (self.plt_got.symbols.items.len > 0) { | ||
| 3666 | self.plt_got_section_index = try self.addSection(.{ | ||
| 3667 | .name = ".plt.got", | ||
| 3668 | .type = elf.SHT_PROGBITS, | ||
| 3669 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | ||
| 3670 | .addralign = 16, | ||
| 3671 | }); | ||
| 3672 | } | ||
| 3673 | |||
| 3674 | if (self.copy_rel.symbols.items.len > 0) { | ||
| 3675 | self.copy_rel_section_index = try self.addSection(.{ | ||
| 3676 | .name = ".copyrel", | ||
| 3677 | .type = elf.SHT_NOBITS, | ||
| 3678 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | ||
| 3679 | }); | ||
| 3680 | } | ||
| 3681 | |||
| 3682 | const needs_interp = blk: { | ||
| 3683 | // On Ubuntu with musl-gcc, we get a weird combo of options looking like this: | ||
| 3684 | // -dynamic-linker=<path> -static | ||
| 3685 | // In this case, if we do generate .interp section and segment, we will get | ||
| 3686 | // a segfault in the dynamic linker trying to load a binary that is static | ||
| 3687 | // and doesn't contain .dynamic section. | ||
| 3688 | if (self.isStatic() and !self.base.options.pie) break :blk false; | ||
| 3689 | break :blk self.base.options.dynamic_linker != null; | ||
| 3690 | }; | ||
| 3691 | if (needs_interp) { | ||
| 3692 | self.interp_section_index = try self.addSection(.{ | ||
| 3693 | .name = ".interp", | ||
| 3694 | .type = elf.SHT_PROGBITS, | ||
| 3695 | .flags = elf.SHF_ALLOC, | ||
| 3696 | .addralign = 1, | ||
| 3697 | }); | ||
| 3698 | } | ||
| 3699 | |||
| 3700 | if (self.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) { | ||
| 3701 | self.dynstrtab_section_index = try self.addSection(.{ | ||
| 3702 | .name = ".dynstr", | ||
| 3703 | .flags = elf.SHF_ALLOC, | ||
| 3704 | .type = elf.SHT_STRTAB, | ||
| 3705 | .entsize = 1, | ||
| 3706 | .addralign = 1, | ||
| 3707 | }); | ||
| 3708 | self.dynamic_section_index = try self.addSection(.{ | ||
| 3709 | .name = ".dynamic", | ||
| 3710 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | ||
| 3711 | .type = elf.SHT_DYNAMIC, | ||
| 3712 | .entsize = @sizeOf(elf.Elf64_Dyn), | ||
| 3713 | .addralign = @alignOf(elf.Elf64_Dyn), | ||
| 3714 | }); | ||
| 3715 | self.dynsymtab_section_index = try self.addSection(.{ | ||
| 3716 | .name = ".dynsym", | ||
| 3717 | .flags = elf.SHF_ALLOC, | ||
| 3718 | .type = elf.SHT_DYNSYM, | ||
| 3719 | .addralign = @alignOf(elf.Elf64_Sym), | ||
| 3720 | .entsize = @sizeOf(elf.Elf64_Sym), | ||
| 3721 | }); | ||
| 3722 | self.hash_section_index = try self.addSection(.{ | ||
| 3723 | .name = ".hash", | ||
| 3724 | .flags = elf.SHF_ALLOC, | ||
| 3725 | .type = elf.SHT_HASH, | ||
| 3726 | .addralign = 4, | ||
| 3727 | .entsize = 4, | ||
| 3728 | }); | ||
| 3729 | self.gnu_hash_section_index = try self.addSection(.{ | ||
| 3730 | .name = ".gnu.hash", | ||
| 3731 | .flags = elf.SHF_ALLOC, | ||
| 3732 | .type = elf.SHT_GNU_HASH, | ||
| 3733 | .addralign = 8, | ||
| 3734 | }); | ||
| 3735 | |||
| 3736 | const needs_versions = for (self.dynsym.entries.items) |entry| { | ||
| 3737 | const sym = self.symbol(entry.symbol_index); | ||
| 3738 | if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true; | ||
| 3739 | } else false; | ||
| 3740 | if (needs_versions) { | ||
| 3741 | self.versym_section_index = try self.addSection(.{ | ||
| 3742 | .name = ".gnu.version", | ||
| 3743 | .flags = elf.SHF_ALLOC, | ||
| 3744 | .type = elf.SHT_GNU_VERSYM, | ||
| 3745 | .addralign = @alignOf(elf.Elf64_Versym), | ||
| 3746 | .entsize = @sizeOf(elf.Elf64_Versym), | ||
| 3747 | }); | ||
| 3748 | self.verneed_section_index = try self.addSection(.{ | ||
| 3749 | .name = ".gnu.version_r", | ||
| 3750 | .flags = elf.SHF_ALLOC, | ||
| 3751 | .type = elf.SHT_GNU_VERNEED, | ||
| 3752 | .addralign = @alignOf(elf.Elf64_Verneed), | ||
| 3753 | }); | ||
| 3754 | } | ||
| 3490 | } | 3755 | } |
| 3491 | 3756 | ||
| 3492 | if (self.symtab_section_index == null) { | 3757 | if (self.symtab_section_index == null) { |
| ... | @@ -3665,6 +3930,20 @@ fn sortSections(self: *Elf) !void { | ... | @@ -3665,6 +3930,20 @@ fn sortSections(self: *Elf) !void { |
| 3665 | &self.symtab_section_index, | 3930 | &self.symtab_section_index, |
| 3666 | &self.strtab_section_index, | 3931 | &self.strtab_section_index, |
| 3667 | &self.shstrtab_section_index, | 3932 | &self.shstrtab_section_index, |
| 3933 | &self.interp_section_index, | ||
| 3934 | &self.dynamic_section_index, | ||
| 3935 | &self.dynsymtab_section_index, | ||
| 3936 | &self.dynstrtab_section_index, | ||
| 3937 | &self.hash_section_index, | ||
| 3938 | &self.gnu_hash_section_index, | ||
| 3939 | &self.plt_section_index, | ||
| 3940 | &self.got_plt_section_index, | ||
| 3941 | &self.plt_got_section_index, | ||
| 3942 | &self.rela_dyn_section_index, | ||
| 3943 | &self.rela_plt_section_index, | ||
| 3944 | &self.copy_rel_section_index, | ||
| 3945 | &self.versym_section_index, | ||
| 3946 | &self.verneed_section_index, | ||
| 3668 | }) |maybe_index| { | 3947 | }) |maybe_index| { |
| 3669 | if (maybe_index.*) |*index| { | 3948 | if (maybe_index.*) |*index| { |
| 3670 | index.* = backlinks[index.*]; | 3949 | index.* = backlinks[index.*]; |
| ... | @@ -3675,6 +3954,47 @@ fn sortSections(self: *Elf) !void { | ... | @@ -3675,6 +3954,47 @@ fn sortSections(self: *Elf) !void { |
| 3675 | const shdr = &self.shdrs.items[index]; | 3954 | const shdr = &self.shdrs.items[index]; |
| 3676 | shdr.sh_link = self.strtab_section_index.?; | 3955 | shdr.sh_link = self.strtab_section_index.?; |
| 3677 | } | 3956 | } |
| 3957 | |||
| 3958 | if (self.dynamic_section_index) |index| { | ||
| 3959 | const shdr = &self.shdrs.items[index]; | ||
| 3960 | shdr.sh_link = self.dynstrtab_section_index.?; | ||
| 3961 | } | ||
| 3962 | |||
| 3963 | if (self.dynsymtab_section_index) |index| { | ||
| 3964 | const shdr = &self.shdrs.items[index]; | ||
| 3965 | shdr.sh_link = self.dynstrtab_section_index.?; | ||
| 3966 | } | ||
| 3967 | |||
| 3968 | if (self.hash_section_index) |index| { | ||
| 3969 | const shdr = &self.shdrs.items[index]; | ||
| 3970 | shdr.sh_link = self.dynsymtab_section_index.?; | ||
| 3971 | } | ||
| 3972 | |||
| 3973 | if (self.gnu_hash_section_index) |index| { | ||
| 3974 | const shdr = &self.shdrs.items[index]; | ||
| 3975 | shdr.sh_link = self.dynsymtab_section_index.?; | ||
| 3976 | } | ||
| 3977 | |||
| 3978 | if (self.versym_section_index) |index| { | ||
| 3979 | const shdr = &self.shdrs.items[index]; | ||
| 3980 | shdr.sh_link = self.dynsymtab_section_index.?; | ||
| 3981 | } | ||
| 3982 | |||
| 3983 | if (self.verneed_section_index) |index| { | ||
| 3984 | const shdr = &self.shdrs.items[index]; | ||
| 3985 | shdr.sh_link = self.dynstrtab_section_index.?; | ||
| 3986 | } | ||
| 3987 | |||
| 3988 | if (self.rela_dyn_section_index) |index| { | ||
| 3989 | const shdr = &self.shdrs.items[index]; | ||
| 3990 | shdr.sh_link = self.dynsymtab_section_index orelse 0; | ||
| 3991 | } | ||
| 3992 | |||
| 3993 | if (self.rela_plt_section_index) |index| { | ||
| 3994 | const shdr = &self.shdrs.items[index]; | ||
| 3995 | shdr.sh_link = self.dynsymtab_section_index.?; | ||
| 3996 | shdr.sh_info = self.plt_section_index.?; | ||
| 3997 | } | ||
| 3678 | } | 3998 | } |
| 3679 | 3999 | ||
| 3680 | fn updateSectionSizes(self: *Elf) !void { | 4000 | fn updateSectionSizes(self: *Elf) !void { |
| ... | @@ -3683,21 +4003,77 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -3683,21 +4003,77 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3683 | } | 4003 | } |
| 3684 | 4004 | ||
| 3685 | if (self.eh_frame_section_index) |index| { | 4005 | if (self.eh_frame_section_index) |index| { |
| 3686 | const shdr = &self.shdrs.items[index]; | 4006 | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); |
| 3687 | shdr.sh_size = try eh_frame.calcEhFrameSize(self); | ||
| 3688 | shdr.sh_addralign = @alignOf(u64); | ||
| 3689 | } | 4007 | } |
| 3690 | 4008 | ||
| 3691 | if (self.eh_frame_hdr_section_index) |index| { | 4009 | if (self.eh_frame_hdr_section_index) |index| { |
| 3692 | const shdr = &self.shdrs.items[index]; | 4010 | self.shdrs.items[index].sh_size = eh_frame.calcEhFrameHdrSize(self); |
| 3693 | shdr.sh_size = eh_frame.calcEhFrameHdrSize(self); | ||
| 3694 | shdr.sh_addralign = @alignOf(u32); | ||
| 3695 | } | 4011 | } |
| 3696 | 4012 | ||
| 3697 | if (self.got_section_index) |index| { | 4013 | if (self.got_section_index) |index| { |
| 3698 | self.shdrs.items[index].sh_size = self.got.size(self); | 4014 | self.shdrs.items[index].sh_size = self.got.size(self); |
| 3699 | } | 4015 | } |
| 3700 | 4016 | ||
| 4017 | if (self.plt_section_index) |index| { | ||
| 4018 | self.shdrs.items[index].sh_size = self.plt.size(); | ||
| 4019 | } | ||
| 4020 | |||
| 4021 | if (self.got_plt_section_index) |index| { | ||
| 4022 | self.shdrs.items[index].sh_size = self.got_plt.size(self); | ||
| 4023 | } | ||
| 4024 | |||
| 4025 | if (self.plt_got_section_index) |index| { | ||
| 4026 | self.shdrs.items[index].sh_size = self.plt_got.size(); | ||
| 4027 | } | ||
| 4028 | |||
| 4029 | if (self.rela_dyn_section_index) |shndx| { | ||
| 4030 | var num = self.got.numRela(self) + self.copy_rel.numRela(); | ||
| 4031 | for (self.objects.items) |index| { | ||
| 4032 | num += self.file(index).?.object.num_dynrelocs; | ||
| 4033 | } | ||
| 4034 | self.shdrs.items[shndx].sh_size = num * @sizeOf(elf.Elf64_Rela); | ||
| 4035 | } | ||
| 4036 | |||
| 4037 | if (self.rela_plt_section_index) |index| { | ||
| 4038 | self.shdrs.items[index].sh_size = self.plt.numRela() * @sizeOf(elf.Elf64_Rela); | ||
| 4039 | } | ||
| 4040 | |||
| 4041 | if (self.copy_rel_section_index) |index| { | ||
| 4042 | try self.copy_rel.updateSectionSize(index, self); | ||
| 4043 | } | ||
| 4044 | |||
| 4045 | if (self.interp_section_index) |index| { | ||
| 4046 | self.shdrs.items[index].sh_size = self.base.options.dynamic_linker.?.len + 1; | ||
| 4047 | } | ||
| 4048 | |||
| 4049 | if (self.hash_section_index) |index| { | ||
| 4050 | self.shdrs.items[index].sh_size = self.hash.size(); | ||
| 4051 | } | ||
| 4052 | |||
| 4053 | if (self.gnu_hash_section_index) |index| { | ||
| 4054 | self.shdrs.items[index].sh_size = self.gnu_hash.size(); | ||
| 4055 | } | ||
| 4056 | |||
| 4057 | if (self.dynamic_section_index) |index| { | ||
| 4058 | self.shdrs.items[index].sh_size = self.dynamic.size(self); | ||
| 4059 | } | ||
| 4060 | |||
| 4061 | if (self.dynsymtab_section_index) |index| { | ||
| 4062 | self.shdrs.items[index].sh_size = self.dynsym.size(); | ||
| 4063 | } | ||
| 4064 | |||
| 4065 | if (self.dynstrtab_section_index) |index| { | ||
| 4066 | self.shdrs.items[index].sh_size = self.dynstrtab.buffer.items.len; | ||
| 4067 | } | ||
| 4068 | |||
| 4069 | if (self.versym_section_index) |index| { | ||
| 4070 | self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym); | ||
| 4071 | } | ||
| 4072 | |||
| 4073 | if (self.verneed_section_index) |index| { | ||
| 4074 | self.shdrs.items[index].sh_size = self.verneed.size(); | ||
| 4075 | } | ||
| 4076 | |||
| 3701 | if (self.symtab_section_index != null) { | 4077 | if (self.symtab_section_index != null) { |
| 3702 | try self.updateSymtabSize(); | 4078 | try self.updateSymtabSize(); |
| 3703 | } | 4079 | } |
| ... | @@ -3708,13 +4084,17 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -3708,13 +4084,17 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3708 | if (self.got_section_index) |_| { | 4084 | if (self.got_section_index) |_| { |
| 3709 | try self.got.updateStrtab(self); | 4085 | try self.got.updateStrtab(self); |
| 3710 | } | 4086 | } |
| 4087 | if (self.plt_section_index) |_| { | ||
| 4088 | try self.plt.updateStrtab(self); | ||
| 4089 | } | ||
| 4090 | if (self.plt_got_section_index) |_| { | ||
| 4091 | try self.plt_got.updateStrtab(self); | ||
| 4092 | } | ||
| 3711 | self.shdrs.items[index].sh_size = self.strtab.buffer.items.len; | 4093 | self.shdrs.items[index].sh_size = self.strtab.buffer.items.len; |
| 3712 | // try self.growNonAllocSection(index, self.strtab.buffer.items.len, 1, false); | ||
| 3713 | } | 4094 | } |
| 3714 | 4095 | ||
| 3715 | if (self.shstrtab_section_index) |index| { | 4096 | if (self.shstrtab_section_index) |index| { |
| 3716 | self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len; | 4097 | self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len; |
| 3717 | // try self.growNonAllocSection(index, self.shstrtab.buffer.items.len, 1, false); | ||
| 3718 | } | 4098 | } |
| 3719 | } | 4099 | } |
| 3720 | 4100 | ||
| ... | @@ -3729,18 +4109,18 @@ fn initPhdrs(self: *Elf) !void { | ... | @@ -3729,18 +4109,18 @@ fn initPhdrs(self: *Elf) !void { |
| 3729 | }); | 4109 | }); |
| 3730 | 4110 | ||
| 3731 | // Add INTERP phdr if required | 4111 | // Add INTERP phdr if required |
| 3732 | // if (self.interp_sect_index) |index| { | 4112 | if (self.interp_section_index) |index| { |
| 3733 | // const shdr = self.sections.items(.shdr)[index]; | 4113 | const shdr = self.shdrs.items[index]; |
| 3734 | // _ = try self.addPhdr(.{ | 4114 | _ = try self.addPhdr(.{ |
| 3735 | // .type = elf.PT_INTERP, | 4115 | .type = elf.PT_INTERP, |
| 3736 | // .flags = elf.PF_R, | 4116 | .flags = elf.PF_R, |
| 3737 | // .@"align" = 1, | 4117 | .@"align" = 1, |
| 3738 | // .offset = shdr.sh_offset, | 4118 | .offset = shdr.sh_offset, |
| 3739 | // .addr = shdr.sh_addr, | 4119 | .addr = shdr.sh_addr, |
| 3740 | // .filesz = shdr.sh_size, | 4120 | .filesz = shdr.sh_size, |
| 3741 | // .memsz = shdr.sh_size, | 4121 | .memsz = shdr.sh_size, |
| 3742 | // }); | 4122 | }); |
| 3743 | // } | 4123 | } |
| 3744 | 4124 | ||
| 3745 | // Add LOAD phdrs | 4125 | // Add LOAD phdrs |
| 3746 | const slice = self.shdrs.items; | 4126 | const slice = self.shdrs.items; |
| ... | @@ -3806,18 +4186,18 @@ fn initPhdrs(self: *Elf) !void { | ... | @@ -3806,18 +4186,18 @@ fn initPhdrs(self: *Elf) !void { |
| 3806 | } | 4186 | } |
| 3807 | 4187 | ||
| 3808 | // Add DYNAMIC phdr | 4188 | // Add DYNAMIC phdr |
| 3809 | // if (self.dynamic_sect_index) |index| { | 4189 | if (self.dynamic_section_index) |index| { |
| 3810 | // const shdr = self.sections.items(.shdr)[index]; | 4190 | const shdr = self.shdrs.items[index]; |
| 3811 | // _ = try self.addPhdr(.{ | 4191 | _ = try self.addPhdr(.{ |
| 3812 | // .type = elf.PT_DYNAMIC, | 4192 | .type = elf.PT_DYNAMIC, |
| 3813 | // .flags = elf.PF_R | elf.PF_W, | 4193 | .flags = elf.PF_R | elf.PF_W, |
| 3814 | // .@"align" = shdr.sh_addralign, | 4194 | .@"align" = shdr.sh_addralign, |
| 3815 | // .offset = shdr.sh_offset, | 4195 | .offset = shdr.sh_offset, |
| 3816 | // .addr = shdr.sh_addr, | 4196 | .addr = shdr.sh_addr, |
| 3817 | // .memsz = shdr.sh_size, | 4197 | .memsz = shdr.sh_size, |
| 3818 | // .filesz = shdr.sh_size, | 4198 | .filesz = shdr.sh_size, |
| 3819 | // }); | 4199 | }); |
| 3820 | // } | 4200 | } |
| 3821 | 4201 | ||
| 3822 | // Add PT_GNU_EH_FRAME phdr if required. | 4202 | // Add PT_GNU_EH_FRAME phdr if required. |
| 3823 | if (self.eh_frame_hdr_section_index) |index| { | 4203 | if (self.eh_frame_hdr_section_index) |index| { |
| ... | @@ -4113,6 +4493,16 @@ fn updateSymtabSize(self: *Elf) !void { | ... | @@ -4113,6 +4493,16 @@ fn updateSymtabSize(self: *Elf) !void { |
| 4113 | sizes.nlocals += self.got.output_symtab_size.nlocals; | 4493 | sizes.nlocals += self.got.output_symtab_size.nlocals; |
| 4114 | } | 4494 | } |
| 4115 | 4495 | ||
| 4496 | if (self.plt_section_index) |_| { | ||
| 4497 | self.plt.updateSymtabSize(self); | ||
| 4498 | sizes.nlocals += self.plt.output_symtab_size.nlocals; | ||
| 4499 | } | ||
| 4500 | |||
| 4501 | if (self.plt_got_section_index) |_| { | ||
| 4502 | self.plt_got.updateSymtabSize(self); | ||
| 4503 | sizes.nlocals += self.plt_got.output_symtab_size.nlocals; | ||
| 4504 | } | ||
| 4505 | |||
| 4116 | if (self.linker_defined_index) |index| { | 4506 | if (self.linker_defined_index) |index| { |
| 4117 | const linker_defined = self.file(index).?.linker_defined; | 4507 | const linker_defined = self.file(index).?.linker_defined; |
| 4118 | linker_defined.updateSymtabSize(self); | 4508 | linker_defined.updateSymtabSize(self); |
| ... | @@ -4127,18 +4517,70 @@ fn updateSymtabSize(self: *Elf) !void { | ... | @@ -4127,18 +4517,70 @@ fn updateSymtabSize(self: *Elf) !void { |
| 4127 | .p32 => @sizeOf(elf.Elf32_Sym), | 4517 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 4128 | .p64 => @sizeOf(elf.Elf64_Sym), | 4518 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 4129 | }; | 4519 | }; |
| 4130 | // const sym_align: u16 = switch (self.ptr_width) { | ||
| 4131 | // .p32 => @alignOf(elf.Elf32_Sym), | ||
| 4132 | // .p64 => @alignOf(elf.Elf64_Sym), | ||
| 4133 | // }; | ||
| 4134 | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; | 4520 | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; |
| 4135 | shdr.sh_size = needed_size; | 4521 | shdr.sh_size = needed_size; |
| 4136 | // try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, false); | ||
| 4137 | } | 4522 | } |
| 4138 | 4523 | ||
| 4139 | fn writeSyntheticSections(self: *Elf) !void { | 4524 | fn writeSyntheticSections(self: *Elf) !void { |
| 4140 | const gpa = self.base.allocator; | 4525 | const gpa = self.base.allocator; |
| 4141 | 4526 | ||
| 4527 | if (self.interp_section_index) |shndx| { | ||
| 4528 | const shdr = self.shdrs.items[shndx]; | ||
| 4529 | var buffer = try gpa.alloc(u8, shdr.sh_size); | ||
| 4530 | defer gpa.free(buffer); | ||
| 4531 | const dylinker = self.base.options.dynamic_linker.?; | ||
| 4532 | @memcpy(buffer[0..dylinker.len], dylinker); | ||
| 4533 | buffer[dylinker.len] = 0; | ||
| 4534 | try self.base.file.?.pwriteAll(buffer, shdr.sh_offset); | ||
| 4535 | } | ||
| 4536 | |||
| 4537 | if (self.hash_section_index) |shndx| { | ||
| 4538 | const shdr = self.shdrs.items[shndx]; | ||
| 4539 | try self.base.file.?.pwriteAll(self.hash.buffer.items, shdr.sh_offset); | ||
| 4540 | } | ||
| 4541 | |||
| 4542 | if (self.gnu_hash_section_index) |shndx| { | ||
| 4543 | const shdr = self.shdrs.items[shndx]; | ||
| 4544 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size()); | ||
| 4545 | defer buffer.deinit(); | ||
| 4546 | try self.gnu_hash.write(self, buffer.writer()); | ||
| 4547 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4548 | } | ||
| 4549 | |||
| 4550 | if (self.versym_section_index) |shndx| { | ||
| 4551 | const shdr = self.shdrs.items[shndx]; | ||
| 4552 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset); | ||
| 4553 | } | ||
| 4554 | |||
| 4555 | if (self.verneed_section_index) |shndx| { | ||
| 4556 | const shdr = self.shdrs.items[shndx]; | ||
| 4557 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size()); | ||
| 4558 | defer buffer.deinit(); | ||
| 4559 | try self.verneed.write(buffer.writer()); | ||
| 4560 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4561 | } | ||
| 4562 | |||
| 4563 | if (self.dynamic_section_index) |shndx| { | ||
| 4564 | const shdr = self.shdrs.items[shndx]; | ||
| 4565 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self)); | ||
| 4566 | defer buffer.deinit(); | ||
| 4567 | try self.dynamic.write(self, buffer.writer()); | ||
| 4568 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4569 | } | ||
| 4570 | |||
| 4571 | if (self.dynsymtab_section_index) |shndx| { | ||
| 4572 | const shdr = self.shdrs.items[shndx]; | ||
| 4573 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size()); | ||
| 4574 | defer buffer.deinit(); | ||
| 4575 | try self.dynsym.write(self, buffer.writer()); | ||
| 4576 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4577 | } | ||
| 4578 | |||
| 4579 | if (self.dynstrtab_section_index) |shndx| { | ||
| 4580 | const shdr = self.shdrs.items[shndx]; | ||
| 4581 | try self.base.file.?.pwriteAll(self.dynstrtab.buffer.items, shdr.sh_offset); | ||
| 4582 | } | ||
| 4583 | |||
| 4142 | if (self.eh_frame_section_index) |shndx| { | 4584 | if (self.eh_frame_section_index) |shndx| { |
| 4143 | const shdr = self.shdrs.items[shndx]; | 4585 | const shdr = self.shdrs.items[shndx]; |
| 4144 | var buffer = try std.ArrayList(u8).initCapacity(gpa, shdr.sh_size); | 4586 | var buffer = try std.ArrayList(u8).initCapacity(gpa, shdr.sh_size); |
| ... | @@ -4163,6 +4605,44 @@ fn writeSyntheticSections(self: *Elf) !void { | ... | @@ -4163,6 +4605,44 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 4163 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | 4605 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 4164 | } | 4606 | } |
| 4165 | 4607 | ||
| 4608 | if (self.rela_dyn_section_index) |shndx| { | ||
| 4609 | const shdr = self.shdrs.items[shndx]; | ||
| 4610 | try self.got.addRela(self); | ||
| 4611 | try self.copy_rel.addRela(self); | ||
| 4612 | self.sortRelaDyn(); | ||
| 4613 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset); | ||
| 4614 | } | ||
| 4615 | |||
| 4616 | if (self.plt_section_index) |shndx| { | ||
| 4617 | const shdr = self.shdrs.items[shndx]; | ||
| 4618 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size()); | ||
| 4619 | defer buffer.deinit(); | ||
| 4620 | try self.plt.write(self, buffer.writer()); | ||
| 4621 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4622 | } | ||
| 4623 | |||
| 4624 | if (self.got_plt_section_index) |shndx| { | ||
| 4625 | const shdr = self.shdrs.items[shndx]; | ||
| 4626 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self)); | ||
| 4627 | defer buffer.deinit(); | ||
| 4628 | try self.got_plt.write(self, buffer.writer()); | ||
| 4629 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4630 | } | ||
| 4631 | |||
| 4632 | if (self.plt_got_section_index) |shndx| { | ||
| 4633 | const shdr = self.shdrs.items[shndx]; | ||
| 4634 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size()); | ||
| 4635 | defer buffer.deinit(); | ||
| 4636 | try self.plt_got.write(self, buffer.writer()); | ||
| 4637 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | ||
| 4638 | } | ||
| 4639 | |||
| 4640 | if (self.rela_plt_section_index) |shndx| { | ||
| 4641 | const shdr = self.shdrs.items[shndx]; | ||
| 4642 | try self.plt.addRela(self); | ||
| 4643 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset); | ||
| 4644 | } | ||
| 4645 | |||
| 4166 | if (self.shstrtab_section_index) |index| { | 4646 | if (self.shstrtab_section_index) |index| { |
| 4167 | const shdr = self.shdrs.items[index]; | 4647 | const shdr = self.shdrs.items[index]; |
| 4168 | try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset); | 4648 | try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset); |
| ... | @@ -4213,11 +4693,27 @@ fn writeSymtab(self: *Elf) !void { | ... | @@ -4213,11 +4693,27 @@ fn writeSymtab(self: *Elf) !void { |
| 4213 | ctx.iglobal += object.output_symtab_size.nglobals; | 4693 | ctx.iglobal += object.output_symtab_size.nglobals; |
| 4214 | } | 4694 | } |
| 4215 | 4695 | ||
| 4696 | for (self.shared_objects.items) |index| { | ||
| 4697 | const shared_object = self.file(index).?.shared_object; | ||
| 4698 | shared_object.writeSymtab(self, ctx); | ||
| 4699 | ctx.iglobal += shared_object.output_symtab_size.nglobals; | ||
| 4700 | } | ||
| 4701 | |||
| 4216 | if (self.got_section_index) |_| { | 4702 | if (self.got_section_index) |_| { |
| 4217 | try self.got.writeSymtab(self, ctx); | 4703 | try self.got.writeSymtab(self, ctx); |
| 4218 | ctx.ilocal += self.got.output_symtab_size.nlocals; | 4704 | ctx.ilocal += self.got.output_symtab_size.nlocals; |
| 4219 | } | 4705 | } |
| 4220 | 4706 | ||
| 4707 | if (self.plt_section_index) |_| { | ||
| 4708 | try self.plt.writeSymtab(self, ctx); | ||
| 4709 | ctx.ilocal += self.plt.output_symtab_size.nlocals; | ||
| 4710 | } | ||
| 4711 | |||
| 4712 | if (self.plt_got_section_index) |_| { | ||
| 4713 | try self.plt_got.writeSymtab(self, ctx); | ||
| 4714 | ctx.ilocal += self.plt_got.output_symtab_size.nlocals; | ||
| 4715 | } | ||
| 4716 | |||
| 4221 | if (self.linker_defined_index) |index| { | 4717 | if (self.linker_defined_index) |index| { |
| 4222 | const linker_defined = self.file(index).?.linker_defined; | 4718 | const linker_defined = self.file(index).?.linker_defined; |
| 4223 | linker_defined.writeSymtab(self, ctx); | 4719 | linker_defined.writeSymtab(self, ctx); |
| ... | @@ -4576,7 +5072,7 @@ pub fn isStatic(self: Elf) bool { | ... | @@ -4576,7 +5072,7 @@ pub fn isStatic(self: Elf) bool { |
| 4576 | } | 5072 | } |
| 4577 | 5073 | ||
| 4578 | pub fn isDynLib(self: Elf) bool { | 5074 | pub fn isDynLib(self: Elf) bool { |
| 4579 | return self.base.options.output_mode == .Lib and self.base.options.link_mode == .Dynamic; | 5075 | return self.base.options.effectiveOutputMode() == .Lib and self.base.options.link_mode == .Dynamic; |
| 4580 | } | 5076 | } |
| 4581 | 5077 | ||
| 4582 | fn addPhdr(self: *Elf, opts: struct { | 5078 | fn addPhdr(self: *Elf, opts: struct { |
| ... | @@ -4723,6 +5219,7 @@ pub fn file(self: *Elf, index: File.Index) ?File { | ... | @@ -4723,6 +5219,7 @@ pub fn file(self: *Elf, index: File.Index) ?File { |
| 4723 | .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined }, | 5219 | .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined }, |
| 4724 | .zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module }, | 5220 | .zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module }, |
| 4725 | .object => .{ .object = &self.files.items(.data)[index].object }, | 5221 | .object => .{ .object = &self.files.items(.data)[index].object }, |
| 5222 | .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object }, | ||
| 4726 | }; | 5223 | }; |
| 4727 | } | 5224 | } |
| 4728 | 5225 | ||
| ... | @@ -5077,6 +5574,16 @@ fn fmtDumpState( | ... | @@ -5077,6 +5574,16 @@ fn fmtDumpState( |
| 5077 | }); | 5574 | }); |
| 5078 | } | 5575 | } |
| 5079 | 5576 | ||
| 5577 | for (self.shared_objects.items) |index| { | ||
| 5578 | const shared_object = self.file(index).?.shared_object; | ||
| 5579 | try writer.print("shared_object({d}) : ", .{index}); | ||
| 5580 | try writer.print("{s}", .{shared_object.path}); | ||
| 5581 | try writer.print(" : needed({})", .{shared_object.needed}); | ||
| 5582 | if (!shared_object.alive) try writer.writeAll(" : [*]"); | ||
| 5583 | try writer.writeByte('\n'); | ||
| 5584 | try writer.print("{}\n", .{shared_object.fmtSymtab(self)}); | ||
| 5585 | } | ||
| 5586 | |||
| 5080 | if (self.linker_defined_index) |index| { | 5587 | if (self.linker_defined_index) |index| { |
| 5081 | const linker_defined = self.file(index).?.linker_defined; | 5588 | const linker_defined = self.file(index).?.linker_defined; |
| 5082 | try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); | 5589 | try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); |
| ... | @@ -5227,10 +5734,16 @@ const Archive = @import("Elf/Archive.zig"); | ... | @@ -5227,10 +5734,16 @@ const Archive = @import("Elf/Archive.zig"); |
| 5227 | pub const Atom = @import("Elf/Atom.zig"); | 5734 | pub const Atom = @import("Elf/Atom.zig"); |
| 5228 | const Cache = std.Build.Cache; | 5735 | const Cache = std.Build.Cache; |
| 5229 | const Compilation = @import("../Compilation.zig"); | 5736 | const Compilation = @import("../Compilation.zig"); |
| 5737 | const CopyRelSection = synthetic_sections.CopyRelSection; | ||
| 5738 | const DynamicSection = synthetic_sections.DynamicSection; | ||
| 5739 | const DynsymSection = synthetic_sections.DynsymSection; | ||
| 5230 | const Dwarf = @import("Dwarf.zig"); | 5740 | const Dwarf = @import("Dwarf.zig"); |
| 5231 | const Elf = @This(); | 5741 | const Elf = @This(); |
| 5232 | const File = @import("Elf/file.zig").File; | 5742 | const File = @import("Elf/file.zig").File; |
| 5743 | const GnuHashSection = synthetic_sections.GnuHashSection; | ||
| 5233 | const GotSection = synthetic_sections.GotSection; | 5744 | const GotSection = synthetic_sections.GotSection; |
| 5745 | const GotPltSection = synthetic_sections.GotPltSection; | ||
| 5746 | const HashSection = synthetic_sections.HashSection; | ||
| 5234 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); | 5747 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); |
| 5235 | const Liveness = @import("../Liveness.zig"); | 5748 | const Liveness = @import("../Liveness.zig"); |
| 5236 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 5749 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| ... | @@ -5238,10 +5751,14 @@ const Module = @import("../Module.zig"); | ... | @@ -5238,10 +5751,14 @@ const Module = @import("../Module.zig"); |
| 5238 | const Object = @import("Elf/Object.zig"); | 5751 | const Object = @import("Elf/Object.zig"); |
| 5239 | const InternPool = @import("../InternPool.zig"); | 5752 | const InternPool = @import("../InternPool.zig"); |
| 5240 | const Package = @import("../Package.zig"); | 5753 | const Package = @import("../Package.zig"); |
| 5754 | const PltSection = synthetic_sections.PltSection; | ||
| 5755 | const PltGotSection = synthetic_sections.PltGotSection; | ||
| 5756 | const SharedObject = @import("Elf/SharedObject.zig"); | ||
| 5241 | const Symbol = @import("Elf/Symbol.zig"); | 5757 | const Symbol = @import("Elf/Symbol.zig"); |
| 5242 | const StringTable = @import("strtab.zig").StringTable; | 5758 | const StringTable = @import("strtab.zig").StringTable; |
| 5243 | const TableSection = @import("table_section.zig").TableSection; | 5759 | const TableSection = @import("table_section.zig").TableSection; |
| 5244 | const Type = @import("../type.zig").Type; | 5760 | const Type = @import("../type.zig").Type; |
| 5245 | const TypedValue = @import("../TypedValue.zig"); | 5761 | const TypedValue = @import("../TypedValue.zig"); |
| 5246 | const Value = @import("../value.zig").Value; | 5762 | const Value = @import("../value.zig").Value; |
| 5763 | const VerneedSection = synthetic_sections.VerneedSection; | ||
| 5247 | const ZigModule = @import("Elf/ZigModule.zig"); | 5764 | const ZigModule = @import("Elf/ZigModule.zig"); |
src/link/Elf/SharedObject.zig created+361| ... | @@ -0,0 +1,361 @@ | ||
| 1 | path: []const u8, | ||
| 2 | data: []const u8, | ||
| 3 | index: File.Index, | ||
| 4 | |||
| 5 | header: ?elf.Elf64_Ehdr = null, | ||
| 6 | shdrs: std.ArrayListUnmanaged(ElfShdr) = .{}, | ||
| 7 | symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{}, | ||
| 8 | strtab: []const u8 = &[0]u8{}, | ||
| 9 | /// Version symtab contains version strings of the symbols if present. | ||
| 10 | versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{}, | ||
| 11 | verstrings: std.ArrayListUnmanaged(u32) = .{}, | ||
| 12 | |||
| 13 | dynamic_sect_index: ?u16 = null, | ||
| 14 | versym_sect_index: ?u16 = null, | ||
| 15 | verdef_sect_index: ?u16 = null, | ||
| 16 | |||
| 17 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 18 | aliases: ?std.ArrayListUnmanaged(u32) = null, | ||
| 19 | |||
| 20 | needed: bool, | ||
| 21 | alive: bool, | ||
| 22 | |||
| 23 | output_symtab_size: Elf.SymtabSize = .{}, | ||
| 24 | |||
| 25 | pub fn isSharedObject(file: std.fs.File) bool { | ||
| 26 | const reader = file.reader(); | ||
| 27 | const header = reader.readStruct(elf.Elf64_Ehdr) catch return false; | ||
| 28 | defer file.seekTo(0) catch {}; | ||
| 29 | if (!mem.eql(u8, header.e_ident[0..4], "\x7fELF")) return false; | ||
| 30 | if (header.e_ident[elf.EI_VERSION] != 1) return false; | ||
| 31 | if (header.e_type != elf.ET.DYN) return false; | ||
| 32 | return true; | ||
| 33 | } | ||
| 34 | |||
| 35 | pub fn deinit(self: *SharedObject, allocator: Allocator) void { | ||
| 36 | self.versyms.deinit(allocator); | ||
| 37 | self.verstrings.deinit(allocator); | ||
| 38 | self.symbols.deinit(allocator); | ||
| 39 | if (self.aliases) |*aliases| aliases.deinit(allocator); | ||
| 40 | self.shdrs.deinit(allocator); | ||
| 41 | } | ||
| 42 | |||
| 43 | pub fn parse(self: *SharedObject, elf_file: *Elf) !void { | ||
| 44 | const gpa = elf_file.base.allocator; | ||
| 45 | var stream = std.io.fixedBufferStream(self.data); | ||
| 46 | const reader = stream.reader(); | ||
| 47 | |||
| 48 | self.header = try reader.readStruct(elf.Elf64_Ehdr); | ||
| 49 | |||
| 50 | var dynsym_index: ?u16 = null; | ||
| 51 | const shdrs = @as( | ||
| 52 | [*]align(1) const elf.Elf64_Shdr, | ||
| 53 | @ptrCast(self.data.ptr + self.header.?.e_shoff), | ||
| 54 | )[0..self.header.?.e_shnum]; | ||
| 55 | try self.shdrs.ensureTotalCapacityPrecise(gpa, shdrs.len); | ||
| 56 | |||
| 57 | for (shdrs, 0..) |shdr, i| { | ||
| 58 | self.shdrs.appendAssumeCapacity(try ElfShdr.fromElf64Shdr(shdr)); | ||
| 59 | switch (shdr.sh_type) { | ||
| 60 | elf.SHT_DYNSYM => dynsym_index = @as(u16, @intCast(i)), | ||
| 61 | elf.SHT_DYNAMIC => self.dynamic_sect_index = @as(u16, @intCast(i)), | ||
| 62 | elf.SHT_GNU_VERSYM => self.versym_sect_index = @as(u16, @intCast(i)), | ||
| 63 | elf.SHT_GNU_VERDEF => self.verdef_sect_index = @as(u16, @intCast(i)), | ||
| 64 | else => {}, | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | if (dynsym_index) |index| { | ||
| 69 | const shdr = self.shdrs.items[index]; | ||
| 70 | const symtab = self.shdrContents(index); | ||
| 71 | const nsyms = @divExact(symtab.len, @sizeOf(elf.Elf64_Sym)); | ||
| 72 | self.symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(symtab.ptr))[0..nsyms]; | ||
| 73 | self.strtab = self.shdrContents(@as(u16, @intCast(shdr.sh_link))); | ||
| 74 | } | ||
| 75 | |||
| 76 | try self.parseVersions(elf_file); | ||
| 77 | try self.initSymtab(elf_file); | ||
| 78 | } | ||
| 79 | |||
| 80 | fn parseVersions(self: *SharedObject, elf_file: *Elf) !void { | ||
| 81 | const gpa = elf_file.base.allocator; | ||
| 82 | |||
| 83 | try self.verstrings.resize(gpa, 2); | ||
| 84 | self.verstrings.items[elf.VER_NDX_LOCAL] = 0; | ||
| 85 | self.verstrings.items[elf.VER_NDX_GLOBAL] = 0; | ||
| 86 | |||
| 87 | if (self.verdef_sect_index) |shndx| { | ||
| 88 | const verdefs = self.shdrContents(shndx); | ||
| 89 | const nverdefs = self.verdefNum(); | ||
| 90 | try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs); | ||
| 91 | |||
| 92 | var i: u32 = 0; | ||
| 93 | var offset: u32 = 0; | ||
| 94 | while (i < nverdefs) : (i += 1) { | ||
| 95 | const verdef = @as(*align(1) const elf.Elf64_Verdef, @ptrCast(verdefs.ptr + offset)).*; | ||
| 96 | defer offset += verdef.vd_next; | ||
| 97 | if (verdef.vd_flags == elf.VER_FLG_BASE) continue; // Skip BASE entry | ||
| 98 | const vda_name = if (verdef.vd_cnt > 0) | ||
| 99 | @as(*align(1) const elf.Elf64_Verdaux, @ptrCast(verdefs.ptr + offset + verdef.vd_aux)).vda_name | ||
| 100 | else | ||
| 101 | 0; | ||
| 102 | self.verstrings.items[verdef.vd_ndx] = vda_name; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | try self.versyms.ensureTotalCapacityPrecise(gpa, self.symtab.len); | ||
| 107 | |||
| 108 | if (self.versym_sect_index) |shndx| { | ||
| 109 | const versyms_raw = self.shdrContents(shndx); | ||
| 110 | const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym)); | ||
| 111 | const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms]; | ||
| 112 | for (versyms) |ver| { | ||
| 113 | const normalized_ver = if (ver & elf.VERSYM_VERSION >= self.verstrings.items.len - 1) | ||
| 114 | elf.VER_NDX_GLOBAL | ||
| 115 | else | ||
| 116 | ver; | ||
| 117 | self.versyms.appendAssumeCapacity(normalized_ver); | ||
| 118 | } | ||
| 119 | } else for (0..self.symtab.len) |_| { | ||
| 120 | self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | fn initSymtab(self: *SharedObject, elf_file: *Elf) !void { | ||
| 125 | const gpa = elf_file.base.allocator; | ||
| 126 | |||
| 127 | try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.len); | ||
| 128 | |||
| 129 | for (self.symtab, 0..) |sym, i| { | ||
| 130 | const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0; | ||
| 131 | const name = self.getString(sym.st_name); | ||
| 132 | // We need to garble up the name so that we don't pick this symbol | ||
| 133 | // during symbol resolution. Thank you GNU! | ||
| 134 | const off = if (hidden) blk: { | ||
| 135 | const full_name = try std.fmt.allocPrint(gpa, "{s}@{s}", .{ | ||
| 136 | name, | ||
| 137 | self.versionString(self.versyms.items[i]), | ||
| 138 | }); | ||
| 139 | defer gpa.free(full_name); | ||
| 140 | break :blk try elf_file.strtab.insert(gpa, full_name); | ||
| 141 | } else try elf_file.strtab.insert(gpa, name); | ||
| 142 | const gop = try elf_file.getOrCreateGlobal(off); | ||
| 143 | self.symbols.addOneAssumeCapacity().* = gop.index; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void { | ||
| 148 | for (self.globals(), 0..) |index, i| { | ||
| 149 | const esym_index = @as(u32, @intCast(i)); | ||
| 150 | const this_sym = self.symtab[esym_index]; | ||
| 151 | |||
| 152 | if (this_sym.st_shndx == elf.SHN_UNDEF) continue; | ||
| 153 | |||
| 154 | const global = elf_file.symbol(index); | ||
| 155 | if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) { | ||
| 156 | global.value = this_sym.st_value; | ||
| 157 | global.atom_index = 0; | ||
| 158 | global.esym_index = esym_index; | ||
| 159 | global.version_index = self.versyms.items[esym_index]; | ||
| 160 | global.file_index = self.index; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | pub fn resetGlobals(self: *SharedObject, elf_file: *Elf) void { | ||
| 166 | for (self.globals()) |index| { | ||
| 167 | const global = elf_file.symbol(index); | ||
| 168 | const off = global.name_offset; | ||
| 169 | global.* = .{}; | ||
| 170 | global.name_offset = off; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | pub fn markLive(self: *SharedObject, elf_file: *Elf) void { | ||
| 175 | for (self.globals(), 0..) |index, i| { | ||
| 176 | const sym = self.symtab[i]; | ||
| 177 | if (sym.st_shndx != elf.SHN_UNDEF) continue; | ||
| 178 | |||
| 179 | const global = elf_file.symbol(index); | ||
| 180 | const file = global.file(elf_file) orelse continue; | ||
| 181 | const should_drop = switch (file) { | ||
| 182 | .shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK, | ||
| 183 | else => false, | ||
| 184 | }; | ||
| 185 | if (!should_drop and !file.isAlive()) { | ||
| 186 | file.setAlive(); | ||
| 187 | file.markLive(elf_file); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void { | ||
| 193 | for (self.globals()) |global_index| { | ||
| 194 | const global = elf_file.symbol(global_index); | ||
| 195 | if (global.file(elf_file)) |file| if (file.index() != self.index) continue; | ||
| 196 | if (global.isLocal()) continue; | ||
| 197 | global.flags.output_symtab = true; | ||
| 198 | self.output_symtab_size.nglobals += 1; | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | pub fn writeSymtab(self: *SharedObject, elf_file: *Elf, ctx: anytype) void { | ||
| 203 | var iglobal = ctx.iglobal; | ||
| 204 | for (self.globals()) |global_index| { | ||
| 205 | const global = elf_file.symbol(global_index); | ||
| 206 | if (global.file(elf_file)) |file| if (file.index() != self.index) continue; | ||
| 207 | if (!global.flags.output_symtab) continue; | ||
| 208 | global.setOutputSym(elf_file, &ctx.symtab[iglobal]); | ||
| 209 | iglobal += 1; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | pub fn globals(self: SharedObject) []const Symbol.Index { | ||
| 214 | return self.symbols.items; | ||
| 215 | } | ||
| 216 | |||
| 217 | pub fn shdrContents(self: SharedObject, index: u16) []const u8 { | ||
| 218 | const shdr = self.shdrs.items[index]; | ||
| 219 | return self.data[shdr.sh_offset..][0..shdr.sh_size]; | ||
| 220 | } | ||
| 221 | |||
| 222 | pub fn getString(self: SharedObject, off: u32) [:0]const u8 { | ||
| 223 | assert(off < self.strtab.len); | ||
| 224 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0); | ||
| 225 | } | ||
| 226 | |||
| 227 | pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { | ||
| 228 | const off = self.verstrings.items[index & elf.VERSYM_VERSION]; | ||
| 229 | return self.getString(off); | ||
| 230 | } | ||
| 231 | |||
| 232 | pub fn asFile(self: *SharedObject) File { | ||
| 233 | return .{ .shared_object = self }; | ||
| 234 | } | ||
| 235 | |||
| 236 | fn dynamicTable(self: *SharedObject) []align(1) const elf.Elf64_Dyn { | ||
| 237 | const shndx = self.dynamic_sect_index orelse return &[0]elf.Elf64_Dyn{}; | ||
| 238 | const raw = self.shdrContents(shndx); | ||
| 239 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn)); | ||
| 240 | return @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num]; | ||
| 241 | } | ||
| 242 | |||
| 243 | fn verdefNum(self: *SharedObject) u32 { | ||
| 244 | const entries = self.dynamicTable(); | ||
| 245 | for (entries) |entry| switch (entry.d_tag) { | ||
| 246 | elf.DT_VERDEFNUM => return @as(u32, @intCast(entry.d_val)), | ||
| 247 | else => {}, | ||
| 248 | }; | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | pub fn soname(self: *SharedObject) []const u8 { | ||
| 253 | const entries = self.dynamicTable(); | ||
| 254 | for (entries) |entry| switch (entry.d_tag) { | ||
| 255 | elf.DT_SONAME => return self.getString(@as(u32, @intCast(entry.d_val))), | ||
| 256 | else => {}, | ||
| 257 | }; | ||
| 258 | return std.fs.path.basename(self.path); | ||
| 259 | } | ||
| 260 | |||
| 261 | pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { | ||
| 262 | assert(self.aliases == null); | ||
| 263 | |||
| 264 | const SortAlias = struct { | ||
| 265 | pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool { | ||
| 266 | const lhs_sym = ctx.symbol(lhs).elfSym(ctx); | ||
| 267 | const rhs_sym = ctx.symbol(rhs).elfSym(ctx); | ||
| 268 | return lhs_sym.st_value < rhs_sym.st_value; | ||
| 269 | } | ||
| 270 | }; | ||
| 271 | |||
| 272 | const gpa = elf_file.base.allocator; | ||
| 273 | var aliases = std.ArrayList(Symbol.Index).init(gpa); | ||
| 274 | defer aliases.deinit(); | ||
| 275 | try aliases.ensureTotalCapacityPrecise(self.globals().len); | ||
| 276 | |||
| 277 | for (self.globals()) |index| { | ||
| 278 | const global = elf_file.symbol(index); | ||
| 279 | const global_file = global.file(elf_file) orelse continue; | ||
| 280 | if (global_file.index() != self.index) continue; | ||
| 281 | aliases.appendAssumeCapacity(index); | ||
| 282 | } | ||
| 283 | |||
| 284 | std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan); | ||
| 285 | |||
| 286 | self.aliases = aliases.moveToUnmanaged(); | ||
| 287 | } | ||
| 288 | |||
| 289 | pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 { | ||
| 290 | assert(self.aliases != null); | ||
| 291 | |||
| 292 | const symbol = elf_file.symbol(index).elfSym(elf_file); | ||
| 293 | const aliases = self.aliases.?; | ||
| 294 | |||
| 295 | const start = for (aliases.items, 0..) |alias, i| { | ||
| 296 | const alias_sym = elf_file.symbol(alias).elfSym(elf_file); | ||
| 297 | if (symbol.st_value == alias_sym.st_value) break i; | ||
| 298 | } else aliases.items.len; | ||
| 299 | |||
| 300 | const end = for (aliases.items[start..], 0..) |alias, i| { | ||
| 301 | const alias_sym = elf_file.symbol(alias).elfSym(elf_file); | ||
| 302 | if (symbol.st_value < alias_sym.st_value) break i + start; | ||
| 303 | } else aliases.items.len; | ||
| 304 | |||
| 305 | return aliases.items[start..end]; | ||
| 306 | } | ||
| 307 | |||
| 308 | pub fn format( | ||
| 309 | self: SharedObject, | ||
| 310 | comptime unused_fmt_string: []const u8, | ||
| 311 | options: std.fmt.FormatOptions, | ||
| 312 | writer: anytype, | ||
| 313 | ) !void { | ||
| 314 | _ = self; | ||
| 315 | _ = unused_fmt_string; | ||
| 316 | _ = options; | ||
| 317 | _ = writer; | ||
| 318 | @compileError("do not format shared objects directly"); | ||
| 319 | } | ||
| 320 | |||
| 321 | pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { | ||
| 322 | return .{ .data = .{ | ||
| 323 | .shared = self, | ||
| 324 | .elf_file = elf_file, | ||
| 325 | } }; | ||
| 326 | } | ||
| 327 | |||
| 328 | const FormatContext = struct { | ||
| 329 | shared: SharedObject, | ||
| 330 | elf_file: *Elf, | ||
| 331 | }; | ||
| 332 | |||
| 333 | fn formatSymtab( | ||
| 334 | ctx: FormatContext, | ||
| 335 | comptime unused_fmt_string: []const u8, | ||
| 336 | options: std.fmt.FormatOptions, | ||
| 337 | writer: anytype, | ||
| 338 | ) !void { | ||
| 339 | _ = unused_fmt_string; | ||
| 340 | _ = options; | ||
| 341 | const shared = ctx.shared; | ||
| 342 | try writer.writeAll(" globals\n"); | ||
| 343 | for (shared.symbols.items) |index| { | ||
| 344 | const global = ctx.elf_file.symbol(index); | ||
| 345 | try writer.print(" {}\n", .{global.fmt(ctx.elf_file)}); | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | const SharedObject = @This(); | ||
| 350 | |||
| 351 | const std = @import("std"); | ||
| 352 | const assert = std.debug.assert; | ||
| 353 | const elf = std.elf; | ||
| 354 | const log = std.log.scoped(.elf); | ||
| 355 | const mem = std.mem; | ||
| 356 | |||
| 357 | const Allocator = mem.Allocator; | ||
| 358 | const Elf = @import("../Elf.zig"); | ||
| 359 | const ElfShdr = @import("Object.zig").ElfShdr; | ||
| 360 | const File = @import("file.zig").File; | ||
| 361 | const Symbol = @import("Symbol.zig"); | ||
src/link/Elf/Symbol.zig+75-47| ... | @@ -32,7 +32,7 @@ extra_index: u32 = 0, | ... | @@ -32,7 +32,7 @@ extra_index: u32 = 0, |
| 32 | 32 | ||
| 33 | pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { | 33 | pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { |
| 34 | const file_ptr = symbol.file(elf_file).?; | 34 | const file_ptr = symbol.file(elf_file).?; |
| 35 | // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS; | 35 | if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS; |
| 36 | return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and | 36 | return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and |
| 37 | file_ptr != .linker_defined; | 37 | file_ptr != .linker_defined; |
| 38 | } | 38 | } |
| ... | @@ -52,8 +52,8 @@ pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool { | ... | @@ -52,8 +52,8 @@ pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool { |
| 52 | 52 | ||
| 53 | pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 { | 53 | pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 { |
| 54 | const s_sym = symbol.elfSym(elf_file); | 54 | const s_sym = symbol.elfSym(elf_file); |
| 55 | // const file_ptr = symbol.file(elf_file).?; | 55 | const file_ptr = symbol.file(elf_file).?; |
| 56 | // if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared) return elf.STT_FUNC; | 56 | if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared_object) return elf.STT_FUNC; |
| 57 | return s_sym.st_type(); | 57 | return s_sym.st_type(); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| ... | @@ -74,7 +74,7 @@ pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { | ... | @@ -74,7 +74,7 @@ pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { |
| 74 | switch (file_ptr) { | 74 | switch (file_ptr) { |
| 75 | .zig_module => |x| return x.elfSym(symbol.esym_index).*, | 75 | .zig_module => |x| return x.elfSym(symbol.esym_index).*, |
| 76 | .linker_defined => |x| return x.symtab.items[symbol.esym_index], | 76 | .linker_defined => |x| return x.symtab.items[symbol.esym_index], |
| 77 | .object => |x| return x.symtab[symbol.esym_index], | 77 | inline else => |x| return x.symtab[symbol.esym_index], |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | 80 | ||
| ... | @@ -88,23 +88,18 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { | ... | @@ -88,23 +88,18 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 { |
| 88 | return file_ptr.symbolRank(sym, in_archive); | 88 | return file_ptr.symbolRank(sym, in_archive); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | pub fn address(symbol: Symbol, opts: struct { | 91 | pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) u64 { |
| 92 | plt: bool = true, | 92 | if (symbol.flags.has_copy_rel) { |
| 93 | }, elf_file: *Elf) u64 { | 93 | return symbol.copyRelAddress(elf_file); |
| 94 | _ = elf_file; | 94 | } |
| 95 | _ = opts; | 95 | if (symbol.flags.has_plt and opts.plt) { |
| 96 | // if (symbol.flags.copy_rel) { | 96 | if (!symbol.flags.is_canonical and symbol.flags.has_got) { |
| 97 | // return elf_file.sectionAddress(elf_file.copy_rel_sect_index.?) + symbol.value; | 97 | // We have a non-lazy bound function pointer, use that! |
| 98 | // } | 98 | return symbol.pltGotAddress(elf_file); |
| 99 | // if (symbol.flags.plt and opts.plt) { | 99 | } |
| 100 | // const extra = symbol.getExtra(elf_file).?; | 100 | // Lazy-bound function it is! |
| 101 | // if (!symbol.flags.is_canonical and symbol.flags.got) { | 101 | return symbol.pltAddress(elf_file); |
| 102 | // // We have a non-lazy bound function pointer, use that! | 102 | } |
| 103 | // return elf_file.getPltGotEntryAddress(extra.plt_got); | ||
| 104 | // } | ||
| 105 | // // Lazy-bound function it is! | ||
| 106 | // return elf_file.getPltEntryAddress(extra.plt); | ||
| 107 | // } | ||
| 108 | return symbol.value; | 103 | return symbol.value; |
| 109 | } | 104 | } |
| 110 | 105 | ||
| ... | @@ -115,6 +110,33 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 { | ... | @@ -115,6 +110,33 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| 115 | return entry.address(elf_file); | 110 | return entry.address(elf_file); |
| 116 | } | 111 | } |
| 117 | 112 | ||
| 113 | pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) u64 { | ||
| 114 | if (!(symbol.flags.has_plt and symbol.flags.has_got and !symbol.flags.is_canonical)) return 0; | ||
| 115 | const extras = symbol.extra(elf_file).?; | ||
| 116 | const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; | ||
| 117 | return shdr.sh_addr + extras.plt_got * 16; | ||
| 118 | } | ||
| 119 | |||
| 120 | pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 { | ||
| 121 | if (!symbol.flags.has_plt) return 0; | ||
| 122 | const extras = symbol.extra(elf_file).?; | ||
| 123 | const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; | ||
| 124 | return shdr.sh_addr + extras.plt * 16 + PltSection.preamble_size; | ||
| 125 | } | ||
| 126 | |||
| 127 | pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) u64 { | ||
| 128 | if (!symbol.flags.has_plt) return 0; | ||
| 129 | const extras = symbol.extra(elf_file).?; | ||
| 130 | const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?]; | ||
| 131 | return shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size; | ||
| 132 | } | ||
| 133 | |||
| 134 | pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) u64 { | ||
| 135 | if (!symbol.flags.has_copy_rel) return 0; | ||
| 136 | const shdr = elf_file.shdrs.items[elf_file.copy_rel_section_index.?]; | ||
| 137 | return shdr.sh_addr + symbol.value; | ||
| 138 | } | ||
| 139 | |||
| 118 | const GetOrCreateGotEntryResult = struct { | 140 | const GetOrCreateGotEntryResult = struct { |
| 119 | found_existing: bool, | 141 | found_existing: bool, |
| 120 | index: GotSection.Index, | 142 | index: GotSection.Index, |
| ... | @@ -149,17 +171,18 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 { | ... | @@ -149,17 +171,18 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| 149 | return entry.address(elf_file); | 171 | return entry.address(elf_file); |
| 150 | } | 172 | } |
| 151 | 173 | ||
| 152 | // pub fn alignment(symbol: Symbol, elf_file: *Elf) !u64 { | 174 | pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 { |
| 153 | // const file = symbol.getFile(elf_file) orelse return 0; | 175 | const file_ptr = symbol.file(elf_file) orelse return 0; |
| 154 | // const shared = file.shared; | 176 | assert(file_ptr == .shared_object); |
| 155 | // const s_sym = symbol.getSourceSymbol(elf_file); | 177 | const shared_object = file_ptr.shared_object; |
| 156 | // const shdr = shared.getShdrs()[s_sym.st_shndx]; | 178 | const esym = symbol.elfSym(elf_file); |
| 157 | // const alignment = @max(1, shdr.sh_addralign); | 179 | const shdr = shared_object.shdrs.items[esym.st_shndx]; |
| 158 | // return if (s_sym.st_value == 0) | 180 | const alignment = @max(1, shdr.sh_addralign); |
| 159 | // alignment | 181 | return if (esym.st_value == 0) |
| 160 | // else | 182 | alignment |
| 161 | // @min(alignment, try std.math.powi(u64, 2, @ctz(s_sym.st_value))); | 183 | else |
| 162 | // } | 184 | @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value))); |
| 185 | } | ||
| 163 | 186 | ||
| 164 | pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void { | 187 | pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void { |
| 165 | symbol.extra_index = try elf_file.addSymbolExtra(extras); | 188 | symbol.extra_index = try elf_file.addSymbolExtra(extras); |
| ... | @@ -183,22 +206,22 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { | ... | @@ -183,22 +206,22 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { |
| 183 | const st_bind: u8 = blk: { | 206 | const st_bind: u8 = blk: { |
| 184 | if (symbol.isLocal()) break :blk 0; | 207 | if (symbol.isLocal()) break :blk 0; |
| 185 | if (symbol.flags.weak) break :blk elf.STB_WEAK; | 208 | if (symbol.flags.weak) break :blk elf.STB_WEAK; |
| 186 | // if (file_ptr == .shared) break :blk elf.STB_GLOBAL; | 209 | if (file_ptr == .shared_object) break :blk elf.STB_GLOBAL; |
| 187 | break :blk esym.st_bind(); | 210 | break :blk esym.st_bind(); |
| 188 | }; | 211 | }; |
| 189 | const st_shndx = blk: { | 212 | const st_shndx = blk: { |
| 190 | // if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?; | 213 | if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?; |
| 191 | // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; | 214 | if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; |
| 192 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) | 215 | if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) |
| 193 | break :blk elf.SHN_ABS; | 216 | break :blk elf.SHN_ABS; |
| 194 | break :blk symbol.outputShndx() orelse elf.SHN_UNDEF; | 217 | break :blk symbol.outputShndx() orelse elf.SHN_UNDEF; |
| 195 | }; | 218 | }; |
| 196 | const st_value = blk: { | 219 | const st_value = blk: { |
| 197 | // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file); | 220 | if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file); |
| 198 | // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) { | 221 | if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) { |
| 199 | // if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file); | 222 | if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file); |
| 200 | // break :blk 0; | 223 | break :blk 0; |
| 201 | // } | 224 | } |
| 202 | if (st_shndx == elf.SHN_ABS) break :blk symbol.value; | 225 | if (st_shndx == elf.SHN_ABS) break :blk symbol.value; |
| 203 | const shdr = &elf_file.shdrs.items[st_shndx]; | 226 | const shdr = &elf_file.shdrs.items[st_shndx]; |
| 204 | if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) | 227 | if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) |
| ... | @@ -254,9 +277,10 @@ fn formatName( | ... | @@ -254,9 +277,10 @@ fn formatName( |
| 254 | switch (symbol.version_index & elf.VERSYM_VERSION) { | 277 | switch (symbol.version_index & elf.VERSYM_VERSION) { |
| 255 | elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {}, | 278 | elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {}, |
| 256 | else => { | 279 | else => { |
| 257 | unreachable; | 280 | const file_ptr = symbol.file(elf_file).?; |
| 258 | // const shared = symbol.getFile(elf_file).?.shared; | 281 | assert(file_ptr == .shared_object); |
| 259 | // try writer.print("@{s}", .{shared.getVersionString(symbol.version_index)}); | 282 | const shared_object = file_ptr.shared_object; |
| 283 | try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)}); | ||
| 260 | }, | 284 | }, |
| 261 | } | 285 | } |
| 262 | } | 286 | } |
| ... | @@ -312,9 +336,12 @@ pub const Flags = packed struct { | ... | @@ -312,9 +336,12 @@ pub const Flags = packed struct { |
| 312 | /// Whether this symbol is weak. | 336 | /// Whether this symbol is weak. |
| 313 | weak: bool = false, | 337 | weak: bool = false, |
| 314 | 338 | ||
| 315 | /// Whether the symbol makes into the output symtab or not. | 339 | /// Whether the symbol makes into the output symtab. |
| 316 | output_symtab: bool = false, | 340 | output_symtab: bool = false, |
| 317 | 341 | ||
| 342 | /// Whether the symbol has entry in dynamic symbol table. | ||
| 343 | has_dynamic: bool = false, | ||
| 344 | |||
| 318 | /// Whether the symbol contains GOT indirection. | 345 | /// Whether the symbol contains GOT indirection. |
| 319 | needs_got: bool = false, | 346 | needs_got: bool = false, |
| 320 | has_got: bool = false, | 347 | has_got: bool = false, |
| ... | @@ -328,7 +355,6 @@ pub const Flags = packed struct { | ... | @@ -328,7 +355,6 @@ pub const Flags = packed struct { |
| 328 | /// Whether the symbol contains COPYREL directive. | 355 | /// Whether the symbol contains COPYREL directive. |
| 329 | needs_copy_rel: bool = false, | 356 | needs_copy_rel: bool = false, |
| 330 | has_copy_rel: bool = false, | 357 | has_copy_rel: bool = false, |
| 331 | has_dynamic: bool = false, | ||
| 332 | 358 | ||
| 333 | /// Whether the symbol contains TLSGD indirection. | 359 | /// Whether the symbol contains TLSGD indirection. |
| 334 | needs_tlsgd: bool = false, | 360 | needs_tlsgd: bool = false, |
| ... | @@ -365,8 +391,10 @@ const Atom = @import("Atom.zig"); | ... | @@ -365,8 +391,10 @@ const Atom = @import("Atom.zig"); |
| 365 | const Elf = @import("../Elf.zig"); | 391 | const Elf = @import("../Elf.zig"); |
| 366 | const File = @import("file.zig").File; | 392 | const File = @import("file.zig").File; |
| 367 | const GotSection = synthetic_sections.GotSection; | 393 | const GotSection = synthetic_sections.GotSection; |
| 394 | const GotPltSection = synthetic_sections.GotPltSection; | ||
| 368 | const LinkerDefined = @import("LinkerDefined.zig"); | 395 | const LinkerDefined = @import("LinkerDefined.zig"); |
| 369 | // const Object = @import("Object.zig"); | 396 | const Object = @import("Object.zig"); |
| 370 | // const SharedObject = @import("SharedObject.zig"); | 397 | const PltSection = synthetic_sections.PltSection; |
| 398 | const SharedObject = @import("SharedObject.zig"); | ||
| 371 | const Symbol = @This(); | 399 | const Symbol = @This(); |
| 372 | const ZigModule = @import("ZigModule.zig"); | 400 | const ZigModule = @import("ZigModule.zig"); |
src/link/Elf/file.zig+7-6| ... | @@ -2,7 +2,7 @@ pub const File = union(enum) { | ... | @@ -2,7 +2,7 @@ pub const File = union(enum) { |
| 2 | zig_module: *ZigModule, | 2 | zig_module: *ZigModule, |
| 3 | linker_defined: *LinkerDefined, | 3 | linker_defined: *LinkerDefined, |
| 4 | object: *Object, | 4 | object: *Object, |
| 5 | // shared_object: *SharedObject, | 5 | shared_object: *SharedObject, |
| 6 | 6 | ||
| 7 | pub fn index(file: File) Index { | 7 | pub fn index(file: File) Index { |
| 8 | return switch (file) { | 8 | return switch (file) { |
| ... | @@ -26,7 +26,7 @@ pub const File = union(enum) { | ... | @@ -26,7 +26,7 @@ pub const File = union(enum) { |
| 26 | .zig_module => |x| try writer.print("{s}", .{x.path}), | 26 | .zig_module => |x| try writer.print("{s}", .{x.path}), |
| 27 | .linker_defined => try writer.writeAll("(linker defined)"), | 27 | .linker_defined => try writer.writeAll("(linker defined)"), |
| 28 | .object => |x| try writer.print("{}", .{x.fmtPath()}), | 28 | .object => |x| try writer.print("{}", .{x.fmtPath()}), |
| 29 | // .shared_object => |x| try writer.writeAll(x.path), | 29 | .shared_object => |x| try writer.writeAll(x.path), |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
| 32 | 32 | ||
| ... | @@ -49,8 +49,7 @@ pub const File = union(enum) { | ... | @@ -49,8 +49,7 @@ pub const File = union(enum) { |
| 49 | pub fn symbolRank(file: File, sym: elf.Elf64_Sym, in_archive: bool) u32 { | 49 | pub fn symbolRank(file: File, sym: elf.Elf64_Sym, in_archive: bool) u32 { |
| 50 | const base: u3 = blk: { | 50 | const base: u3 = blk: { |
| 51 | if (sym.st_shndx == elf.SHN_COMMON) break :blk if (in_archive) 6 else 5; | 51 | if (sym.st_shndx == elf.SHN_COMMON) break :blk if (in_archive) 6 else 5; |
| 52 | // if (file == .shared or in_archive) break :blk switch (sym.st_bind()) { | 52 | if (file == .shared_object or in_archive) break :blk switch (sym.st_bind()) { |
| 53 | if (in_archive) break :blk switch (sym.st_bind()) { | ||
| 54 | elf.STB_GLOBAL => 3, | 53 | elf.STB_GLOBAL => 3, |
| 55 | else => 4, | 54 | else => 4, |
| 56 | }; | 55 | }; |
| ... | @@ -92,6 +91,7 @@ pub const File = union(enum) { | ... | @@ -92,6 +91,7 @@ pub const File = union(enum) { |
| 92 | pub fn atoms(file: File) []const Atom.Index { | 91 | pub fn atoms(file: File) []const Atom.Index { |
| 93 | return switch (file) { | 92 | return switch (file) { |
| 94 | .linker_defined => unreachable, | 93 | .linker_defined => unreachable, |
| 94 | .shared_object => unreachable, | ||
| 95 | .zig_module => |x| x.atoms.items, | 95 | .zig_module => |x| x.atoms.items, |
| 96 | .object => |x| x.atoms.items, | 96 | .object => |x| x.atoms.items, |
| 97 | }; | 97 | }; |
| ... | @@ -100,6 +100,7 @@ pub const File = union(enum) { | ... | @@ -100,6 +100,7 @@ pub const File = union(enum) { |
| 100 | pub fn locals(file: File) []const Symbol.Index { | 100 | pub fn locals(file: File) []const Symbol.Index { |
| 101 | return switch (file) { | 101 | return switch (file) { |
| 102 | .linker_defined => unreachable, | 102 | .linker_defined => unreachable, |
| 103 | .shared_object => unreachable, | ||
| 103 | inline else => |x| x.locals(), | 104 | inline else => |x| x.locals(), |
| 104 | }; | 105 | }; |
| 105 | } | 106 | } |
| ... | @@ -117,7 +118,7 @@ pub const File = union(enum) { | ... | @@ -117,7 +118,7 @@ pub const File = union(enum) { |
| 117 | zig_module: ZigModule, | 118 | zig_module: ZigModule, |
| 118 | linker_defined: LinkerDefined, | 119 | linker_defined: LinkerDefined, |
| 119 | object: Object, | 120 | object: Object, |
| 120 | // shared_object: SharedObject, | 121 | shared_object: SharedObject, |
| 121 | }; | 122 | }; |
| 122 | }; | 123 | }; |
| 123 | 124 | ||
| ... | @@ -129,6 +130,6 @@ const Atom = @import("Atom.zig"); | ... | @@ -129,6 +130,6 @@ const Atom = @import("Atom.zig"); |
| 129 | const Elf = @import("../Elf.zig"); | 130 | const Elf = @import("../Elf.zig"); |
| 130 | const LinkerDefined = @import("LinkerDefined.zig"); | 131 | const LinkerDefined = @import("LinkerDefined.zig"); |
| 131 | const Object = @import("Object.zig"); | 132 | const Object = @import("Object.zig"); |
| 132 | // const SharedObject = @import("SharedObject.zig"); | 133 | const SharedObject = @import("SharedObject.zig"); |
| 133 | const Symbol = @import("Symbol.zig"); | 134 | const Symbol = @import("Symbol.zig"); |
| 134 | const ZigModule = @import("ZigModule.zig"); | 135 | const ZigModule = @import("ZigModule.zig"); |
src/link/Elf/synthetic_sections.zig+1163-289| ... | @@ -1,3 +1,225 @@ | ... | @@ -1,3 +1,225 @@ |
| 1 | pub const DynamicSection = struct { | ||
| 2 | soname: ?u32 = null, | ||
| 3 | needed: std.ArrayListUnmanaged(u32) = .{}, | ||
| 4 | rpath: u32 = 0, | ||
| 5 | |||
| 6 | pub fn deinit(dt: *DynamicSection, allocator: Allocator) void { | ||
| 7 | dt.needed.deinit(allocator); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn addNeeded(dt: *DynamicSection, shared: *SharedObject, elf_file: *Elf) !void { | ||
| 11 | const gpa = elf_file.base.allocator; | ||
| 12 | const off = try elf_file.dynstrtab.insert(gpa, shared.getSoname()); | ||
| 13 | try dt.needed.append(gpa, off); | ||
| 14 | } | ||
| 15 | |||
| 16 | pub fn setRpath(dt: *DynamicSection, rpath_list: []const []const u8, elf_file: *Elf) !void { | ||
| 17 | if (rpath_list.len == 0) return; | ||
| 18 | const gpa = elf_file.base.allocator; | ||
| 19 | var rpath = std.ArrayList(u8).init(gpa); | ||
| 20 | defer rpath.deinit(); | ||
| 21 | for (rpath_list, 0..) |path, i| { | ||
| 22 | if (i > 0) try rpath.append(':'); | ||
| 23 | try rpath.appendSlice(path); | ||
| 24 | } | ||
| 25 | dt.rpath = try elf_file.dynstrtab.insert(gpa, rpath.items); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn setSoname(dt: *DynamicSection, soname: []const u8, elf_file: *Elf) !void { | ||
| 29 | dt.soname = try elf_file.dynstrtab.insert(elf_file.base.allocator, soname); | ||
| 30 | } | ||
| 31 | |||
| 32 | fn getFlags(dt: DynamicSection, elf_file: *Elf) ?u64 { | ||
| 33 | _ = dt; | ||
| 34 | var flags: u64 = 0; | ||
| 35 | if (elf_file.base.options.z_now) { | ||
| 36 | flags |= elf.DF_BIND_NOW; | ||
| 37 | } | ||
| 38 | for (elf_file.got.entries.items) |entry| switch (entry.tag) { | ||
| 39 | .gottp => { | ||
| 40 | flags |= elf.DF_STATIC_TLS; | ||
| 41 | break; | ||
| 42 | }, | ||
| 43 | else => {}, | ||
| 44 | }; | ||
| 45 | if (elf_file.has_text_reloc) { | ||
| 46 | flags |= elf.DF_TEXTREL; | ||
| 47 | } | ||
| 48 | return if (flags > 0) flags else null; | ||
| 49 | } | ||
| 50 | |||
| 51 | fn getFlags1(dt: DynamicSection, elf_file: *Elf) ?u64 { | ||
| 52 | _ = dt; | ||
| 53 | var flags_1: u64 = 0; | ||
| 54 | if (elf_file.base.options.z_now) { | ||
| 55 | flags_1 |= elf.DF_1_NOW; | ||
| 56 | } | ||
| 57 | if (elf_file.base.options.pie) { | ||
| 58 | flags_1 |= elf.DF_1_PIE; | ||
| 59 | } | ||
| 60 | // if (elf_file.base.options.z_nodlopen) { | ||
| 61 | // flags_1 |= elf.DF_1_NOOPEN; | ||
| 62 | // } | ||
| 63 | return if (flags_1 > 0) flags_1 else null; | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn size(dt: DynamicSection, elf_file: *Elf) usize { | ||
| 67 | var nentries: usize = 0; | ||
| 68 | nentries += dt.needed.items.len; // NEEDED | ||
| 69 | if (dt.soname != null) nentries += 1; // SONAME | ||
| 70 | if (dt.rpath > 0) nentries += 1; // RUNPATH | ||
| 71 | if (elf_file.sectionByName(".init") != null) nentries += 1; // INIT | ||
| 72 | if (elf_file.sectionByName(".fini") != null) nentries += 1; // FINI | ||
| 73 | if (elf_file.sectionByName(".init_array") != null) nentries += 2; // INIT_ARRAY | ||
| 74 | if (elf_file.sectionByName(".fini_array") != null) nentries += 2; // FINI_ARRAY | ||
| 75 | if (elf_file.rela_dyn_section_index != null) nentries += 3; // RELA | ||
| 76 | if (elf_file.rela_plt_section_index != null) nentries += 3; // JMPREL | ||
| 77 | if (elf_file.got_plt_section_index != null) nentries += 1; // PLTGOT | ||
| 78 | nentries += 1; // HASH | ||
| 79 | if (elf_file.gnu_hash_section_index != null) nentries += 1; // GNU_HASH | ||
| 80 | if (elf_file.has_text_reloc) nentries += 1; // TEXTREL | ||
| 81 | nentries += 1; // SYMTAB | ||
| 82 | nentries += 1; // SYMENT | ||
| 83 | nentries += 1; // STRTAB | ||
| 84 | nentries += 1; // STRSZ | ||
| 85 | if (elf_file.versym_section_index != null) nentries += 1; // VERSYM | ||
| 86 | if (elf_file.verneed_section_index != null) nentries += 2; // VERNEED | ||
| 87 | if (dt.getFlags(elf_file) != null) nentries += 1; // FLAGS | ||
| 88 | if (dt.getFlags1(elf_file) != null) nentries += 1; // FLAGS_1 | ||
| 89 | if (!elf_file.isDynLib()) nentries += 1; // DEBUG | ||
| 90 | nentries += 1; // NULL | ||
| 91 | return nentries * @sizeOf(elf.Elf64_Dyn); | ||
| 92 | } | ||
| 93 | |||
| 94 | pub fn write(dt: DynamicSection, elf_file: *Elf, writer: anytype) !void { | ||
| 95 | // NEEDED | ||
| 96 | for (dt.needed.items) |off| { | ||
| 97 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); | ||
| 98 | } | ||
| 99 | |||
| 100 | if (dt.soname) |off| { | ||
| 101 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); | ||
| 102 | } | ||
| 103 | |||
| 104 | // RUNPATH | ||
| 105 | // TODO add option in Options to revert to old RPATH tag | ||
| 106 | if (dt.rpath > 0) { | ||
| 107 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); | ||
| 108 | } | ||
| 109 | |||
| 110 | // INIT | ||
| 111 | if (elf_file.sectionByName(".init")) |shndx| { | ||
| 112 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 113 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); | ||
| 114 | } | ||
| 115 | |||
| 116 | // FINI | ||
| 117 | if (elf_file.sectionByName(".fini")) |shndx| { | ||
| 118 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 119 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); | ||
| 120 | } | ||
| 121 | |||
| 122 | // INIT_ARRAY | ||
| 123 | if (elf_file.sectionByName(".init_array")) |shndx| { | ||
| 124 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 125 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); | ||
| 126 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); | ||
| 127 | } | ||
| 128 | |||
| 129 | // FINI_ARRAY | ||
| 130 | if (elf_file.sectionByName(".fini_array")) |shndx| { | ||
| 131 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 132 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); | ||
| 133 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); | ||
| 134 | } | ||
| 135 | |||
| 136 | // RELA | ||
| 137 | if (elf_file.rela_dyn_section_index) |shndx| { | ||
| 138 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 139 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); | ||
| 140 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); | ||
| 141 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); | ||
| 142 | } | ||
| 143 | |||
| 144 | // JMPREL | ||
| 145 | if (elf_file.rela_plt_section_index) |shndx| { | ||
| 146 | const shdr = elf_file.shdrs.items[shndx]; | ||
| 147 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); | ||
| 148 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); | ||
| 149 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); | ||
| 150 | } | ||
| 151 | |||
| 152 | // PLTGOT | ||
| 153 | if (elf_file.got_plt_section_index) |shndx| { | ||
| 154 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 155 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); | ||
| 156 | } | ||
| 157 | |||
| 158 | { | ||
| 159 | assert(elf_file.hash_section_index != null); | ||
| 160 | const addr = elf_file.shdrs.items[elf_file.hash_section_index.?].sh_addr; | ||
| 161 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); | ||
| 162 | } | ||
| 163 | |||
| 164 | if (elf_file.gnu_hash_section_index) |shndx| { | ||
| 165 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 166 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); | ||
| 167 | } | ||
| 168 | |||
| 169 | // TEXTREL | ||
| 170 | if (elf_file.has_text_reloc) { | ||
| 171 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); | ||
| 172 | } | ||
| 173 | |||
| 174 | // SYMTAB + SYMENT | ||
| 175 | { | ||
| 176 | assert(elf_file.dynsymtab_section_index != null); | ||
| 177 | const shdr = elf_file.shdrs.items[elf_file.dynsymtab_section_index.?]; | ||
| 178 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); | ||
| 179 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); | ||
| 180 | } | ||
| 181 | |||
| 182 | // STRTAB + STRSZ | ||
| 183 | { | ||
| 184 | assert(elf_file.dynstrtab_section_index != null); | ||
| 185 | const shdr = elf_file.shdrs.items[elf_file.dynstrtab_section_index.?]; | ||
| 186 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); | ||
| 187 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); | ||
| 188 | } | ||
| 189 | |||
| 190 | // VERSYM | ||
| 191 | if (elf_file.versym_section_index) |shndx| { | ||
| 192 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 193 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); | ||
| 194 | } | ||
| 195 | |||
| 196 | // VERNEED + VERNEEDNUM | ||
| 197 | if (elf_file.verneed_section_index) |shndx| { | ||
| 198 | const addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 199 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); | ||
| 200 | try writer.writeStruct(elf.Elf64_Dyn{ | ||
| 201 | .d_tag = elf.DT_VERNEEDNUM, | ||
| 202 | .d_val = elf_file.verneed.verneed.items.len, | ||
| 203 | }); | ||
| 204 | } | ||
| 205 | |||
| 206 | // FLAGS | ||
| 207 | if (dt.getFlags(elf_file)) |flags| { | ||
| 208 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); | ||
| 209 | } | ||
| 210 | // FLAGS_1 | ||
| 211 | if (dt.getFlags1(elf_file)) |flags_1| { | ||
| 212 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); | ||
| 213 | } | ||
| 214 | |||
| 215 | // DEBUG | ||
| 216 | if (!elf_file.isDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); | ||
| 217 | |||
| 218 | // NULL | ||
| 219 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); | ||
| 220 | } | ||
| 221 | }; | ||
| 222 | |||
| 1 | pub const GotSection = struct { | 223 | pub const GotSection = struct { |
| 2 | entries: std.ArrayListUnmanaged(Entry) = .{}, | 224 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 3 | output_symtab_size: Elf.SymtabSize = .{}, | 225 | output_symtab_size: Elf.SymtabSize = .{}, |
| ... | @@ -72,44 +294,57 @@ pub const GotSection = struct { | ... | @@ -72,44 +294,57 @@ pub const GotSection = struct { |
| 72 | return index; | 294 | return index; |
| 73 | } | 295 | } |
| 74 | 296 | ||
| 75 | // pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | 297 | pub fn addTlsLdSymbol(got: *GotSection, elf_file: *Elf) !void { |
| 76 | // const index = got.next_index; | 298 | assert(got.flags.needs_tlsld); |
| 77 | // const symbol = elf_file.getSymbol(sym_index); | 299 | const index = try got.allocateEntry(elf_file.base.allocator); |
| 78 | // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true; | 300 | const entry = &got.entries.items[index]; |
| 79 | // if (symbol.getExtra(elf_file)) |extra| { | 301 | entry.tag = .tlsld; |
| 80 | // var new_extra = extra; | 302 | entry.symbol_index = undefined; // unused |
| 81 | // new_extra.tlsgd = index; | 303 | got.flags.needs_rela = true; |
| 82 | // symbol.setExtra(new_extra, elf_file); | 304 | got.tlsld_index = index; |
| 83 | // } else try symbol.addExtra(.{ .tlsgd = index }, elf_file); | 305 | } |
| 84 | // try got.symbols.append(elf_file.base.allocator, .{ .tlsgd = sym_index }); | 306 | |
| 85 | // got.next_index += 2; | 307 | pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| 86 | // } | 308 | const index = try got.allocateEntry(elf_file.base.allocator); |
| 87 | 309 | const entry = &got.entries.items[index]; | |
| 88 | // pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | 310 | entry.tag = .tlsgd; |
| 89 | // const index = got.next_index; | 311 | entry.symbol_index = sym_index; |
| 90 | // const symbol = elf_file.getSymbol(sym_index); | 312 | const symbol = elf_file.symbol(sym_index); |
| 91 | // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true; | 313 | if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true; |
| 92 | // if (symbol.getExtra(elf_file)) |extra| { | 314 | if (symbol.extra(elf_file)) |extra| { |
| 93 | // var new_extra = extra; | 315 | var new_extra = extra; |
| 94 | // new_extra.gottp = index; | 316 | new_extra.tlsgd = index; |
| 95 | // symbol.setExtra(new_extra, elf_file); | 317 | symbol.setExtra(new_extra, elf_file); |
| 96 | // } else try symbol.addExtra(.{ .gottp = index }, elf_file); | 318 | } else try symbol.addExtra(.{ .tlsgd = index }, elf_file); |
| 97 | // try got.symbols.append(elf_file.base.allocator, .{ .gottp = sym_index }); | 319 | } |
| 98 | // got.next_index += 1; | 320 | |
| 99 | // } | 321 | pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { |
| 100 | 322 | const index = try got.allocateEntry(elf_file.base.allocator); | |
| 101 | // pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | 323 | const entry = &got.entries.items[index]; |
| 102 | // const index = got.next_index; | 324 | entry.tag = .gottp; |
| 103 | // const symbol = elf_file.getSymbol(sym_index); | 325 | entry.symbol_index = sym_index; |
| 104 | // got.needs_rela = true; | 326 | const symbol = elf_file.symbol(sym_index); |
| 105 | // if (symbol.getExtra(elf_file)) |extra| { | 327 | if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true; |
| 106 | // var new_extra = extra; | 328 | if (symbol.extra(elf_file)) |extra| { |
| 107 | // new_extra.tlsdesc = index; | 329 | var new_extra = extra; |
| 108 | // symbol.setExtra(new_extra, elf_file); | 330 | new_extra.gottp = index; |
| 109 | // } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file); | 331 | symbol.setExtra(new_extra, elf_file); |
| 110 | // try got.symbols.append(elf_file.base.allocator, .{ .tlsdesc = sym_index }); | 332 | } else try symbol.addExtra(.{ .gottp = index }, elf_file); |
| 111 | // got.next_index += 2; | 333 | } |
| 112 | // } | 334 | |
| 335 | pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | ||
| 336 | const index = try got.allocateEntry(elf_file.base.allocator); | ||
| 337 | const entry = &got.entries.items[index]; | ||
| 338 | entry.tag = .tlsdesc; | ||
| 339 | entry.symbol_index = sym_index; | ||
| 340 | const symbol = elf_file.symbol(sym_index); | ||
| 341 | got.flags.needs_rela = true; | ||
| 342 | if (symbol.extra(elf_file)) |extra| { | ||
| 343 | var new_extra = extra; | ||
| 344 | new_extra.tlsdesc = index; | ||
| 345 | symbol.setExtra(new_extra, elf_file); | ||
| 346 | } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file); | ||
| 347 | } | ||
| 113 | 348 | ||
| 114 | pub fn size(got: GotSection, elf_file: *Elf) usize { | 349 | pub fn size(got: GotSection, elf_file: *Elf) usize { |
| 115 | var s: usize = 0; | 350 | var s: usize = 0; |
| ... | @@ -119,260 +354,207 @@ pub const GotSection = struct { | ... | @@ -119,260 +354,207 @@ pub const GotSection = struct { |
| 119 | return s; | 354 | return s; |
| 120 | } | 355 | } |
| 121 | 356 | ||
| 122 | pub fn writeEntry(got: *GotSection, elf_file: *Elf, index: Index) !void { | 357 | pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { |
| 123 | const entry_size: u16 = elf_file.archPtrWidthBytes(); | 358 | const is_dyn_lib = elf_file.isDynLib(); |
| 124 | // if (got.dirty) { | 359 | const apply_relocs = true; // TODO add user option for this |
| 125 | // const needed_size = got.size(elf_file); | 360 | |
| 126 | // try elf_file.growAllocSection(elf_file.got_section_index.?, needed_size); | 361 | for (got.entries.items) |entry| { |
| 127 | // got.dirty = false; | 362 | const symbol = elf_file.symbol(entry.symbol_index); |
| 128 | // } | 363 | switch (entry.tag) { |
| 364 | .got => { | ||
| 365 | const value = blk: { | ||
| 366 | const value = symbol.address(.{ .plt = false }, elf_file); | ||
| 367 | if (symbol.flags.import) break :blk 0; | ||
| 368 | if (symbol.isIFunc(elf_file)) | ||
| 369 | break :blk if (apply_relocs) value else 0; | ||
| 370 | if (elf_file.base.options.pic and !symbol.isAbs(elf_file)) | ||
| 371 | break :blk if (apply_relocs) value else 0; | ||
| 372 | break :blk value; | ||
| 373 | }; | ||
| 374 | try writeInt(value, elf_file, writer); | ||
| 375 | }, | ||
| 376 | .tlsld => { | ||
| 377 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); | ||
| 378 | try writeInt(0, elf_file, writer); | ||
| 379 | }, | ||
| 380 | .tlsgd => { | ||
| 381 | if (symbol.flags.import) { | ||
| 382 | try writeInt(0, elf_file, writer); | ||
| 383 | try writeInt(0, elf_file, writer); | ||
| 384 | } else { | ||
| 385 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); | ||
| 386 | const offset = symbol.address(.{}, elf_file) - elf_file.dtpAddress(); | ||
| 387 | try writeInt(offset, elf_file, writer); | ||
| 388 | } | ||
| 389 | }, | ||
| 390 | .gottp => { | ||
| 391 | if (symbol.flags.import) { | ||
| 392 | try writeInt(0, elf_file, writer); | ||
| 393 | } else if (is_dyn_lib) { | ||
| 394 | const offset = if (apply_relocs) | ||
| 395 | symbol.address(.{}, elf_file) - elf_file.tlsAddress() | ||
| 396 | else | ||
| 397 | 0; | ||
| 398 | try writeInt(offset, elf_file, writer); | ||
| 399 | } else { | ||
| 400 | const offset = @as(i64, @intCast(symbol.address(.{}, elf_file))) - | ||
| 401 | @as(i64, @intCast(elf_file.tpAddress())); | ||
| 402 | try writeInt(offset, elf_file, writer); | ||
| 403 | } | ||
| 404 | }, | ||
| 405 | .tlsdesc => { | ||
| 406 | try writeInt(0, elf_file, writer); | ||
| 407 | try writeInt(0, elf_file, writer); | ||
| 408 | }, | ||
| 409 | } | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { | ||
| 414 | const entry_size = elf_file.archPtrWidthBytes(); | ||
| 129 | const endian = elf_file.base.options.target.cpu.arch.endian(); | 415 | const endian = elf_file.base.options.target.cpu.arch.endian(); |
| 130 | const entry = got.entries.items[index]; | ||
| 131 | const shdr = &elf_file.shdrs.items[elf_file.got_section_index.?]; | ||
| 132 | const off = shdr.sh_offset + @as(u64, entry_size) * entry.cell_index; | ||
| 133 | const vaddr = shdr.sh_addr + @as(u64, entry_size) * entry.cell_index; | ||
| 134 | const value = elf_file.symbol(entry.symbol_index).value; | ||
| 135 | switch (entry_size) { | 416 | switch (entry_size) { |
| 136 | 2 => { | 417 | 2 => try writer.writeInt(u16, @intCast(value), endian), |
| 137 | var buf: [2]u8 = undefined; | 418 | 4 => try writer.writeInt(u32, @intCast(value), endian), |
| 138 | std.mem.writeInt(u16, &buf, @as(u16, @intCast(value)), endian); | 419 | 8 => try writer.writeInt(u64, @intCast(value), endian), |
| 139 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 140 | }, | ||
| 141 | 4 => { | ||
| 142 | var buf: [4]u8 = undefined; | ||
| 143 | std.mem.writeInt(u32, &buf, @as(u32, @intCast(value)), endian); | ||
| 144 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 145 | }, | ||
| 146 | 8 => { | ||
| 147 | var buf: [8]u8 = undefined; | ||
| 148 | std.mem.writeInt(u64, &buf, value, endian); | ||
| 149 | try elf_file.base.file.?.pwriteAll(&buf, off); | ||
| 150 | |||
| 151 | if (elf_file.base.child_pid) |pid| { | ||
| 152 | switch (builtin.os.tag) { | ||
| 153 | .linux => { | ||
| 154 | var local_vec: [1]std.os.iovec_const = .{.{ | ||
| 155 | .iov_base = &buf, | ||
| 156 | .iov_len = buf.len, | ||
| 157 | }}; | ||
| 158 | var remote_vec: [1]std.os.iovec_const = .{.{ | ||
| 159 | .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))), | ||
| 160 | .iov_len = buf.len, | ||
| 161 | }}; | ||
| 162 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); | ||
| 163 | switch (std.os.errno(rc)) { | ||
| 164 | .SUCCESS => assert(rc == buf.len), | ||
| 165 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), | ||
| 166 | } | ||
| 167 | }, | ||
| 168 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | ||
| 169 | } | ||
| 170 | } | ||
| 171 | }, | ||
| 172 | else => unreachable, | 420 | else => unreachable, |
| 173 | } | 421 | } |
| 174 | } | 422 | } |
| 175 | 423 | ||
| 176 | pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { | 424 | pub fn addRela(got: GotSection, elf_file: *Elf) !void { |
| 177 | const entry_size: u16 = elf_file.archPtrWidthBytes(); | 425 | const is_dyn_lib = elf_file.isDynLib(); |
| 178 | const endian = elf_file.base.options.target.cpu.arch.endian(); | 426 | try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file)); |
| 427 | |||
| 179 | for (got.entries.items) |entry| { | 428 | for (got.entries.items) |entry| { |
| 180 | const value = elf_file.symbol(entry.symbol_index).value; | 429 | const symbol = switch (entry.tag) { |
| 181 | switch (entry_size) { | 430 | .tlsld => null, |
| 182 | 2 => try writer.writeInt(u16, @intCast(value), endian), | 431 | inline else => elf_file.symbol(entry.symbol_index), |
| 183 | 4 => try writer.writeInt(u32, @intCast(value), endian), | 432 | }; |
| 184 | 8 => try writer.writeInt(u64, @intCast(value), endian), | 433 | const extra = if (symbol) |s| s.extra(elf_file).? else null; |
| 185 | else => unreachable, | 434 | |
| 435 | switch (entry.tag) { | ||
| 436 | .got => { | ||
| 437 | const offset = symbol.?.gotAddress(elf_file); | ||
| 438 | if (symbol.?.flags.import) { | ||
| 439 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 440 | .offset = offset, | ||
| 441 | .sym = extra.?.dynamic, | ||
| 442 | .type = elf.R_X86_64_GLOB_DAT, | ||
| 443 | }); | ||
| 444 | continue; | ||
| 445 | } | ||
| 446 | if (symbol.?.isIFunc(elf_file)) { | ||
| 447 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 448 | .offset = offset, | ||
| 449 | .type = elf.R_X86_64_IRELATIVE, | ||
| 450 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | ||
| 451 | }); | ||
| 452 | continue; | ||
| 453 | } | ||
| 454 | if (elf_file.base.options.pic and !symbol.?.isAbs(elf_file)) { | ||
| 455 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 456 | .offset = offset, | ||
| 457 | .type = elf.R_X86_64_RELATIVE, | ||
| 458 | .addend = @intCast(symbol.?.address(.{ .plt = false }, elf_file)), | ||
| 459 | }); | ||
| 460 | } | ||
| 461 | }, | ||
| 462 | |||
| 463 | .tlsld => { | ||
| 464 | if (is_dyn_lib) { | ||
| 465 | const offset = entry.address(elf_file); | ||
| 466 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 467 | .offset = offset, | ||
| 468 | .type = elf.R_X86_64_DTPMOD64, | ||
| 469 | }); | ||
| 470 | } | ||
| 471 | }, | ||
| 472 | |||
| 473 | .tlsgd => { | ||
| 474 | const offset = symbol.?.tlsGdAddress(elf_file); | ||
| 475 | if (symbol.?.flags.import) { | ||
| 476 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 477 | .offset = offset, | ||
| 478 | .sym = extra.?.dynamic, | ||
| 479 | .type = elf.R_X86_64_DTPMOD64, | ||
| 480 | }); | ||
| 481 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 482 | .offset = offset + 8, | ||
| 483 | .sym = extra.?.dynamic, | ||
| 484 | .type = elf.R_X86_64_DTPOFF64, | ||
| 485 | }); | ||
| 486 | } else if (is_dyn_lib) { | ||
| 487 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 488 | .offset = offset, | ||
| 489 | .sym = extra.?.dynamic, | ||
| 490 | .type = elf.R_X86_64_DTPMOD64, | ||
| 491 | }); | ||
| 492 | } | ||
| 493 | }, | ||
| 494 | |||
| 495 | .gottp => { | ||
| 496 | const offset = symbol.?.gotTpAddress(elf_file); | ||
| 497 | if (symbol.?.flags.import) { | ||
| 498 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 499 | .offset = offset, | ||
| 500 | .sym = extra.?.dynamic, | ||
| 501 | .type = elf.R_X86_64_TPOFF64, | ||
| 502 | }); | ||
| 503 | } else if (is_dyn_lib) { | ||
| 504 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 505 | .offset = offset, | ||
| 506 | .type = elf.R_X86_64_TPOFF64, | ||
| 507 | .addend = @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), | ||
| 508 | }); | ||
| 509 | } | ||
| 510 | }, | ||
| 511 | |||
| 512 | .tlsdesc => { | ||
| 513 | const offset = symbol.?.tlsDescAddress(elf_file); | ||
| 514 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 515 | .offset = offset, | ||
| 516 | .sym = extra.?.dynamic, | ||
| 517 | .type = elf.R_X86_64_TLSDESC, | ||
| 518 | }); | ||
| 519 | }, | ||
| 186 | } | 520 | } |
| 187 | } | 521 | } |
| 188 | } | 522 | } |
| 189 | 523 | ||
| 190 | // pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void { | 524 | pub fn numRela(got: GotSection, elf_file: *Elf) usize { |
| 191 | // const is_shared = elf_file.options.output_mode == .lib; | 525 | const is_dyn_lib = elf_file.isDynLib(); |
| 192 | // const apply_relocs = elf_file.options.apply_dynamic_relocs; | 526 | var num: usize = 0; |
| 193 | 527 | for (got.entries.items) |entry| { | |
| 194 | // for (got.symbols.items) |sym| { | 528 | const symbol = switch (entry.tag) { |
| 195 | // const symbol = elf_file.getSymbol(sym.getIndex()); | 529 | .tlsld => null, |
| 196 | // switch (sym) { | 530 | inline else => elf_file.symbol(entry.symbol_index), |
| 197 | // .got => { | 531 | }; |
| 198 | // const value: u64 = blk: { | 532 | switch (entry.tag) { |
| 199 | // const value = symbol.getAddress(.{ .plt = false }, elf_file); | 533 | .got => if (symbol.?.flags.import or |
| 200 | // if (symbol.flags.import) break :blk 0; | 534 | symbol.?.isIFunc(elf_file) or (elf_file.base.options.pic and !symbol.?.isAbs(elf_file))) |
| 201 | // if (symbol.isIFunc(elf_file)) | 535 | { |
| 202 | // break :blk if (apply_relocs) value else 0; | 536 | num += 1; |
| 203 | // if (elf_file.options.pic and !symbol.isAbs(elf_file)) | 537 | }, |
| 204 | // break :blk if (apply_relocs) value else 0; | 538 | |
| 205 | // break :blk value; | 539 | .tlsld => if (is_dyn_lib) { |
| 206 | // }; | 540 | num += 1; |
| 207 | // try writer.writeIntLittle(u64, value); | 541 | }, |
| 208 | // }, | 542 | |
| 209 | 543 | .tlsgd => if (symbol.?.flags.import) { | |
| 210 | // .tlsgd => { | 544 | num += 2; |
| 211 | // if (symbol.flags.import) { | 545 | } else if (is_dyn_lib) { |
| 212 | // try writer.writeIntLittle(u64, 0); | 546 | num += 1; |
| 213 | // try writer.writeIntLittle(u64, 0); | 547 | }, |
| 214 | // } else { | 548 | |
| 215 | // try writer.writeIntLittle(u64, if (is_shared) @as(u64, 0) else 1); | 549 | .gottp => if (symbol.?.flags.import or is_dyn_lib) { |
| 216 | // const offset = symbol.getAddress(.{}, elf_file) - elf_file.getDtpAddress(); | 550 | num += 1; |
| 217 | // try writer.writeIntLittle(u64, offset); | 551 | }, |
| 218 | // } | 552 | |
| 219 | // }, | 553 | .tlsdesc => num += 1, |
| 220 | 554 | } | |
| 221 | // .gottp => { | 555 | } |
| 222 | // if (symbol.flags.import) { | 556 | return num; |
| 223 | // try writer.writeIntLittle(u64, 0); | 557 | } |
| 224 | // } else if (is_shared) { | ||
| 225 | // const offset = if (apply_relocs) | ||
| 226 | // symbol.getAddress(.{}, elf_file) - elf_file.getTlsAddress() | ||
| 227 | // else | ||
| 228 | // 0; | ||
| 229 | // try writer.writeIntLittle(u64, offset); | ||
| 230 | // } else { | ||
| 231 | // const offset = @as(i64, @intCast(symbol.getAddress(.{}, elf_file))) - | ||
| 232 | // @as(i64, @intCast(elf_file.getTpAddress())); | ||
| 233 | // try writer.writeIntLittle(u64, @as(u64, @bitCast(offset))); | ||
| 234 | // } | ||
| 235 | // }, | ||
| 236 | |||
| 237 | // .tlsdesc => { | ||
| 238 | // try writer.writeIntLittle(u64, 0); | ||
| 239 | // try writer.writeIntLittle(u64, 0); | ||
| 240 | // }, | ||
| 241 | // } | ||
| 242 | // } | ||
| 243 | |||
| 244 | // if (got.emit_tlsld) { | ||
| 245 | // try writer.writeIntLittle(u64, if (is_shared) @as(u64, 0) else 1); | ||
| 246 | // try writer.writeIntLittle(u64, 0); | ||
| 247 | // } | ||
| 248 | // } | ||
| 249 | |||
| 250 | // pub fn addRela(got: GotSection, elf_file: *Elf) !void { | ||
| 251 | // const is_shared = elf_file.options.output_mode == .lib; | ||
| 252 | // try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file)); | ||
| 253 | |||
| 254 | // for (got.symbols.items) |sym| { | ||
| 255 | // const symbol = elf_file.getSymbol(sym.getIndex()); | ||
| 256 | // const extra = symbol.getExtra(elf_file).?; | ||
| 257 | |||
| 258 | // switch (sym) { | ||
| 259 | // .got => { | ||
| 260 | // const offset = symbol.gotAddress(elf_file); | ||
| 261 | |||
| 262 | // if (symbol.flags.import) { | ||
| 263 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 264 | // .offset = offset, | ||
| 265 | // .sym = extra.dynamic, | ||
| 266 | // .type = elf.R_X86_64_GLOB_DAT, | ||
| 267 | // }); | ||
| 268 | // continue; | ||
| 269 | // } | ||
| 270 | |||
| 271 | // if (symbol.isIFunc(elf_file)) { | ||
| 272 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 273 | // .offset = offset, | ||
| 274 | // .type = elf.R_X86_64_IRELATIVE, | ||
| 275 | // .addend = @intCast(symbol.getAddress(.{ .plt = false }, elf_file)), | ||
| 276 | // }); | ||
| 277 | // continue; | ||
| 278 | // } | ||
| 279 | |||
| 280 | // if (elf_file.options.pic and !symbol.isAbs(elf_file)) { | ||
| 281 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 282 | // .offset = offset, | ||
| 283 | // .type = elf.R_X86_64_RELATIVE, | ||
| 284 | // .addend = @intCast(symbol.getAddress(.{ .plt = false }, elf_file)), | ||
| 285 | // }); | ||
| 286 | // } | ||
| 287 | // }, | ||
| 288 | |||
| 289 | // .tlsgd => { | ||
| 290 | // const offset = symbol.getTlsGdAddress(elf_file); | ||
| 291 | // if (symbol.flags.import) { | ||
| 292 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 293 | // .offset = offset, | ||
| 294 | // .sym = extra.dynamic, | ||
| 295 | // .type = elf.R_X86_64_DTPMOD64, | ||
| 296 | // }); | ||
| 297 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 298 | // .offset = offset + 8, | ||
| 299 | // .sym = extra.dynamic, | ||
| 300 | // .type = elf.R_X86_64_DTPOFF64, | ||
| 301 | // }); | ||
| 302 | // } else if (is_shared) { | ||
| 303 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 304 | // .offset = offset, | ||
| 305 | // .sym = extra.dynamic, | ||
| 306 | // .type = elf.R_X86_64_DTPMOD64, | ||
| 307 | // }); | ||
| 308 | // } | ||
| 309 | // }, | ||
| 310 | |||
| 311 | // .gottp => { | ||
| 312 | // const offset = symbol.getGotTpAddress(elf_file); | ||
| 313 | // if (symbol.flags.import) { | ||
| 314 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 315 | // .offset = offset, | ||
| 316 | // .sym = extra.dynamic, | ||
| 317 | // .type = elf.R_X86_64_TPOFF64, | ||
| 318 | // }); | ||
| 319 | // } else if (is_shared) { | ||
| 320 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 321 | // .offset = offset, | ||
| 322 | // .type = elf.R_X86_64_TPOFF64, | ||
| 323 | // .addend = @intCast(symbol.getAddress(.{}, elf_file) - elf_file.getTlsAddress()), | ||
| 324 | // }); | ||
| 325 | // } | ||
| 326 | // }, | ||
| 327 | |||
| 328 | // .tlsdesc => { | ||
| 329 | // const offset = symbol.getTlsDescAddress(elf_file); | ||
| 330 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 331 | // .offset = offset, | ||
| 332 | // .sym = extra.dynamic, | ||
| 333 | // .type = elf.R_X86_64_TLSDESC, | ||
| 334 | // }); | ||
| 335 | // }, | ||
| 336 | // } | ||
| 337 | // } | ||
| 338 | |||
| 339 | // if (is_shared and got.emit_tlsld) { | ||
| 340 | // const offset = elf_file.getTlsLdAddress(); | ||
| 341 | // elf_file.addRelaDynAssumeCapacity(.{ | ||
| 342 | // .offset = offset, | ||
| 343 | // .type = elf.R_X86_64_DTPMOD64, | ||
| 344 | // }); | ||
| 345 | // } | ||
| 346 | // } | ||
| 347 | |||
| 348 | // pub fn numRela(got: GotSection, elf_file: *Elf) usize { | ||
| 349 | // const is_shared = elf_file.options.output_mode == .lib; | ||
| 350 | // var num: usize = 0; | ||
| 351 | // for (got.symbols.items) |sym| { | ||
| 352 | // const symbol = elf_file.symbol(sym.index()); | ||
| 353 | // switch (sym) { | ||
| 354 | // .got => if (symbol.flags.import or | ||
| 355 | // symbol.isIFunc(elf_file) or (elf_file.options.pic and !symbol.isAbs(elf_file))) | ||
| 356 | // { | ||
| 357 | // num += 1; | ||
| 358 | // }, | ||
| 359 | |||
| 360 | // .tlsgd => if (symbol.flags.import) { | ||
| 361 | // num += 2; | ||
| 362 | // } else if (is_shared) { | ||
| 363 | // num += 1; | ||
| 364 | // }, | ||
| 365 | |||
| 366 | // .gottp => if (symbol.flags.import or is_shared) { | ||
| 367 | // num += 1; | ||
| 368 | // }, | ||
| 369 | |||
| 370 | // .tlsdesc => num += 1, | ||
| 371 | // } | ||
| 372 | // } | ||
| 373 | // if (is_shared and got.emit_tlsld) num += 1; | ||
| 374 | // return num; | ||
| 375 | // } | ||
| 376 | 558 | ||
| 377 | pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void { | 559 | pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void { |
| 378 | _ = elf_file; | 560 | _ = elf_file; |
| ... | @@ -382,8 +564,11 @@ pub const GotSection = struct { | ... | @@ -382,8 +564,11 @@ pub const GotSection = struct { |
| 382 | pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void { | 564 | pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void { |
| 383 | const gpa = elf_file.base.allocator; | 565 | const gpa = elf_file.base.allocator; |
| 384 | for (got.entries.items) |entry| { | 566 | for (got.entries.items) |entry| { |
| 385 | const symbol = elf_file.symbol(entry.symbol_index); | 567 | const symbol_name = switch (entry.tag) { |
| 386 | const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol.name(elf_file), @tagName(entry.tag) }); | 568 | .tlsld => "", |
| 569 | inline else => elf_file.symbol(entry.symbol_index).name(elf_file), | ||
| 570 | }; | ||
| 571 | const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) }); | ||
| 387 | defer gpa.free(name); | 572 | defer gpa.free(name); |
| 388 | _ = try elf_file.strtab.insert(gpa, name); | 573 | _ = try elf_file.strtab.insert(gpa, name); |
| 389 | } | 574 | } |
| ... | @@ -392,14 +577,18 @@ pub const GotSection = struct { | ... | @@ -392,14 +577,18 @@ pub const GotSection = struct { |
| 392 | pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void { | 577 | pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void { |
| 393 | const gpa = elf_file.base.allocator; | 578 | const gpa = elf_file.base.allocator; |
| 394 | for (got.entries.items, ctx.ilocal..) |entry, ilocal| { | 579 | for (got.entries.items, ctx.ilocal..) |entry, ilocal| { |
| 395 | const symbol = elf_file.symbol(entry.symbol_index); | 580 | const symbol = switch (entry.tag) { |
| 396 | const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol.name(elf_file), @tagName(entry.tag) }); | 581 | .tlsld => null, |
| 582 | inline else => elf_file.symbol(entry.symbol_index), | ||
| 583 | }; | ||
| 584 | const symbol_name = switch (entry.tag) { | ||
| 585 | .tlsld => "", | ||
| 586 | inline else => symbol.?.name(elf_file), | ||
| 587 | }; | ||
| 588 | const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol_name, @tagName(entry.tag) }); | ||
| 397 | defer gpa.free(name); | 589 | defer gpa.free(name); |
| 398 | const st_name = try elf_file.strtab.insert(gpa, name); | 590 | const st_name = try elf_file.strtab.insert(gpa, name); |
| 399 | const st_value = switch (entry.tag) { | 591 | const st_value = entry.address(elf_file); |
| 400 | .got => symbol.gotAddress(elf_file), | ||
| 401 | else => unreachable, | ||
| 402 | }; | ||
| 403 | const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes(); | 592 | const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes(); |
| 404 | ctx.symtab[ilocal] = .{ | 593 | ctx.symtab[ilocal] = .{ |
| 405 | .st_name = st_name, | 594 | .st_name = st_name, |
| ... | @@ -443,12 +632,697 @@ pub const GotSection = struct { | ... | @@ -443,12 +632,697 @@ pub const GotSection = struct { |
| 443 | } | 632 | } |
| 444 | }; | 633 | }; |
| 445 | 634 | ||
| 635 | pub const PltSection = struct { | ||
| 636 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 637 | output_symtab_size: Elf.SymtabSize = .{}, | ||
| 638 | |||
| 639 | pub const preamble_size = 32; | ||
| 640 | |||
| 641 | pub fn deinit(plt: *PltSection, allocator: Allocator) void { | ||
| 642 | plt.symbols.deinit(allocator); | ||
| 643 | } | ||
| 644 | |||
| 645 | pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | ||
| 646 | const index = @as(u32, @intCast(plt.symbols.items.len)); | ||
| 647 | const symbol = elf_file.symbol(sym_index); | ||
| 648 | if (symbol.extra(elf_file)) |extra| { | ||
| 649 | var new_extra = extra; | ||
| 650 | new_extra.plt = index; | ||
| 651 | symbol.setExtra(new_extra, elf_file); | ||
| 652 | } else try symbol.addExtra(.{ .plt = index }, elf_file); | ||
| 653 | try plt.symbols.append(elf_file.base.allocator, sym_index); | ||
| 654 | } | ||
| 655 | |||
| 656 | pub fn size(plt: PltSection) usize { | ||
| 657 | return preamble_size + plt.symbols.items.len * 16; | ||
| 658 | } | ||
| 659 | |||
| 660 | pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { | ||
| 661 | const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; | ||
| 662 | const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; | ||
| 663 | var preamble = [_]u8{ | ||
| 664 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | ||
| 665 | 0x41, 0x53, // push r11 | ||
| 666 | 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push qword ptr [rip] -> .got.plt[1] | ||
| 667 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[2] | ||
| 668 | }; | ||
| 669 | var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; | ||
| 670 | mem.writeIntLittle(i32, preamble[8..][0..4], @as(i32, @intCast(disp))); | ||
| 671 | disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; | ||
| 672 | mem.writeIntLittle(i32, preamble[14..][0..4], @as(i32, @intCast(disp))); | ||
| 673 | try writer.writeAll(&preamble); | ||
| 674 | try writer.writeByteNTimes(0xcc, preamble_size - preamble.len); | ||
| 675 | |||
| 676 | for (plt.symbols.items, 0..) |sym_index, i| { | ||
| 677 | const sym = elf_file.symbol(sym_index); | ||
| 678 | const target_addr = sym.gotPltAddress(elf_file); | ||
| 679 | const source_addr = sym.pltAddress(elf_file); | ||
| 680 | disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; | ||
| 681 | var entry = [_]u8{ | ||
| 682 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | ||
| 683 | 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N | ||
| 684 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] | ||
| 685 | }; | ||
| 686 | mem.writeIntLittle(i32, entry[6..][0..4], @as(i32, @intCast(i))); | ||
| 687 | mem.writeIntLittle(i32, entry[12..][0..4], @as(i32, @intCast(disp))); | ||
| 688 | try writer.writeAll(&entry); | ||
| 689 | } | ||
| 690 | } | ||
| 691 | |||
| 692 | pub fn addRela(plt: PltSection, elf_file: *Elf) !void { | ||
| 693 | try elf_file.rela_plt.ensureUnusedCapacity(elf_file.base.allocator, plt.numRela()); | ||
| 694 | for (plt.symbols.items) |sym_index| { | ||
| 695 | const sym = elf_file.symbol(sym_index); | ||
| 696 | assert(sym.flags.import); | ||
| 697 | const extra = sym.extra(elf_file).?; | ||
| 698 | const r_offset = sym.gotPltAddress(elf_file); | ||
| 699 | const r_sym: u64 = extra.dynamic; | ||
| 700 | const r_type: u32 = elf.R_X86_64_JUMP_SLOT; | ||
| 701 | elf_file.rela_plt.appendAssumeCapacity(.{ | ||
| 702 | .r_offset = r_offset, | ||
| 703 | .r_info = (r_sym << 32) | r_type, | ||
| 704 | .r_addend = 0, | ||
| 705 | }); | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | pub fn numRela(plt: PltSection) usize { | ||
| 710 | return plt.symbols.items.len; | ||
| 711 | } | ||
| 712 | |||
| 713 | pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void { | ||
| 714 | _ = elf_file; | ||
| 715 | plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len)); | ||
| 716 | } | ||
| 717 | |||
| 718 | pub fn updateStrtab(plt: PltSection, elf_file: *Elf) !void { | ||
| 719 | const gpa = elf_file.base.allocator; | ||
| 720 | for (plt.symbols.items) |sym_index| { | ||
| 721 | const sym = elf_file.symbol(sym_index); | ||
| 722 | const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)}); | ||
| 723 | defer gpa.free(name); | ||
| 724 | _ = try elf_file.strtab.insert(gpa, name); | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) !void { | ||
| 729 | const gpa = elf_file.base.allocator; | ||
| 730 | |||
| 731 | var ilocal = ctx.ilocal; | ||
| 732 | for (plt.symbols.items) |sym_index| { | ||
| 733 | const sym = elf_file.symbol(sym_index); | ||
| 734 | const name = try std.fmt.allocPrint(gpa, "{s}$plt", .{sym.name(elf_file)}); | ||
| 735 | defer gpa.free(name); | ||
| 736 | const st_name = try elf_file.strtab.insert(gpa, name); | ||
| 737 | ctx.symtab[ilocal] = .{ | ||
| 738 | .st_name = st_name, | ||
| 739 | .st_info = elf.STT_FUNC, | ||
| 740 | .st_other = 0, | ||
| 741 | .st_shndx = elf_file.plt_section_index.?, | ||
| 742 | .st_value = sym.pltAddress(elf_file), | ||
| 743 | .st_size = 16, | ||
| 744 | }; | ||
| 745 | ilocal += 1; | ||
| 746 | } | ||
| 747 | } | ||
| 748 | }; | ||
| 749 | |||
| 750 | pub const GotPltSection = struct { | ||
| 751 | pub const preamble_size = 24; | ||
| 752 | |||
| 753 | pub fn size(got_plt: GotPltSection, elf_file: *Elf) usize { | ||
| 754 | _ = got_plt; | ||
| 755 | return preamble_size + elf_file.plt.symbols.items.len * 8; | ||
| 756 | } | ||
| 757 | |||
| 758 | pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: anytype) !void { | ||
| 759 | _ = got_plt; | ||
| 760 | { | ||
| 761 | // [0]: _DYNAMIC | ||
| 762 | const symbol = elf_file.symbol(elf_file.dynamic_index.?); | ||
| 763 | try writer.writeIntLittle(u64, symbol.value); | ||
| 764 | } | ||
| 765 | // [1]: 0x0 | ||
| 766 | // [2]: 0x0 | ||
| 767 | try writer.writeIntLittle(u64, 0x0); | ||
| 768 | try writer.writeIntLittle(u64, 0x0); | ||
| 769 | if (elf_file.plt_section_index) |shndx| { | ||
| 770 | const plt_addr = elf_file.shdrs.items[shndx].sh_addr; | ||
| 771 | for (0..elf_file.plt.symbols.items.len) |_| { | ||
| 772 | // [N]: .plt | ||
| 773 | try writer.writeIntLittle(u64, plt_addr); | ||
| 774 | } | ||
| 775 | } | ||
| 776 | } | ||
| 777 | }; | ||
| 778 | |||
| 779 | pub const PltGotSection = struct { | ||
| 780 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 781 | output_symtab_size: Elf.SymtabSize = .{}, | ||
| 782 | |||
| 783 | pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void { | ||
| 784 | plt_got.symbols.deinit(allocator); | ||
| 785 | } | ||
| 786 | |||
| 787 | pub fn addSymbol(plt_got: *PltGotSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | ||
| 788 | const index = @as(u32, @intCast(plt_got.symbols.items.len)); | ||
| 789 | const symbol = elf_file.symbol(sym_index); | ||
| 790 | if (symbol.extra(elf_file)) |extra| { | ||
| 791 | var new_extra = extra; | ||
| 792 | new_extra.plt_got = index; | ||
| 793 | symbol.setExtra(new_extra, elf_file); | ||
| 794 | } else try symbol.addExtra(.{ .plt_got = index }, elf_file); | ||
| 795 | try plt_got.symbols.append(elf_file.base.allocator, sym_index); | ||
| 796 | } | ||
| 797 | |||
| 798 | pub fn size(plt_got: PltGotSection) usize { | ||
| 799 | return plt_got.symbols.items.len * 16; | ||
| 800 | } | ||
| 801 | |||
| 802 | pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { | ||
| 803 | for (plt_got.symbols.items) |sym_index| { | ||
| 804 | const sym = elf_file.symbol(sym_index); | ||
| 805 | const target_addr = sym.gotAddress(elf_file); | ||
| 806 | const source_addr = sym.pltGotAddress(elf_file); | ||
| 807 | const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4; | ||
| 808 | var entry = [_]u8{ | ||
| 809 | 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 | ||
| 810 | 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got[N] | ||
| 811 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, | ||
| 812 | }; | ||
| 813 | mem.writeIntLittle(i32, entry[6..][0..4], @as(i32, @intCast(disp))); | ||
| 814 | try writer.writeAll(&entry); | ||
| 815 | } | ||
| 816 | } | ||
| 817 | |||
| 818 | pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void { | ||
| 819 | _ = elf_file; | ||
| 820 | plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len)); | ||
| 821 | } | ||
| 822 | |||
| 823 | pub fn updateStrtab(plt_got: PltGotSection, elf_file: *Elf) !void { | ||
| 824 | const gpa = elf_file.base.allocator; | ||
| 825 | for (plt_got.symbols.items) |sym_index| { | ||
| 826 | const sym = elf_file.symbol(sym_index); | ||
| 827 | const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)}); | ||
| 828 | defer gpa.free(name); | ||
| 829 | _ = try elf_file.strtab.insert(gpa, name); | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) !void { | ||
| 834 | const gpa = elf_file.base.allocator; | ||
| 835 | var ilocal = ctx.ilocal; | ||
| 836 | for (plt_got.symbols.items) |sym_index| { | ||
| 837 | const sym = elf_file.symbol(sym_index); | ||
| 838 | const name = try std.fmt.allocPrint(gpa, "{s}$pltgot", .{sym.name(elf_file)}); | ||
| 839 | defer gpa.free(name); | ||
| 840 | const st_name = try elf_file.strtab.insert(gpa, name); | ||
| 841 | ctx.symtab[ilocal] = .{ | ||
| 842 | .st_name = st_name, | ||
| 843 | .st_info = elf.STT_FUNC, | ||
| 844 | .st_other = 0, | ||
| 845 | .st_shndx = elf_file.plt_got_section_index.?, | ||
| 846 | .st_value = sym.pltGotAddress(elf_file), | ||
| 847 | .st_size = 16, | ||
| 848 | }; | ||
| 849 | ilocal += 1; | ||
| 850 | } | ||
| 851 | } | ||
| 852 | }; | ||
| 853 | |||
| 854 | pub const CopyRelSection = struct { | ||
| 855 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | ||
| 856 | |||
| 857 | pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void { | ||
| 858 | copy_rel.symbols.deinit(allocator); | ||
| 859 | } | ||
| 860 | |||
| 861 | pub fn addSymbol(copy_rel: *CopyRelSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | ||
| 862 | const index = @as(u32, @intCast(copy_rel.symbols.items.len)); | ||
| 863 | const symbol = elf_file.symbol(sym_index); | ||
| 864 | symbol.flags.import = true; | ||
| 865 | symbol.flags.@"export" = true; | ||
| 866 | symbol.flags.has_copy_rel = true; | ||
| 867 | symbol.flags.weak = false; | ||
| 868 | |||
| 869 | if (symbol.extra(elf_file)) |extra| { | ||
| 870 | var new_extra = extra; | ||
| 871 | new_extra.copy_rel = index; | ||
| 872 | symbol.setExtra(new_extra, elf_file); | ||
| 873 | } else try symbol.addExtra(.{ .copy_rel = index }, elf_file); | ||
| 874 | try copy_rel.symbols.append(elf_file.base.allocator, sym_index); | ||
| 875 | |||
| 876 | const shared_object = symbol.file(elf_file).?.shared_object; | ||
| 877 | if (shared_object.aliases == null) { | ||
| 878 | try shared_object.initSymbolAliases(elf_file); | ||
| 879 | } | ||
| 880 | |||
| 881 | const aliases = shared_object.symbolAliases(sym_index, elf_file); | ||
| 882 | for (aliases) |alias| { | ||
| 883 | if (alias == sym_index) continue; | ||
| 884 | const alias_sym = elf_file.symbol(alias); | ||
| 885 | alias_sym.flags.import = true; | ||
| 886 | alias_sym.flags.@"export" = true; | ||
| 887 | alias_sym.flags.has_copy_rel = true; | ||
| 888 | alias_sym.flags.needs_copy_rel = true; | ||
| 889 | alias_sym.flags.weak = false; | ||
| 890 | try elf_file.dynsym.addSymbol(alias, elf_file); | ||
| 891 | } | ||
| 892 | } | ||
| 893 | |||
| 894 | pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u16, elf_file: *Elf) !void { | ||
| 895 | const shdr = &elf_file.shdrs.items[shndx]; | ||
| 896 | for (copy_rel.symbols.items) |sym_index| { | ||
| 897 | const symbol = elf_file.symbol(sym_index); | ||
| 898 | const shared_object = symbol.file(elf_file).?.shared_object; | ||
| 899 | const alignment = try symbol.dsoAlignment(elf_file); | ||
| 900 | symbol.value = mem.alignForward(u64, shdr.sh_size, alignment); | ||
| 901 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment); | ||
| 902 | shdr.sh_size = symbol.value + symbol.elfSym(elf_file).st_size; | ||
| 903 | |||
| 904 | const aliases = shared_object.symbolAliases(sym_index, elf_file); | ||
| 905 | for (aliases) |alias| { | ||
| 906 | if (alias == sym_index) continue; | ||
| 907 | const alias_sym = elf_file.symbol(alias); | ||
| 908 | alias_sym.value = symbol.value; | ||
| 909 | } | ||
| 910 | } | ||
| 911 | } | ||
| 912 | |||
| 913 | pub fn addRela(copy_rel: CopyRelSection, elf_file: *Elf) !void { | ||
| 914 | try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, copy_rel.numRela()); | ||
| 915 | for (copy_rel.symbols.items) |sym_index| { | ||
| 916 | const sym = elf_file.symbol(sym_index); | ||
| 917 | assert(sym.flags.import and sym.flags.has_copy_rel); | ||
| 918 | const extra = sym.extra(elf_file).?; | ||
| 919 | elf_file.addRelaDynAssumeCapacity(.{ | ||
| 920 | .offset = sym.address(.{}, elf_file), | ||
| 921 | .sym = extra.dynamic, | ||
| 922 | .type = elf.R_X86_64_COPY, | ||
| 923 | }); | ||
| 924 | } | ||
| 925 | } | ||
| 926 | |||
| 927 | pub fn numRela(copy_rel: CopyRelSection) usize { | ||
| 928 | return copy_rel.symbols.items.len; | ||
| 929 | } | ||
| 930 | }; | ||
| 931 | |||
| 932 | pub const DynsymSection = struct { | ||
| 933 | entries: std.ArrayListUnmanaged(Entry) = .{}, | ||
| 934 | |||
| 935 | pub const Entry = struct { | ||
| 936 | /// Index of the symbol which gets privilege of getting a dynamic treatment | ||
| 937 | symbol_index: Symbol.Index, | ||
| 938 | /// Offset into .dynstrtab | ||
| 939 | off: u32, | ||
| 940 | }; | ||
| 941 | |||
| 942 | pub fn deinit(dynsym: *DynsymSection, allocator: Allocator) void { | ||
| 943 | dynsym.entries.deinit(allocator); | ||
| 944 | } | ||
| 945 | |||
| 946 | pub fn addSymbol(dynsym: *DynsymSection, sym_index: Symbol.Index, elf_file: *Elf) !void { | ||
| 947 | const gpa = elf_file.base.allocator; | ||
| 948 | const index = @as(u32, @intCast(dynsym.entries.items.len + 1)); | ||
| 949 | const sym = elf_file.symbol(sym_index); | ||
| 950 | sym.flags.has_dynamic = true; | ||
| 951 | if (sym.extra(elf_file)) |extra| { | ||
| 952 | var new_extra = extra; | ||
| 953 | new_extra.dynamic = index; | ||
| 954 | sym.setExtra(new_extra, elf_file); | ||
| 955 | } else try sym.addExtra(.{ .dynamic = index }, elf_file); | ||
| 956 | const off = try elf_file.dynstrtab.insert(gpa, sym.name(elf_file)); | ||
| 957 | try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off }); | ||
| 958 | } | ||
| 959 | |||
| 960 | pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void { | ||
| 961 | const Sort = struct { | ||
| 962 | pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool { | ||
| 963 | const lhs_sym = ctx.symbol(lhs.symbol_index); | ||
| 964 | const rhs_sym = ctx.symbol(rhs.symbol_index); | ||
| 965 | |||
| 966 | if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") { | ||
| 967 | return rhs_sym.flags.@"export"; | ||
| 968 | } | ||
| 969 | |||
| 970 | // TODO cache hash values | ||
| 971 | const nbuckets = ctx.gnu_hash.num_buckets; | ||
| 972 | const lhs_hash = GnuHashSection.hasher(lhs_sym.name(ctx)) % nbuckets; | ||
| 973 | const rhs_hash = GnuHashSection.hasher(rhs_sym.name(ctx)) % nbuckets; | ||
| 974 | |||
| 975 | if (lhs_hash == rhs_hash) | ||
| 976 | return lhs_sym.extra(ctx).?.dynamic < rhs_sym.extra(ctx).?.dynamic; | ||
| 977 | return lhs_hash < rhs_hash; | ||
| 978 | } | ||
| 979 | }; | ||
| 980 | |||
| 981 | var num_exports: u32 = 0; | ||
| 982 | for (dynsym.entries.items) |entry| { | ||
| 983 | const sym = elf_file.symbol(entry.symbol_index); | ||
| 984 | if (sym.flags.@"export") num_exports += 1; | ||
| 985 | } | ||
| 986 | |||
| 987 | elf_file.gnu_hash.num_buckets = @divTrunc(num_exports, GnuHashSection.load_factor) + 1; | ||
| 988 | |||
| 989 | std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan); | ||
| 990 | |||
| 991 | for (dynsym.entries.items, 1..) |entry, index| { | ||
| 992 | const sym = elf_file.symbol(entry.symbol_index); | ||
| 993 | var extra = sym.extra(elf_file).?; | ||
| 994 | extra.dynamic = @as(u32, @intCast(index)); | ||
| 995 | sym.setExtra(extra, elf_file); | ||
| 996 | } | ||
| 997 | } | ||
| 998 | |||
| 999 | pub fn size(dynsym: DynsymSection) usize { | ||
| 1000 | return dynsym.count() * @sizeOf(elf.Elf64_Sym); | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | pub fn count(dynsym: DynsymSection) u32 { | ||
| 1004 | return @as(u32, @intCast(dynsym.entries.items.len + 1)); | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void { | ||
| 1008 | try writer.writeStruct(Elf.null_sym); | ||
| 1009 | for (dynsym.entries.items) |entry| { | ||
| 1010 | const sym = elf_file.symbol(entry.symbol_index); | ||
| 1011 | var out_sym: elf.Elf64_Sym = Elf.null_sym; | ||
| 1012 | sym.setOutputSym(elf_file, &out_sym); | ||
| 1013 | out_sym.st_name = entry.off; | ||
| 1014 | try writer.writeStruct(out_sym); | ||
| 1015 | } | ||
| 1016 | } | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | pub const HashSection = struct { | ||
| 1020 | buffer: std.ArrayListUnmanaged(u8) = .{}, | ||
| 1021 | |||
| 1022 | pub fn deinit(hs: *HashSection, allocator: Allocator) void { | ||
| 1023 | hs.buffer.deinit(allocator); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | pub fn generate(hs: *HashSection, elf_file: *Elf) !void { | ||
| 1027 | if (elf_file.dynsym.count() == 1) return; | ||
| 1028 | |||
| 1029 | const gpa = elf_file.base.allocator; | ||
| 1030 | const nsyms = elf_file.dynsym.count(); | ||
| 1031 | |||
| 1032 | var buckets = try gpa.alloc(u32, nsyms); | ||
| 1033 | defer gpa.free(buckets); | ||
| 1034 | @memset(buckets, 0); | ||
| 1035 | |||
| 1036 | var chains = try gpa.alloc(u32, nsyms); | ||
| 1037 | defer gpa.free(chains); | ||
| 1038 | @memset(chains, 0); | ||
| 1039 | |||
| 1040 | for (elf_file.dynsym.entries.items, 1..) |entry, i| { | ||
| 1041 | const name = elf_file.dynstrtab.getAssumeExists(entry.off); | ||
| 1042 | const hash = hasher(name) % buckets.len; | ||
| 1043 | chains[@as(u32, @intCast(i))] = buckets[hash]; | ||
| 1044 | buckets[hash] = @as(u32, @intCast(i)); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | try hs.buffer.ensureTotalCapacityPrecise(gpa, (2 + nsyms * 2) * 4); | ||
| 1048 | hs.buffer.writer(gpa).writeIntLittle(u32, @as(u32, @intCast(nsyms))) catch unreachable; | ||
| 1049 | hs.buffer.writer(gpa).writeIntLittle(u32, @as(u32, @intCast(nsyms))) catch unreachable; | ||
| 1050 | hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(buckets)) catch unreachable; | ||
| 1051 | hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(chains)) catch unreachable; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | pub inline fn size(hs: HashSection) usize { | ||
| 1055 | return hs.buffer.items.len; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | pub fn hasher(name: [:0]const u8) u32 { | ||
| 1059 | var h: u32 = 0; | ||
| 1060 | var g: u32 = 0; | ||
| 1061 | for (name) |c| { | ||
| 1062 | h = (h << 4) + c; | ||
| 1063 | g = h & 0xf0000000; | ||
| 1064 | if (g > 0) h ^= g >> 24; | ||
| 1065 | h &= ~g; | ||
| 1066 | } | ||
| 1067 | return h; | ||
| 1068 | } | ||
| 1069 | }; | ||
| 1070 | |||
| 1071 | pub const GnuHashSection = struct { | ||
| 1072 | num_buckets: u32 = 0, | ||
| 1073 | num_bloom: u32 = 1, | ||
| 1074 | num_exports: u32 = 0, | ||
| 1075 | |||
| 1076 | pub const load_factor = 8; | ||
| 1077 | pub const header_size = 16; | ||
| 1078 | pub const bloom_shift = 26; | ||
| 1079 | |||
| 1080 | fn getExports(elf_file: *Elf) []const DynsymSection.Entry { | ||
| 1081 | const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| { | ||
| 1082 | const sym = elf_file.symbol(entry.symbol_index); | ||
| 1083 | if (sym.flags.@"export") break i; | ||
| 1084 | } else elf_file.dynsym.entries.items.len; | ||
| 1085 | return elf_file.dynsym.entries.items[start..]; | ||
| 1086 | } | ||
| 1087 | |||
| 1088 | inline fn bitCeil(x: u64) u64 { | ||
| 1089 | if (@popCount(x) == 1) return x; | ||
| 1090 | return @as(u64, @intCast(@as(u128, 1) << (64 - @clz(x)))); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | pub fn calcSize(hash: *GnuHashSection, elf_file: *Elf) !void { | ||
| 1094 | hash.num_exports = @as(u32, @intCast(getExports(elf_file).len)); | ||
| 1095 | if (hash.num_exports > 0) { | ||
| 1096 | const num_bits = hash.num_exports * 12; | ||
| 1097 | hash.num_bloom = @as(u32, @intCast(bitCeil(@divTrunc(num_bits, 64)))); | ||
| 1098 | } | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | pub fn size(hash: GnuHashSection) usize { | ||
| 1102 | return header_size + hash.num_bloom * 8 + hash.num_buckets * 4 + hash.num_exports * 4; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | pub fn write(hash: GnuHashSection, elf_file: *Elf, writer: anytype) !void { | ||
| 1106 | const exports = getExports(elf_file); | ||
| 1107 | const export_off = elf_file.dynsym.count() - hash.num_exports; | ||
| 1108 | |||
| 1109 | var counting = std.io.countingWriter(writer); | ||
| 1110 | const cwriter = counting.writer(); | ||
| 1111 | |||
| 1112 | try cwriter.writeIntLittle(u32, hash.num_buckets); | ||
| 1113 | try cwriter.writeIntLittle(u32, export_off); | ||
| 1114 | try cwriter.writeIntLittle(u32, hash.num_bloom); | ||
| 1115 | try cwriter.writeIntLittle(u32, bloom_shift); | ||
| 1116 | |||
| 1117 | const gpa = elf_file.base.allocator; | ||
| 1118 | const hashes = try gpa.alloc(u32, exports.len); | ||
| 1119 | defer gpa.free(hashes); | ||
| 1120 | const indices = try gpa.alloc(u32, exports.len); | ||
| 1121 | defer gpa.free(indices); | ||
| 1122 | |||
| 1123 | // Compose and write the bloom filter | ||
| 1124 | const bloom = try gpa.alloc(u64, hash.num_bloom); | ||
| 1125 | defer gpa.free(bloom); | ||
| 1126 | @memset(bloom, 0); | ||
| 1127 | |||
| 1128 | for (exports, 0..) |entry, i| { | ||
| 1129 | const sym = elf_file.symbol(entry.symbol_index); | ||
| 1130 | const h = hasher(sym.name(elf_file)); | ||
| 1131 | hashes[i] = h; | ||
| 1132 | indices[i] = h % hash.num_buckets; | ||
| 1133 | const idx = @divTrunc(h, 64) % hash.num_bloom; | ||
| 1134 | bloom[idx] |= @as(u64, 1) << @as(u6, @intCast(h % 64)); | ||
| 1135 | bloom[idx] |= @as(u64, 1) << @as(u6, @intCast((h >> bloom_shift) % 64)); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | try cwriter.writeAll(mem.sliceAsBytes(bloom)); | ||
| 1139 | |||
| 1140 | // Fill in the hash bucket indices | ||
| 1141 | const buckets = try gpa.alloc(u32, hash.num_buckets); | ||
| 1142 | defer gpa.free(buckets); | ||
| 1143 | @memset(buckets, 0); | ||
| 1144 | |||
| 1145 | for (0..hash.num_exports) |i| { | ||
| 1146 | if (buckets[indices[i]] == 0) { | ||
| 1147 | buckets[indices[i]] = @as(u32, @intCast(i + export_off)); | ||
| 1148 | } | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | try cwriter.writeAll(mem.sliceAsBytes(buckets)); | ||
| 1152 | |||
| 1153 | // Finally, write the hash table | ||
| 1154 | const table = try gpa.alloc(u32, hash.num_exports); | ||
| 1155 | defer gpa.free(table); | ||
| 1156 | @memset(table, 0); | ||
| 1157 | |||
| 1158 | for (0..hash.num_exports) |i| { | ||
| 1159 | const h = hashes[i]; | ||
| 1160 | if (i == exports.len - 1 or indices[i] != indices[i + 1]) { | ||
| 1161 | table[i] = h | 1; | ||
| 1162 | } else { | ||
| 1163 | table[i] = h & ~@as(u32, 1); | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | try cwriter.writeAll(mem.sliceAsBytes(table)); | ||
| 1168 | |||
| 1169 | assert(counting.bytes_written == hash.size()); | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | pub fn hasher(name: [:0]const u8) u32 { | ||
| 1173 | var h: u32 = 5381; | ||
| 1174 | for (name) |c| { | ||
| 1175 | h = (h << 5) +% h +% c; | ||
| 1176 | } | ||
| 1177 | return h; | ||
| 1178 | } | ||
| 1179 | }; | ||
| 1180 | |||
| 1181 | pub const VerneedSection = struct { | ||
| 1182 | verneed: std.ArrayListUnmanaged(elf.Elf64_Verneed) = .{}, | ||
| 1183 | vernaux: std.ArrayListUnmanaged(elf.Elf64_Vernaux) = .{}, | ||
| 1184 | index: elf.Elf64_Versym = elf.VER_NDX_GLOBAL + 1, | ||
| 1185 | |||
| 1186 | pub fn deinit(vern: *VerneedSection, allocator: Allocator) void { | ||
| 1187 | vern.verneed.deinit(allocator); | ||
| 1188 | vern.vernaux.deinit(allocator); | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | pub fn generate(vern: *VerneedSection, elf_file: *Elf) !void { | ||
| 1192 | const dynsyms = elf_file.dynsym.entries.items; | ||
| 1193 | var versyms = elf_file.versym.items; | ||
| 1194 | |||
| 1195 | const VersionedSymbol = struct { | ||
| 1196 | /// Index in the output version table | ||
| 1197 | index: usize, | ||
| 1198 | /// Index of the defining this symbol version shared object file | ||
| 1199 | shared_object: File.Index, | ||
| 1200 | /// Version index | ||
| 1201 | version_index: elf.Elf64_Versym, | ||
| 1202 | |||
| 1203 | fn soname(this: @This(), ctx: *Elf) []const u8 { | ||
| 1204 | const shared_object = ctx.file(this.shared_object).?.shared_object; | ||
| 1205 | return shared_object.soname(); | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | fn versionString(this: @This(), ctx: *Elf) [:0]const u8 { | ||
| 1209 | const shared_object = ctx.file(this.shared_object).?.shared_object; | ||
| 1210 | return shared_object.versionString(this.version_index); | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool { | ||
| 1214 | if (lhs.shared_object == rhs.shared_object) return lhs.version_index < rhs.version_index; | ||
| 1215 | return mem.lessThan(u8, lhs.soname(ctx), rhs.soname(ctx)); | ||
| 1216 | } | ||
| 1217 | }; | ||
| 1218 | |||
| 1219 | const gpa = elf_file.base.allocator; | ||
| 1220 | var verneed = std.ArrayList(VersionedSymbol).init(gpa); | ||
| 1221 | defer verneed.deinit(); | ||
| 1222 | try verneed.ensureTotalCapacity(dynsyms.len); | ||
| 1223 | |||
| 1224 | for (dynsyms, 1..) |entry, i| { | ||
| 1225 | const symbol = elf_file.symbol(entry.symbol_index); | ||
| 1226 | if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) { | ||
| 1227 | const shared_object = symbol.file(elf_file).?.shared_object; | ||
| 1228 | verneed.appendAssumeCapacity(.{ | ||
| 1229 | .index = i, | ||
| 1230 | .shared_object = shared_object.index, | ||
| 1231 | .version_index = symbol.version_index, | ||
| 1232 | }); | ||
| 1233 | } | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | mem.sort(VersionedSymbol, verneed.items, elf_file, VersionedSymbol.lessThan); | ||
| 1237 | |||
| 1238 | var last = verneed.items[0]; | ||
| 1239 | var last_verneed = try vern.addVerneed(last.soname(elf_file), elf_file); | ||
| 1240 | var last_vernaux = try vern.addVernaux(last_verneed, last.versionString(elf_file), elf_file); | ||
| 1241 | versyms[last.index] = last_vernaux.vna_other; | ||
| 1242 | |||
| 1243 | for (verneed.items[1..]) |ver| { | ||
| 1244 | if (ver.shared_object == last.shared_object) { | ||
| 1245 | if (ver.version_index != last.version_index) { | ||
| 1246 | last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file); | ||
| 1247 | } | ||
| 1248 | } else { | ||
| 1249 | last_verneed = try vern.addVerneed(ver.soname(elf_file), elf_file); | ||
| 1250 | last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file); | ||
| 1251 | } | ||
| 1252 | last = ver; | ||
| 1253 | versyms[ver.index] = last_vernaux.vna_other; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | // Fixup offsets | ||
| 1257 | var count: usize = 0; | ||
| 1258 | var verneed_off: u32 = 0; | ||
| 1259 | var vernaux_off: u32 = @as(u32, @intCast(vern.verneed.items.len)) * @sizeOf(elf.Elf64_Verneed); | ||
| 1260 | for (vern.verneed.items, 0..) |*vsym, vsym_i| { | ||
| 1261 | if (vsym_i < vern.verneed.items.len - 1) vsym.vn_next = @sizeOf(elf.Elf64_Verneed); | ||
| 1262 | vsym.vn_aux = vernaux_off - verneed_off; | ||
| 1263 | var inner_off: u32 = 0; | ||
| 1264 | for (vern.vernaux.items[count..][0..vsym.vn_cnt], 0..) |*vaux, vaux_i| { | ||
| 1265 | if (vaux_i < vsym.vn_cnt - 1) vaux.vna_next = @sizeOf(elf.Elf64_Vernaux); | ||
| 1266 | inner_off += @sizeOf(elf.Elf64_Vernaux); | ||
| 1267 | } | ||
| 1268 | vernaux_off += inner_off; | ||
| 1269 | verneed_off += @sizeOf(elf.Elf64_Verneed); | ||
| 1270 | count += vsym.vn_cnt; | ||
| 1271 | } | ||
| 1272 | } | ||
| 1273 | |||
| 1274 | fn addVerneed(vern: *VerneedSection, soname: []const u8, elf_file: *Elf) !*elf.Elf64_Verneed { | ||
| 1275 | const gpa = elf_file.base.allocator; | ||
| 1276 | const sym = try vern.verneed.addOne(gpa); | ||
| 1277 | sym.* = .{ | ||
| 1278 | .vn_version = 1, | ||
| 1279 | .vn_cnt = 0, | ||
| 1280 | .vn_file = try elf_file.dynstrtab.insert(gpa, soname), | ||
| 1281 | .vn_aux = 0, | ||
| 1282 | .vn_next = 0, | ||
| 1283 | }; | ||
| 1284 | return sym; | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | fn addVernaux( | ||
| 1288 | vern: *VerneedSection, | ||
| 1289 | verneed_sym: *elf.Elf64_Verneed, | ||
| 1290 | version: [:0]const u8, | ||
| 1291 | elf_file: *Elf, | ||
| 1292 | ) !elf.Elf64_Vernaux { | ||
| 1293 | const gpa = elf_file.base.allocator; | ||
| 1294 | const sym = try vern.vernaux.addOne(gpa); | ||
| 1295 | sym.* = .{ | ||
| 1296 | .vna_hash = HashSection.hasher(version), | ||
| 1297 | .vna_flags = 0, | ||
| 1298 | .vna_other = vern.index, | ||
| 1299 | .vna_name = try elf_file.dynstrtab.insert(gpa, version), | ||
| 1300 | .vna_next = 0, | ||
| 1301 | }; | ||
| 1302 | verneed_sym.vn_cnt += 1; | ||
| 1303 | vern.index += 1; | ||
| 1304 | return sym.*; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | pub fn size(vern: VerneedSection) usize { | ||
| 1308 | return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Elf64_Vernaux); | ||
| 1309 | } | ||
| 1310 | |||
| 1311 | pub fn write(vern: VerneedSection, writer: anytype) !void { | ||
| 1312 | try writer.writeAll(mem.sliceAsBytes(vern.verneed.items)); | ||
| 1313 | try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items)); | ||
| 1314 | } | ||
| 1315 | }; | ||
| 1316 | |||
| 446 | const assert = std.debug.assert; | 1317 | const assert = std.debug.assert; |
| 447 | const builtin = @import("builtin"); | 1318 | const builtin = @import("builtin"); |
| 448 | const elf = std.elf; | 1319 | const elf = std.elf; |
| 1320 | const mem = std.mem; | ||
| 449 | const log = std.log.scoped(.link); | 1321 | const log = std.log.scoped(.link); |
| 450 | const std = @import("std"); | 1322 | const std = @import("std"); |
| 451 | 1323 | ||
| 452 | const Allocator = std.mem.Allocator; | 1324 | const Allocator = std.mem.Allocator; |
| 453 | const Elf = @import("../Elf.zig"); | 1325 | const Elf = @import("../Elf.zig"); |
| 1326 | const File = @import("file.zig").File; | ||
| 1327 | const SharedObject = @import("SharedObject.zig"); | ||
| 454 | const Symbol = @import("Symbol.zig"); | 1328 | const Symbol = @import("Symbol.zig"); |