authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-05 17:53:04+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:04+02:00
logd1446565a1449d1f79edb848bbd8db21ce05c70b
treeb3f846e70f76ca2699bc6e38897e244f0e759d5d
parent04a8f217c651f56a2e185d87dd40c0a87ee78bc5

elf: re-enable dynamic linking codepaths


6 files changed, 2189 insertions(+), 407 deletions(-)

CMakeLists.txt+1
......@@ -591,6 +591,7 @@ set(ZIG_STAGE2_SOURCES
591591 "${CMAKE_SOURCE_DIR}/src/link/Elf/Atom.zig"
592592 "${CMAKE_SOURCE_DIR}/src/link/Elf/LinkerDefined.zig"
593593 "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"
594 "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"
594595 "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig"
595596 "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig"
596597 "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"
src/link/Elf.zig+582-65
......@@ -14,6 +14,7 @@ files: std.MultiArrayList(File.Entry) = .{},
1414zig_module_index: ?File.Index = null,
1515linker_defined_index: ?File.Index = null,
1616objects: std.ArrayListUnmanaged(File.Index) = .{},
17shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
1718
1819/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
1920/// Same order as in the file.
......@@ -61,10 +62,34 @@ default_sym_version: elf.Elf64_Versym,
6162shstrtab: StringTable(.strtab) = .{},
6263/// .strtab buffer
6364strtab: StringTable(.strtab) = .{},
64
65/// Representation of the GOT table as committed to the file.
65/// Dynamic symbol table. Only populated and emitted when linking dynamically.
66dynsym: DynsymSection = .{},
67/// .dynstrtab buffer
68dynstrtab: StringTable(.dynstrtab) = .{},
69/// Version symbol table. Only populated and emitted when linking dynamically.
70versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
71/// .verneed section
72verneed: VerneedSection = .{},
73/// .got section
6674got: GotSection = .{},
75/// .rela.dyn section
6776rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
77/// .dynamic section
78dynamic: DynamicSection = .{},
79/// .hash section
80hash: HashSection = .{},
81/// .gnu.hash section
82gnu_hash: GnuHashSection = .{},
83/// .plt section
84plt: PltSection = .{},
85/// .got.plt section
86got_plt: GotPltSection = .{},
87/// .plt.got section
88plt_got: PltGotSection = .{},
89/// .copyrel section
90copy_rel: CopyRelSection = .{},
91/// .rela.plt section
92rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
6893
6994/// Tracked section headers
7095text_section_index: ?u16 = null,
......@@ -73,18 +98,30 @@ data_section_index: ?u16 = null,
7398bss_section_index: ?u16 = null,
7499tdata_section_index: ?u16 = null,
75100tbss_section_index: ?u16 = null,
101debug_info_section_index: ?u16 = null,
102debug_abbrev_section_index: ?u16 = null,
103debug_str_section_index: ?u16 = null,
104debug_aranges_section_index: ?u16 = null,
105debug_line_section_index: ?u16 = null,
106
107copy_rel_section_index: ?u16 = null,
108dynamic_section_index: ?u16 = null,
109dynstrtab_section_index: ?u16 = null,
110dynsymtab_section_index: ?u16 = null,
76111eh_frame_section_index: ?u16 = null,
77112eh_frame_hdr_section_index: ?u16 = null,
78dynamic_section_index: ?u16 = null,
113hash_section_index: ?u16 = null,
114gnu_hash_section_index: ?u16 = null,
79115got_section_index: ?u16 = null,
80116got_plt_section_index: ?u16 = null,
117interp_section_index: ?u16 = null,
81118plt_section_index: ?u16 = null,
119plt_got_section_index: ?u16 = null,
82120rela_dyn_section_index: ?u16 = null,
83debug_info_section_index: ?u16 = null,
84debug_abbrev_section_index: ?u16 = null,
85debug_str_section_index: ?u16 = null,
86debug_aranges_section_index: ?u16 = null,
87debug_line_section_index: ?u16 = null,
121rela_plt_section_index: ?u16 = null,
122versym_section_index: ?u16 = null,
123verneed_section_index: ?u16 = null,
124
88125shstrtab_section_index: ?u16 = null,
89126strtab_section_index: ?u16 = null,
90127symtab_section_index: ?u16 = null,
......@@ -316,10 +353,11 @@ pub fn deinit(self: *Elf) void {
316353 .zig_module => data.zig_module.deinit(gpa),
317354 .linker_defined => data.linker_defined.deinit(gpa),
318355 .object => data.object.deinit(gpa),
319 // .shared_object => data.shared_object.deinit(gpa),
356 .shared_object => data.shared_object.deinit(gpa),
320357 };
321358 self.files.deinit(gpa);
322359 self.objects.deinit(gpa);
360 self.shared_objects.deinit(gpa);
323361
324362 self.shdrs.deinit(gpa);
325363 self.phdr_to_shdr_table.deinit(gpa);
......@@ -333,7 +371,6 @@ pub fn deinit(self: *Elf) void {
333371 self.symbols.deinit(gpa);
334372 self.symbols_extra.deinit(gpa);
335373 self.symbols_free_list.deinit(gpa);
336 self.got.deinit(gpa);
337374 self.resolver.deinit(gpa);
338375 self.start_stop_indexes.deinit(gpa);
339376
......@@ -369,7 +406,19 @@ pub fn deinit(self: *Elf) void {
369406 self.comdat_groups.deinit(gpa);
370407 self.comdat_groups_owners.deinit(gpa);
371408 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);
372420 self.rela_dyn.deinit(gpa);
421 self.rela_plt.deinit(gpa);
373422}
374423
375424pub 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
12681317 try dw.flushModule(self.base.options.module.?);
12691318 }
12701319
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
12711338 // If we haven't already, create a linker-generated input file comprising of
12721339 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
12731340 if (self.linker_defined_index == null) {
......@@ -1677,6 +1744,7 @@ fn resolveSymbols(self: *Elf) void {
16771744 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
16781745 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
16791746 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1747 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
16801748
16811749 // Mark live objects.
16821750 self.markLive();
......@@ -1684,6 +1752,7 @@ fn resolveSymbols(self: *Elf) void {
16841752 // Reset state of all globals after marking live objects.
16851753 if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self);
16861754 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1755 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
16871756
16881757 // Prune dead objects and shared objects.
16891758 var i: usize = 0;
......@@ -1693,6 +1762,13 @@ fn resolveSymbols(self: *Elf) void {
16931762 _ = self.objects.orderedRemove(i);
16941763 } else i += 1;
16951764 }
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 }
16961772
16971773 // Dedup comdat groups.
16981774 for (self.objects.items) |index| {
......@@ -1728,6 +1804,7 @@ fn resolveSymbols(self: *Elf) void {
17281804 // Re-resolve the symbols.
17291805 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
17301806 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1807 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
17311808}
17321809
17331810/// Traverses all objects and shared objects marking any object referenced by
......@@ -1740,6 +1817,10 @@ fn markLive(self: *Elf) void {
17401817 const file_ptr = self.file(index).?;
17411818 if (file_ptr.isAlive()) file_ptr.markLive(self);
17421819 }
1820 for (self.shared_objects.items) |index| {
1821 const file_ptr = self.file(index).?;
1822 if (file_ptr.isAlive()) file_ptr.markLive(self);
1823 }
17431824}
17441825
17451826fn markEhFrameAtomsDead(self: *Elf) void {
......@@ -1759,10 +1840,10 @@ fn markImportsExports(self: *Elf) void {
17591840 const file_ptr = global.file(elf_file) orelse continue;
17601841 const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
17611842 if (vis == .HIDDEN) continue;
1762 // if (file == .shared and !global.isAbs(self)) {
1763 // global.flags.import = true;
1764 // continue;
1765 // }
1843 if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
1844 global.flags.import = true;
1845 continue;
1846 }
17661847 if (file_ptr.index() == file_index) {
17671848 global.flags.@"export" = true;
17681849 if (elf_file.isDynLib() and vis != .PROTECTED) {
......@@ -1773,6 +1854,17 @@ fn markImportsExports(self: *Elf) void {
17731854 }
17741855 }.mark;
17751856
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
17761868 if (self.zig_module_index) |index| {
17771869 mark(self, index);
17781870 }
......@@ -1820,12 +1912,51 @@ fn scanRelocs(self: *Elf) !void {
18201912
18211913 try self.reportUndefined(&undefs);
18221914
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 }
18241921 if (sym.flags.needs_got) {
18251922 log.debug("'{s}' needs GOT", .{sym.name(self)});
1826 _ = try self.got.addGotSymbol(@intCast(sym_index), self);
1827 sym.flags.has_got = true;
1923 _ = try self.got.addGotSymbol(index, self);
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);
18281945 }
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);
18291960 }
18301961}
18311962
......@@ -2567,12 +2698,12 @@ fn writeHeader(self: *Elf) !void {
25672698
25682699 assert(index == 16);
25692700
2570 const elf_type = switch (self.base.options.effectiveOutputMode()) {
2571 .Exe => elf.ET.EXEC,
2572 .Obj => elf.ET.REL,
2701 const elf_type: elf.ET = switch (self.base.options.effectiveOutputMode()) {
2702 .Exe => if (self.base.options.pic) .DYN else .EXEC,
2703 .Obj => .REL,
25732704 .Lib => switch (self.base.options.link_mode) {
2574 .Static => elf.ET.REL,
2575 .Dynamic => elf.ET.DYN,
2705 .Static => @as(elf.ET, .REL),
2706 .Dynamic => .DYN,
25762707 },
25772708 };
25782709 mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian);
......@@ -2819,8 +2950,8 @@ fn updateDeclCode(
28192950 esym.st_value = atom_ptr.value;
28202951
28212952 log.debug(" (writing new offset table entry)", .{});
2822 const extra = sym.extra(self).?;
2823 try self.got.writeEntry(self, extra.got);
2953 // const extra = sym.extra(self).?;
2954 // try self.got.writeEntry(self, extra.got);
28242955 }
28252956 } else if (code.len < old_size) {
28262957 atom_ptr.shrink(self);
......@@ -2834,7 +2965,8 @@ fn updateDeclCode(
28342965
28352966 sym.flags.needs_got = true;
28362967 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);
28382970 }
28392971
28402972 if (self.base.child_pid) |pid| {
......@@ -3070,7 +3202,8 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
30703202
30713203 local_sym.flags.needs_got = true;
30723204 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);
30743207
30753208 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
30763209 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
......@@ -3480,13 +3613,145 @@ fn initSections(self: *Elf) !void {
34803613 }
34813614 }
34823615
3483 if (self.got.entries.items.len > 0 and self.got_section_index == null) {
3616 if (self.got.entries.items.len > 0) {
34843617 self.got_section_index = try self.addSection(.{
34853618 .name = ".got",
34863619 .type = elf.SHT_PROGBITS,
34873620 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
34883621 .addralign = ptr_size,
34893622 });
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 }
34903755 }
34913756
34923757 if (self.symtab_section_index == null) {
......@@ -3665,6 +3930,20 @@ fn sortSections(self: *Elf) !void {
36653930 &self.symtab_section_index,
36663931 &self.strtab_section_index,
36673932 &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,
36683947 }) |maybe_index| {
36693948 if (maybe_index.*) |*index| {
36703949 index.* = backlinks[index.*];
......@@ -3675,6 +3954,47 @@ fn sortSections(self: *Elf) !void {
36753954 const shdr = &self.shdrs.items[index];
36763955 shdr.sh_link = self.strtab_section_index.?;
36773956 }
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 }
36783998}
36793999
36804000fn updateSectionSizes(self: *Elf) !void {
......@@ -3683,21 +4003,77 @@ fn updateSectionSizes(self: *Elf) !void {
36834003 }
36844004
36854005 if (self.eh_frame_section_index) |index| {
3686 const shdr = &self.shdrs.items[index];
3687 shdr.sh_size = try eh_frame.calcEhFrameSize(self);
3688 shdr.sh_addralign = @alignOf(u64);
4006 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
36894007 }
36904008
36914009 if (self.eh_frame_hdr_section_index) |index| {
3692 const shdr = &self.shdrs.items[index];
3693 shdr.sh_size = eh_frame.calcEhFrameHdrSize(self);
3694 shdr.sh_addralign = @alignOf(u32);
4010 self.shdrs.items[index].sh_size = eh_frame.calcEhFrameHdrSize(self);
36954011 }
36964012
36974013 if (self.got_section_index) |index| {
36984014 self.shdrs.items[index].sh_size = self.got.size(self);
36994015 }
37004016
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
37014077 if (self.symtab_section_index != null) {
37024078 try self.updateSymtabSize();
37034079 }
......@@ -3708,13 +4084,17 @@ fn updateSectionSizes(self: *Elf) !void {
37084084 if (self.got_section_index) |_| {
37094085 try self.got.updateStrtab(self);
37104086 }
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 }
37114093 self.shdrs.items[index].sh_size = self.strtab.buffer.items.len;
3712 // try self.growNonAllocSection(index, self.strtab.buffer.items.len, 1, false);
37134094 }
37144095
37154096 if (self.shstrtab_section_index) |index| {
37164097 self.shdrs.items[index].sh_size = self.shstrtab.buffer.items.len;
3717 // try self.growNonAllocSection(index, self.shstrtab.buffer.items.len, 1, false);
37184098 }
37194099}
37204100
......@@ -3729,18 +4109,18 @@ fn initPhdrs(self: *Elf) !void {
37294109 });
37304110
37314111 // Add INTERP phdr if required
3732 // if (self.interp_sect_index) |index| {
3733 // const shdr = self.sections.items(.shdr)[index];
3734 // _ = try self.addPhdr(.{
3735 // .type = elf.PT_INTERP,
3736 // .flags = elf.PF_R,
3737 // .@"align" = 1,
3738 // .offset = shdr.sh_offset,
3739 // .addr = shdr.sh_addr,
3740 // .filesz = shdr.sh_size,
3741 // .memsz = shdr.sh_size,
3742 // });
3743 // }
4112 if (self.interp_section_index) |index| {
4113 const shdr = self.shdrs.items[index];
4114 _ = try self.addPhdr(.{
4115 .type = elf.PT_INTERP,
4116 .flags = elf.PF_R,
4117 .@"align" = 1,
4118 .offset = shdr.sh_offset,
4119 .addr = shdr.sh_addr,
4120 .filesz = shdr.sh_size,
4121 .memsz = shdr.sh_size,
4122 });
4123 }
37444124
37454125 // Add LOAD phdrs
37464126 const slice = self.shdrs.items;
......@@ -3806,18 +4186,18 @@ fn initPhdrs(self: *Elf) !void {
38064186 }
38074187
38084188 // Add DYNAMIC phdr
3809 // if (self.dynamic_sect_index) |index| {
3810 // const shdr = self.sections.items(.shdr)[index];
3811 // _ = try self.addPhdr(.{
3812 // .type = elf.PT_DYNAMIC,
3813 // .flags = elf.PF_R | elf.PF_W,
3814 // .@"align" = shdr.sh_addralign,
3815 // .offset = shdr.sh_offset,
3816 // .addr = shdr.sh_addr,
3817 // .memsz = shdr.sh_size,
3818 // .filesz = shdr.sh_size,
3819 // });
3820 // }
4189 if (self.dynamic_section_index) |index| {
4190 const shdr = self.shdrs.items[index];
4191 _ = try self.addPhdr(.{
4192 .type = elf.PT_DYNAMIC,
4193 .flags = elf.PF_R | elf.PF_W,
4194 .@"align" = shdr.sh_addralign,
4195 .offset = shdr.sh_offset,
4196 .addr = shdr.sh_addr,
4197 .memsz = shdr.sh_size,
4198 .filesz = shdr.sh_size,
4199 });
4200 }
38214201
38224202 // Add PT_GNU_EH_FRAME phdr if required.
38234203 if (self.eh_frame_hdr_section_index) |index| {
......@@ -4113,6 +4493,16 @@ fn updateSymtabSize(self: *Elf) !void {
41134493 sizes.nlocals += self.got.output_symtab_size.nlocals;
41144494 }
41154495
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
41164506 if (self.linker_defined_index) |index| {
41174507 const linker_defined = self.file(index).?.linker_defined;
41184508 linker_defined.updateSymtabSize(self);
......@@ -4127,18 +4517,70 @@ fn updateSymtabSize(self: *Elf) !void {
41274517 .p32 => @sizeOf(elf.Elf32_Sym),
41284518 .p64 => @sizeOf(elf.Elf64_Sym),
41294519 };
4130 // const sym_align: u16 = switch (self.ptr_width) {
4131 // .p32 => @alignOf(elf.Elf32_Sym),
4132 // .p64 => @alignOf(elf.Elf64_Sym),
4133 // };
41344520 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
41354521 shdr.sh_size = needed_size;
4136 // try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, false);
41374522}
41384523
41394524fn writeSyntheticSections(self: *Elf) !void {
41404525 const gpa = self.base.allocator;
41414526
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
41424584 if (self.eh_frame_section_index) |shndx| {
41434585 const shdr = self.shdrs.items[shndx];
41444586 var buffer = try std.ArrayList(u8).initCapacity(gpa, shdr.sh_size);
......@@ -4163,6 +4605,44 @@ fn writeSyntheticSections(self: *Elf) !void {
41634605 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
41644606 }
41654607
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
41664646 if (self.shstrtab_section_index) |index| {
41674647 const shdr = self.shdrs.items[index];
41684648 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shdr.sh_offset);
......@@ -4213,11 +4693,27 @@ fn writeSymtab(self: *Elf) !void {
42134693 ctx.iglobal += object.output_symtab_size.nglobals;
42144694 }
42154695
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
42164702 if (self.got_section_index) |_| {
42174703 try self.got.writeSymtab(self, ctx);
42184704 ctx.ilocal += self.got.output_symtab_size.nlocals;
42194705 }
42204706
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
42214717 if (self.linker_defined_index) |index| {
42224718 const linker_defined = self.file(index).?.linker_defined;
42234719 linker_defined.writeSymtab(self, ctx);
......@@ -4576,7 +5072,7 @@ pub fn isStatic(self: Elf) bool {
45765072}
45775073
45785074pub 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;
45805076}
45815077
45825078fn addPhdr(self: *Elf, opts: struct {
......@@ -4723,6 +5219,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {
47235219 .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined },
47245220 .zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module },
47255221 .object => .{ .object = &self.files.items(.data)[index].object },
5222 .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },
47265223 };
47275224}
47285225
......@@ -5077,6 +5574,16 @@ fn fmtDumpState(
50775574 });
50785575 }
50795576
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
50805587 if (self.linker_defined_index) |index| {
50815588 const linker_defined = self.file(index).?.linker_defined;
50825589 try writer.print("linker_defined({d}) : (linker defined)\n", .{index});
......@@ -5227,10 +5734,16 @@ const Archive = @import("Elf/Archive.zig");
52275734pub const Atom = @import("Elf/Atom.zig");
52285735const Cache = std.Build.Cache;
52295736const Compilation = @import("../Compilation.zig");
5737const CopyRelSection = synthetic_sections.CopyRelSection;
5738const DynamicSection = synthetic_sections.DynamicSection;
5739const DynsymSection = synthetic_sections.DynsymSection;
52305740const Dwarf = @import("Dwarf.zig");
52315741const Elf = @This();
52325742const File = @import("Elf/file.zig").File;
5743const GnuHashSection = synthetic_sections.GnuHashSection;
52335744const GotSection = synthetic_sections.GotSection;
5745const GotPltSection = synthetic_sections.GotPltSection;
5746const HashSection = synthetic_sections.HashSection;
52345747const LinkerDefined = @import("Elf/LinkerDefined.zig");
52355748const Liveness = @import("../Liveness.zig");
52365749const LlvmObject = @import("../codegen/llvm.zig").Object;
......@@ -5238,10 +5751,14 @@ const Module = @import("../Module.zig");
52385751const Object = @import("Elf/Object.zig");
52395752const InternPool = @import("../InternPool.zig");
52405753const Package = @import("../Package.zig");
5754const PltSection = synthetic_sections.PltSection;
5755const PltGotSection = synthetic_sections.PltGotSection;
5756const SharedObject = @import("Elf/SharedObject.zig");
52415757const Symbol = @import("Elf/Symbol.zig");
52425758const StringTable = @import("strtab.zig").StringTable;
52435759const TableSection = @import("table_section.zig").TableSection;
52445760const Type = @import("../type.zig").Type;
52455761const TypedValue = @import("../TypedValue.zig");
52465762const Value = @import("../value.zig").Value;
5763const VerneedSection = synthetic_sections.VerneedSection;
52475764const ZigModule = @import("Elf/ZigModule.zig");
src/link/Elf/SharedObject.zig created+361
......@@ -0,0 +1,361 @@
1path: []const u8,
2data: []const u8,
3index: File.Index,
4
5header: ?elf.Elf64_Ehdr = null,
6shdrs: std.ArrayListUnmanaged(ElfShdr) = .{},
7symtab: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{},
8strtab: []const u8 = &[0]u8{},
9/// Version symtab contains version strings of the symbols if present.
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
11verstrings: std.ArrayListUnmanaged(u32) = .{},
12
13dynamic_sect_index: ?u16 = null,
14versym_sect_index: ?u16 = null,
15verdef_sect_index: ?u16 = null,
16
17symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
18aliases: ?std.ArrayListUnmanaged(u32) = null,
19
20needed: bool,
21alive: bool,
22
23output_symtab_size: Elf.SymtabSize = .{},
24
25pub 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
35pub 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
43pub 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
80fn 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
124fn 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
147pub 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
165pub 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
174pub 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
192pub 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
202pub 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
213pub fn globals(self: SharedObject) []const Symbol.Index {
214 return self.symbols.items;
215}
216
217pub 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
222pub 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
227pub 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
232pub fn asFile(self: *SharedObject) File {
233 return .{ .shared_object = self };
234}
235
236fn 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
243fn 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
252pub 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
261pub 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
289pub 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
308pub 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
321pub 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
328const FormatContext = struct {
329 shared: SharedObject,
330 elf_file: *Elf,
331};
332
333fn 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
349const SharedObject = @This();
350
351const std = @import("std");
352const assert = std.debug.assert;
353const elf = std.elf;
354const log = std.log.scoped(.elf);
355const mem = std.mem;
356
357const Allocator = mem.Allocator;
358const Elf = @import("../Elf.zig");
359const ElfShdr = @import("Object.zig").ElfShdr;
360const File = @import("file.zig").File;
361const Symbol = @import("Symbol.zig");
src/link/Elf/Symbol.zig+75-47
......@@ -32,7 +32,7 @@ extra_index: u32 = 0,
3232
3333pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
3434 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;
3636 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and
3737 file_ptr != .linker_defined;
3838}
......@@ -52,8 +52,8 @@ pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
5252
5353pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
5454 const s_sym = symbol.elfSym(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;
55 const file_ptr = symbol.file(elf_file).?;
56 if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared_object) return elf.STT_FUNC;
5757 return s_sym.st_type();
5858}
5959
......@@ -74,7 +74,7 @@ pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
7474 switch (file_ptr) {
7575 .zig_module => |x| return x.elfSym(symbol.esym_index).*,
7676 .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],
7878 }
7979}
8080
......@@ -88,23 +88,18 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
8888 return file_ptr.symbolRank(sym, in_archive);
8989}
9090
91pub fn address(symbol: Symbol, opts: struct {
92 plt: bool = true,
93}, elf_file: *Elf) u64 {
94 _ = elf_file;
95 _ = opts;
96 // if (symbol.flags.copy_rel) {
97 // return elf_file.sectionAddress(elf_file.copy_rel_sect_index.?) + symbol.value;
98 // }
99 // if (symbol.flags.plt and opts.plt) {
100 // const extra = symbol.getExtra(elf_file).?;
101 // if (!symbol.flags.is_canonical and symbol.flags.got) {
102 // // We have a non-lazy bound function pointer, use that!
103 // return elf_file.getPltGotEntryAddress(extra.plt_got);
104 // }
105 // // Lazy-bound function it is!
106 // return elf_file.getPltEntryAddress(extra.plt);
107 // }
91pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) u64 {
92 if (symbol.flags.has_copy_rel) {
93 return symbol.copyRelAddress(elf_file);
94 }
95 if (symbol.flags.has_plt and opts.plt) {
96 if (!symbol.flags.is_canonical and symbol.flags.has_got) {
97 // We have a non-lazy bound function pointer, use that!
98 return symbol.pltGotAddress(elf_file);
99 }
100 // Lazy-bound function it is!
101 return symbol.pltAddress(elf_file);
102 }
108103 return symbol.value;
109104}
110105
......@@ -115,6 +110,33 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
115110 return entry.address(elf_file);
116111}
117112
113pub 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
120pub 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
127pub 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
134pub 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
118140const GetOrCreateGotEntryResult = struct {
119141 found_existing: bool,
120142 index: GotSection.Index,
......@@ -149,17 +171,18 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) u64 {
149171 return entry.address(elf_file);
150172}
151173
152// pub fn alignment(symbol: Symbol, elf_file: *Elf) !u64 {
153// const file = symbol.getFile(elf_file) orelse return 0;
154// const shared = file.shared;
155// const s_sym = symbol.getSourceSymbol(elf_file);
156// const shdr = shared.getShdrs()[s_sym.st_shndx];
157// const alignment = @max(1, shdr.sh_addralign);
158// return if (s_sym.st_value == 0)
159// alignment
160// else
161// @min(alignment, try std.math.powi(u64, 2, @ctz(s_sym.st_value)));
162// }
174pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
175 const file_ptr = symbol.file(elf_file) orelse return 0;
176 assert(file_ptr == .shared_object);
177 const shared_object = file_ptr.shared_object;
178 const esym = symbol.elfSym(elf_file);
179 const shdr = shared_object.shdrs.items[esym.st_shndx];
180 const alignment = @max(1, shdr.sh_addralign);
181 return if (esym.st_value == 0)
182 alignment
183 else
184 @min(alignment, try std.math.powi(u64, 2, @ctz(esym.st_value)));
185}
163186
164187pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void {
165188 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 {
183206 const st_bind: u8 = blk: {
184207 if (symbol.isLocal()) break :blk 0;
185208 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;
187210 break :blk esym.st_bind();
188211 };
189212 const st_shndx = blk: {
190 // if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?;
191 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
213 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
214 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
192215 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
193216 break :blk elf.SHN_ABS;
194217 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
195218 };
196219 const st_value = blk: {
197 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);
198 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) {
199 // if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
200 // break :blk 0;
201 // }
220 if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);
221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) {
222 if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
223 break :blk 0;
224 }
202225 if (st_shndx == elf.SHN_ABS) break :blk symbol.value;
203226 const shdr = &elf_file.shdrs.items[st_shndx];
204227 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
......@@ -254,9 +277,10 @@ fn formatName(
254277 switch (symbol.version_index & elf.VERSYM_VERSION) {
255278 elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},
256279 else => {
257 unreachable;
258 // const shared = symbol.getFile(elf_file).?.shared;
259 // try writer.print("@{s}", .{shared.getVersionString(symbol.version_index)});
280 const file_ptr = symbol.file(elf_file).?;
281 assert(file_ptr == .shared_object);
282 const shared_object = file_ptr.shared_object;
283 try writer.print("@{s}", .{shared_object.versionString(symbol.version_index)});
260284 },
261285 }
262286}
......@@ -312,9 +336,12 @@ pub const Flags = packed struct {
312336 /// Whether this symbol is weak.
313337 weak: bool = false,
314338
315 /// Whether the symbol makes into the output symtab or not.
339 /// Whether the symbol makes into the output symtab.
316340 output_symtab: bool = false,
317341
342 /// Whether the symbol has entry in dynamic symbol table.
343 has_dynamic: bool = false,
344
318345 /// Whether the symbol contains GOT indirection.
319346 needs_got: bool = false,
320347 has_got: bool = false,
......@@ -328,7 +355,6 @@ pub const Flags = packed struct {
328355 /// Whether the symbol contains COPYREL directive.
329356 needs_copy_rel: bool = false,
330357 has_copy_rel: bool = false,
331 has_dynamic: bool = false,
332358
333359 /// Whether the symbol contains TLSGD indirection.
334360 needs_tlsgd: bool = false,
......@@ -365,8 +391,10 @@ const Atom = @import("Atom.zig");
365391const Elf = @import("../Elf.zig");
366392const File = @import("file.zig").File;
367393const GotSection = synthetic_sections.GotSection;
394const GotPltSection = synthetic_sections.GotPltSection;
368395const LinkerDefined = @import("LinkerDefined.zig");
369// const Object = @import("Object.zig");
370// const SharedObject = @import("SharedObject.zig");
396const Object = @import("Object.zig");
397const PltSection = synthetic_sections.PltSection;
398const SharedObject = @import("SharedObject.zig");
371399const Symbol = @This();
372400const ZigModule = @import("ZigModule.zig");
src/link/Elf/file.zig+7-6
......@@ -2,7 +2,7 @@ pub const File = union(enum) {
22 zig_module: *ZigModule,
33 linker_defined: *LinkerDefined,
44 object: *Object,
5 // shared_object: *SharedObject,
5 shared_object: *SharedObject,
66
77 pub fn index(file: File) Index {
88 return switch (file) {
......@@ -26,7 +26,7 @@ pub const File = union(enum) {
2626 .zig_module => |x| try writer.print("{s}", .{x.path}),
2727 .linker_defined => try writer.writeAll("(linker defined)"),
2828 .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),
3030 }
3131 }
3232
......@@ -49,8 +49,7 @@ pub const File = union(enum) {
4949 pub fn symbolRank(file: File, sym: elf.Elf64_Sym, in_archive: bool) u32 {
5050 const base: u3 = blk: {
5151 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()) {
53 if (in_archive) break :blk switch (sym.st_bind()) {
52 if (file == .shared_object or in_archive) break :blk switch (sym.st_bind()) {
5453 elf.STB_GLOBAL => 3,
5554 else => 4,
5655 };
......@@ -92,6 +91,7 @@ pub const File = union(enum) {
9291 pub fn atoms(file: File) []const Atom.Index {
9392 return switch (file) {
9493 .linker_defined => unreachable,
94 .shared_object => unreachable,
9595 .zig_module => |x| x.atoms.items,
9696 .object => |x| x.atoms.items,
9797 };
......@@ -100,6 +100,7 @@ pub const File = union(enum) {
100100 pub fn locals(file: File) []const Symbol.Index {
101101 return switch (file) {
102102 .linker_defined => unreachable,
103 .shared_object => unreachable,
103104 inline else => |x| x.locals(),
104105 };
105106 }
......@@ -117,7 +118,7 @@ pub const File = union(enum) {
117118 zig_module: ZigModule,
118119 linker_defined: LinkerDefined,
119120 object: Object,
120 // shared_object: SharedObject,
121 shared_object: SharedObject,
121122 };
122123};
123124
......@@ -129,6 +130,6 @@ const Atom = @import("Atom.zig");
129130const Elf = @import("../Elf.zig");
130131const LinkerDefined = @import("LinkerDefined.zig");
131132const Object = @import("Object.zig");
132// const SharedObject = @import("SharedObject.zig");
133const SharedObject = @import("SharedObject.zig");
133134const Symbol = @import("Symbol.zig");
134135const ZigModule = @import("ZigModule.zig");
src/link/Elf/synthetic_sections.zig+1163-289
......@@ -1,3 +1,225 @@
1pub 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
1223pub const GotSection = struct {
2224 entries: std.ArrayListUnmanaged(Entry) = .{},
3225 output_symtab_size: Elf.SymtabSize = .{},
......@@ -72,44 +294,57 @@ pub const GotSection = struct {
72294 return index;
73295 }
74296
75 // pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
76 // const index = got.next_index;
77 // const symbol = elf_file.getSymbol(sym_index);
78 // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true;
79 // if (symbol.getExtra(elf_file)) |extra| {
80 // var new_extra = extra;
81 // new_extra.tlsgd = index;
82 // symbol.setExtra(new_extra, elf_file);
83 // } else try symbol.addExtra(.{ .tlsgd = index }, elf_file);
84 // try got.symbols.append(elf_file.base.allocator, .{ .tlsgd = sym_index });
85 // got.next_index += 2;
86 // }
87
88 // pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
89 // const index = got.next_index;
90 // const symbol = elf_file.getSymbol(sym_index);
91 // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true;
92 // if (symbol.getExtra(elf_file)) |extra| {
93 // var new_extra = extra;
94 // new_extra.gottp = index;
95 // symbol.setExtra(new_extra, elf_file);
96 // } else try symbol.addExtra(.{ .gottp = index }, elf_file);
97 // try got.symbols.append(elf_file.base.allocator, .{ .gottp = sym_index });
98 // got.next_index += 1;
99 // }
100
101 // pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
102 // const index = got.next_index;
103 // const symbol = elf_file.getSymbol(sym_index);
104 // got.needs_rela = true;
105 // if (symbol.getExtra(elf_file)) |extra| {
106 // var new_extra = extra;
107 // new_extra.tlsdesc = index;
108 // symbol.setExtra(new_extra, elf_file);
109 // } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file);
110 // try got.symbols.append(elf_file.base.allocator, .{ .tlsdesc = sym_index });
111 // got.next_index += 2;
112 // }
297 pub fn addTlsLdSymbol(got: *GotSection, elf_file: *Elf) !void {
298 assert(got.flags.needs_tlsld);
299 const index = try got.allocateEntry(elf_file.base.allocator);
300 const entry = &got.entries.items[index];
301 entry.tag = .tlsld;
302 entry.symbol_index = undefined; // unused
303 got.flags.needs_rela = true;
304 got.tlsld_index = index;
305 }
306
307 pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
308 const index = try got.allocateEntry(elf_file.base.allocator);
309 const entry = &got.entries.items[index];
310 entry.tag = .tlsgd;
311 entry.symbol_index = sym_index;
312 const symbol = elf_file.symbol(sym_index);
313 if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true;
314 if (symbol.extra(elf_file)) |extra| {
315 var new_extra = extra;
316 new_extra.tlsgd = index;
317 symbol.setExtra(new_extra, elf_file);
318 } else try symbol.addExtra(.{ .tlsgd = index }, elf_file);
319 }
320
321 pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
322 const index = try got.allocateEntry(elf_file.base.allocator);
323 const entry = &got.entries.items[index];
324 entry.tag = .gottp;
325 entry.symbol_index = sym_index;
326 const symbol = elf_file.symbol(sym_index);
327 if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true;
328 if (symbol.extra(elf_file)) |extra| {
329 var new_extra = extra;
330 new_extra.gottp = index;
331 symbol.setExtra(new_extra, elf_file);
332 } else try symbol.addExtra(.{ .gottp = index }, elf_file);
333 }
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 }
113348
114349 pub fn size(got: GotSection, elf_file: *Elf) usize {
115350 var s: usize = 0;
......@@ -119,260 +354,207 @@ pub const GotSection = struct {
119354 return s;
120355 }
121356
122 pub fn writeEntry(got: *GotSection, elf_file: *Elf, index: Index) !void {
123 const entry_size: u16 = elf_file.archPtrWidthBytes();
124 // if (got.dirty) {
125 // const needed_size = got.size(elf_file);
126 // try elf_file.growAllocSection(elf_file.got_section_index.?, needed_size);
127 // got.dirty = false;
128 // }
357 pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
358 const is_dyn_lib = elf_file.isDynLib();
359 const apply_relocs = true; // TODO add user option for this
360
361 for (got.entries.items) |entry| {
362 const symbol = elf_file.symbol(entry.symbol_index);
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();
129415 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;
135416 switch (entry_size) {
136 2 => {
137 var buf: [2]u8 = undefined;
138 std.mem.writeInt(u16, &buf, @as(u16, @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 },
417 2 => try writer.writeInt(u16, @intCast(value), endian),
418 4 => try writer.writeInt(u32, @intCast(value), endian),
419 8 => try writer.writeInt(u64, @intCast(value), endian),
172420 else => unreachable,
173421 }
174422 }
175423
176 pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
177 const entry_size: u16 = elf_file.archPtrWidthBytes();
178 const endian = elf_file.base.options.target.cpu.arch.endian();
424 pub fn addRela(got: GotSection, elf_file: *Elf) !void {
425 const is_dyn_lib = elf_file.isDynLib();
426 try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file));
427
179428 for (got.entries.items) |entry| {
180 const value = elf_file.symbol(entry.symbol_index).value;
181 switch (entry_size) {
182 2 => try writer.writeInt(u16, @intCast(value), endian),
183 4 => try writer.writeInt(u32, @intCast(value), endian),
184 8 => try writer.writeInt(u64, @intCast(value), endian),
185 else => unreachable,
429 const symbol = switch (entry.tag) {
430 .tlsld => null,
431 inline else => elf_file.symbol(entry.symbol_index),
432 };
433 const extra = if (symbol) |s| s.extra(elf_file).? else null;
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 },
186520 }
187521 }
188522 }
189523
190 // pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
191 // const is_shared = elf_file.options.output_mode == .lib;
192 // const apply_relocs = elf_file.options.apply_dynamic_relocs;
193
194 // for (got.symbols.items) |sym| {
195 // const symbol = elf_file.getSymbol(sym.getIndex());
196 // switch (sym) {
197 // .got => {
198 // const value: u64 = blk: {
199 // const value = symbol.getAddress(.{ .plt = false }, elf_file);
200 // if (symbol.flags.import) break :blk 0;
201 // if (symbol.isIFunc(elf_file))
202 // break :blk if (apply_relocs) value else 0;
203 // if (elf_file.options.pic and !symbol.isAbs(elf_file))
204 // break :blk if (apply_relocs) value else 0;
205 // break :blk value;
206 // };
207 // try writer.writeIntLittle(u64, value);
208 // },
209
210 // .tlsgd => {
211 // if (symbol.flags.import) {
212 // try writer.writeIntLittle(u64, 0);
213 // try writer.writeIntLittle(u64, 0);
214 // } else {
215 // try writer.writeIntLittle(u64, if (is_shared) @as(u64, 0) else 1);
216 // const offset = symbol.getAddress(.{}, elf_file) - elf_file.getDtpAddress();
217 // try writer.writeIntLittle(u64, offset);
218 // }
219 // },
220
221 // .gottp => {
222 // if (symbol.flags.import) {
223 // try writer.writeIntLittle(u64, 0);
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 // }
524 pub fn numRela(got: GotSection, elf_file: *Elf) usize {
525 const is_dyn_lib = elf_file.isDynLib();
526 var num: usize = 0;
527 for (got.entries.items) |entry| {
528 const symbol = switch (entry.tag) {
529 .tlsld => null,
530 inline else => elf_file.symbol(entry.symbol_index),
531 };
532 switch (entry.tag) {
533 .got => if (symbol.?.flags.import or
534 symbol.?.isIFunc(elf_file) or (elf_file.base.options.pic and !symbol.?.isAbs(elf_file)))
535 {
536 num += 1;
537 },
538
539 .tlsld => if (is_dyn_lib) {
540 num += 1;
541 },
542
543 .tlsgd => if (symbol.?.flags.import) {
544 num += 2;
545 } else if (is_dyn_lib) {
546 num += 1;
547 },
548
549 .gottp => if (symbol.?.flags.import or is_dyn_lib) {
550 num += 1;
551 },
552
553 .tlsdesc => num += 1,
554 }
555 }
556 return num;
557 }
376558
377559 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
378560 _ = elf_file;
......@@ -382,8 +564,11 @@ pub const GotSection = struct {
382564 pub fn updateStrtab(got: GotSection, elf_file: *Elf) !void {
383565 const gpa = elf_file.base.allocator;
384566 for (got.entries.items) |entry| {
385 const symbol = elf_file.symbol(entry.symbol_index);
386 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol.name(elf_file), @tagName(entry.tag) });
567 const symbol_name = switch (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) });
387572 defer gpa.free(name);
388573 _ = try elf_file.strtab.insert(gpa, name);
389574 }
......@@ -392,14 +577,18 @@ pub const GotSection = struct {
392577 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {
393578 const gpa = elf_file.base.allocator;
394579 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
395 const symbol = elf_file.symbol(entry.symbol_index);
396 const name = try std.fmt.allocPrint(gpa, "{s}${s}", .{ symbol.name(elf_file), @tagName(entry.tag) });
580 const symbol = switch (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) });
397589 defer gpa.free(name);
398590 const st_name = try elf_file.strtab.insert(gpa, name);
399 const st_value = switch (entry.tag) {
400 .got => symbol.gotAddress(elf_file),
401 else => unreachable,
402 };
591 const st_value = entry.address(elf_file);
403592 const st_size: u64 = entry.len() * elf_file.archPtrWidthBytes();
404593 ctx.symtab[ilocal] = .{
405594 .st_name = st_name,
......@@ -443,12 +632,697 @@ pub const GotSection = struct {
443632 }
444633};
445634
635pub 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
750pub 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
779pub 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
854pub 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
932pub 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
1019pub 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
1071pub 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
1181pub 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
4461317const assert = std.debug.assert;
4471318const builtin = @import("builtin");
4481319const elf = std.elf;
1320const mem = std.mem;
4491321const log = std.log.scoped(.link);
4501322const std = @import("std");
4511323
4521324const Allocator = std.mem.Allocator;
4531325const Elf = @import("../Elf.zig");
1326const File = @import("file.zig").File;
1327const SharedObject = @import("SharedObject.zig");
4541328const Symbol = @import("Symbol.zig");