authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-31 15:45:36+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-07 10:21:02+02:00
log9fe69cc0b588ff96075854d687f3fce3d4457258
treeca08a39f9fb895d001d49773a25218db383f6555
parentd0367b02199417c10b2cde6d0deae4242689d127

elf: move symbol ownership to SharedObject


2 files changed, 200 insertions(+), 131 deletions(-)

src/link/Elf/Object.zig+75-84
...@@ -562,7 +562,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {...@@ -562,7 +562,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
562 }562 }
563}563}
564564
565pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {565pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void {
566 const gpa = elf_file.base.comp.gpa;566 const gpa = elf_file.base.comp.gpa;
567567
568 const first_global = self.first_global orelse return;568 const first_global = self.first_global orelse return;
...@@ -585,12 +585,12 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -585,12 +585,12 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
585 resolv.* = gop.index;585 resolv.* = gop.index;
586586
587 if (esym.st_shndx == elf.SHN_UNDEF) continue;587 if (esym.st_shndx == elf.SHN_UNDEF) continue;
588 if (elf_file.symbol(gop.ref) == null) {588 if (elf_file.symbol(gop.ref.*) == null) {
589 gop.ref.* = .{ .index = @intCast(i), .file = self.index };589 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
590 continue;590 continue;
591 }591 }
592592
593 if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref).?.symbolRank(elf_file)) {593 if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
594 gop.ref.* = .{ .index = @intCast(i), .file = self.index };594 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
595 }595 }
596 }596 }
...@@ -625,34 +625,40 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -625,34 +625,40 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
625625
626pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {626pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
627 const first_global = self.first_global orelse return;627 const first_global = self.first_global orelse return;
628 for (self.globals(), 0..) |index, i| {628 for (self.globals(), 0..) |*sym, i| {
629 const esym_index = @as(u32, @intCast(first_global + i));629 const esym_index = @as(u32, @intCast(first_global + i));
630 const esym = self.symtab.items[esym_index];630 const esym = self.symtab.items[esym_index];
631 if (esym.st_shndx != elf.SHN_UNDEF) continue;631 if (esym.st_shndx != elf.SHN_UNDEF) continue;
632 if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue;
632633
633 const global = elf_file.symbol(index);634 // TODO: audit this
634 if (global.file(elf_file)) |file| {635 // const global = elf_file.symbol(index);
635 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;636 // if (global.file(elf_file)) |file| {
636 }637 // if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
638 // }
637639
638 global.value = 0;640 sym.value = 0;
639 global.ref = .{ .index = 0, .file = 0 };641 sym.ref = .{ .index = 0, .file = 0 };
640 global.esym_index = esym_index;642 sym.esym_index = esym_index;
641 global.file_index = self.index;643 sym.file_index = self.index;
644
645 const idx = self.symbols_resolver.items[i];
646 elf_file.resolver.items[idx - 1] = .{ .index = esym_index, .file = self.index };
642 }647 }
643}648}
644649
645pub fn markLive(self: *Object, elf_file: *Elf) void {650pub fn markLive(self: *Object, elf_file: *Elf) void {
646 const first_global = self.first_global orelse return;651 const first_global = self.first_global orelse return;
647 for (self.globals(), 0..) |index, i| {652 for (0..self.globals().len) |i| {
648 const sym_idx = first_global + i;653 const esym_idx = first_global + i;
649 const sym = self.symtab.items[sym_idx];654 const esym = self.symtab.items[esym_idx];
650 if (sym.st_bind() == elf.STB_WEAK) continue;655 if (esym.st_bind() == elf.STB_WEAK) continue;
651656
652 const global = elf_file.symbol(index);657 const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
653 const file = global.file(elf_file) orelse continue;658 const sym = elf_file.symbol(ref) orelse continue;
654 const should_keep = sym.st_shndx == elf.SHN_UNDEF or659 const file = sym.file(elf_file).?;
655 (sym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);660 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
661 (esym.st_shndx == elf.SHN_COMMON and sym.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
656 if (should_keep and !file.isAlive()) {662 if (should_keep and !file.isAlive()) {
657 file.setAlive();663 file.setAlive();
658 file.markLive(elf_file);664 file.markLive(elf_file);
...@@ -672,24 +678,25 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {...@@ -672,24 +678,25 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
672678
673pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {679pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
674 const first_global = self.first_global orelse return;680 const first_global = self.first_global orelse return;
675 for (self.globals(), 0..) |index, i| {681 for (0..self.globals().len) |i| {
676 const sym_idx = first_global + i;682 const esym_idx = first_global + i;
677 const sym = self.symtab.items[sym_idx];683 const esym = self.symtab.items[esym_idx];
678 const global = elf_file.symbol(index);684 const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
679 const global_file = global.file(elf_file) orelse continue;685 const ref_sym = elf_file.symbol(ref) orelse continue;
680686 const ref_file = ref_sym.file(elf_file).?;
681 if (self.index == global_file.index() or687
682 sym.st_shndx == elf.SHN_UNDEF or688 if (self.index == ref_file.index() or
683 sym.st_bind() == elf.STB_WEAK or689 esym.st_shndx == elf.SHN_UNDEF or
684 sym.st_shndx == elf.SHN_COMMON) continue;690 esym.st_bind() == elf.STB_WEAK or
685691 esym.st_shndx == elf.SHN_COMMON) continue;
686 if (sym.st_shndx != elf.SHN_ABS) {692
687 const atom_index = self.atoms_indexes.items[sym.st_shndx];693 if (esym.st_shndx != elf.SHN_ABS) {
694 const atom_index = self.atoms_indexes.items[esym.st_shndx];
688 const atom_ptr = self.atom(atom_index) orelse continue;695 const atom_ptr = self.atom(atom_index) orelse continue;
689 if (!atom_ptr.alive) continue;696 if (!atom_ptr.alive) continue;
690 }697 }
691698
692 const gop = try dupes.getOrPut(index);699 const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
693 if (!gop.found_existing) {700 if (!gop.found_existing) {
694 gop.value_ptr.* = .{};701 gop.value_ptr.* = .{};
695 }702 }
...@@ -819,8 +826,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -819,8 +826,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
819 }826 }
820827
821 for (self.symtab.items, 0..) |*esym, idx| {828 for (self.symtab.items, 0..) |*esym, idx| {
822 const sym_index = self.symbols.items[idx];829 const sym = &self.symbols.items[idx];
823 const sym = elf_file.symbol(sym_index);830 // TODO: do we need ref here?
824831
825 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;832 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
826833
...@@ -860,23 +867,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -860,23 +867,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
860 return error.MalformedObject;867 return error.MalformedObject;
861 };868 };
862869
863 const out_sym_idx: u64 = @intCast(self.symbols.items.len);870 const sym_index = try self.addSymbol(gpa);
864 try self.symbols.ensureUnusedCapacity(gpa, 1);871 const sym = &self.symbols.items[sym_index];
865 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });872 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });
866 defer gpa.free(name);873 defer gpa.free(name);
867 const sym_index = try elf_file.addSymbol();
868 const sym = elf_file.symbol(sym_index);
869 sym.* = .{874 sym.* = .{
870 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),875 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
871 .name_offset = try self.addString(gpa, name),876 .name_offset = try self.addString(gpa, name),
872 .esym_index = rel.r_sym(),877 .esym_index = rel.r_sym(),
873 .file_index = self.index,878 .file_index = self.index,
874 .extra_index = try elf_file.addSymbolExtra(.{}),879 .extra_index = try self.addSymbolExtra(gpa, .{}),
875 };880 };
876 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };881 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
877 sym.flags.merge_subsection = true;882 sym.flags.merge_subsection = true;
878 self.symbols.addOneAssumeCapacity().* = sym_index;883 rel.r_info = (@as(u64, @intCast(sym_index)) << 32) | rel.r_type();
879 rel.r_info = (out_sym_idx << 32) | rel.r_type();
880 }884 }
881 }885 }
882}886}
...@@ -885,27 +889,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -885,27 +889,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
885/// play nicely with the rest of the system.889/// play nicely with the rest of the system.
886pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {890pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
887 const first_global = self.first_global orelse return;891 const first_global = self.first_global orelse return;
888 for (self.globals(), 0..) |index, i| {892 for (self.globals(), self.symbols_resolver.items, 0..) |*sym, resolv, i| {
889 const sym_idx = @as(u32, @intCast(first_global + i));893 const esym_idx = @as(u32, @intCast(first_global + i));
890 const this_sym = self.symtab.items[sym_idx];894 const esym = self.symtab.items[esym_idx];
891 if (this_sym.st_shndx != elf.SHN_COMMON) continue;895 if (esym.st_shndx != elf.SHN_COMMON) continue;
892896 if (elf_file.resolver.get(resolv).?.file != self.index) continue;
893 const global = elf_file.symbol(index);
894 const global_file = global.file(elf_file).?;
895 if (global_file.index() != self.index) {
896 // if (elf_file.options.warn_common) {
897 // elf_file.base.warn("{}: multiple common symbols: {s}", .{
898 // self.fmtPath(),
899 // global.getName(elf_file),
900 // });
901 // }
902 continue;
903 }
904897
905 const comp = elf_file.base.comp;898 const comp = elf_file.base.comp;
906 const gpa = comp.gpa;899 const gpa = comp.gpa;
907900
908 const is_tls = global.type(elf_file) == elf.STT_TLS;901 const is_tls = sym.type(elf_file) == elf.STT_TLS;
909 const name = if (is_tls) ".tls_common" else ".common";902 const name = if (is_tls) ".tls_common" else ".common";
910 const name_offset = @as(u32, @intCast(self.strtab.items.len));903 const name_offset = @as(u32, @intCast(self.strtab.items.len));
911 try self.strtab.writer(gpa).print("{s}\x00", .{name});904 try self.strtab.writer(gpa).print("{s}\x00", .{name});
...@@ -914,7 +907,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -914,7 +907,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
914 if (is_tls) sh_flags |= elf.SHF_TLS;907 if (is_tls) sh_flags |= elf.SHF_TLS;
915 const shndx = @as(u32, @intCast(self.shdrs.items.len));908 const shndx = @as(u32, @intCast(self.shdrs.items.len));
916 const shdr = try self.shdrs.addOne(gpa);909 const shdr = try self.shdrs.addOne(gpa);
917 const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;910 const sh_size = math.cast(usize, esym.st_size) orelse return error.Overflow;
918 shdr.* = .{911 shdr.* = .{
919 .sh_name = name_offset,912 .sh_name = name_offset,
920 .sh_type = elf.SHT_NOBITS,913 .sh_type = elf.SHT_NOBITS,
...@@ -924,21 +917,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -924,21 +917,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
924 .sh_size = sh_size,917 .sh_size = sh_size,
925 .sh_link = 0,918 .sh_link = 0,
926 .sh_info = 0,919 .sh_info = 0,
927 .sh_addralign = this_sym.st_value,920 .sh_addralign = esym.st_value,
928 .sh_entsize = 0,921 .sh_entsize = 0,
929 };922 };
930923
931 const atom_index = try self.addAtom(gpa, .{924 const atom_index = try self.addAtom(gpa, .{
932 .name = name_offset,925 .name = name_offset,
933 .shndx = shndx,926 .shndx = shndx,
934 .size = this_sym.st_size,927 .size = esym.st_size,
935 .alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),928 .alignment = Alignment.fromNonzeroByteUnits(esym.st_value),
936 });929 });
937 try self.atoms_indexes.append(gpa, atom_index);930 try self.atoms_indexes.append(gpa, atom_index);
938931
939 global.value = 0;932 sym.value = 0;
940 global.ref = .{ .index = atom_index, .file = self.index };933 sym.ref = .{ .index = atom_index, .file = self.index };
941 global.flags.weak = false;934 sym.flags.weak = false;
942 }935 }
943}936}
944937
...@@ -1080,7 +1073,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {...@@ -1080,7 +1073,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
1080 try writer.writeAll(data);1073 try writer.writeAll(data);
1081}1074}
10821075
1083pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {1076pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
1084 const isAlive = struct {1077 const isAlive = struct {
1085 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {1078 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
1086 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;1079 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
...@@ -1089,8 +1082,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1089,8 +1082,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1089 }1082 }
1090 }.isAlive;1083 }.isAlive;
10911084
1092 for (self.locals()) |local_index| {1085 for (self.locals()) |*local| {
1093 const local = elf_file.symbol(local_index);
1094 if (!isAlive(local, elf_file)) continue;1086 if (!isAlive(local, elf_file)) continue;
1095 const esym = local.elfSym(elf_file);1087 const esym = local.elfSym(elf_file);
1096 switch (esym.st_type()) {1088 switch (esym.st_type()) {
...@@ -1099,22 +1091,22 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1099,22 +1091,22 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1099 else => {},1091 else => {},
1100 }1092 }
1101 local.flags.output_symtab = true;1093 local.flags.output_symtab = true;
1102 try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);1094 local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
1103 self.output_symtab_ctx.nlocals += 1;1095 self.output_symtab_ctx.nlocals += 1;
1104 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;1096 self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
1105 }1097 }
11061098
1107 for (self.globals()) |global_index| {1099 for (self.globals(), self.symbols_resolver.items) |*global, resolv| {
1108 const global = elf_file.symbol(global_index);1100 const ref = elf_file.resolver.items[resolv];
1109 const file_ptr = global.file(elf_file) orelse continue;1101 const ref_sym = elf_file.symbol(ref) orelse continue;
1110 if (file_ptr.index() != self.index) continue;1102 if (ref_sym.file(elf_file).?.index() != self.index) continue;
1111 if (!isAlive(global, elf_file)) continue;1103 if (!isAlive(global, elf_file)) continue;
1112 global.flags.output_symtab = true;1104 global.flags.output_symtab = true;
1113 if (global.isLocal(elf_file)) {1105 if (global.isLocal(elf_file)) {
1114 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);1106 global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
1115 self.output_symtab_ctx.nlocals += 1;1107 self.output_symtab_ctx.nlocals += 1;
1116 } else {1108 } else {
1117 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);1109 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
1118 self.output_symtab_ctx.nglobals += 1;1110 self.output_symtab_ctx.nglobals += 1;
1119 }1111 }
1120 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;1112 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
...@@ -1122,8 +1114,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1122,8 +1114,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1122}1114}
11231115
1124pub fn writeSymtab(self: Object, elf_file: *Elf) void {1116pub fn writeSymtab(self: Object, elf_file: *Elf) void {
1125 for (self.locals()) |local_index| {1117 for (self.locals()) |local| {
1126 const local = elf_file.symbol(local_index);
1127 const idx = local.outputSymtabIndex(elf_file) orelse continue;1118 const idx = local.outputSymtabIndex(elf_file) orelse continue;
1128 const out_sym = &elf_file.symtab.items[idx];1119 const out_sym = &elf_file.symtab.items[idx];
1129 out_sym.st_name = @intCast(elf_file.strtab.items.len);1120 out_sym.st_name = @intCast(elf_file.strtab.items.len);
...@@ -1132,10 +1123,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {...@@ -1132,10 +1123,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
1132 local.setOutputSym(elf_file, out_sym);1123 local.setOutputSym(elf_file, out_sym);
1133 }1124 }
11341125
1135 for (self.globals()) |global_index| {1126 for (self.globals(), self.symbols_resolver.items) |global, resolv| {
1136 const global = elf_file.symbol(global_index);1127 const ref = elf_file.resolver.items[resolv];
1137 const file_ptr = global.file(elf_file) orelse continue;1128 const ref_sym = elf_file.symbol(ref) orelse continue;
1138 if (file_ptr.index() != self.index) continue;1129 if (ref_sym.file(elf_file).?.index() != self.index) continue;
1139 const idx = global.outputSymtabIndex(elf_file) orelse continue;1130 const idx = global.outputSymtabIndex(elf_file) orelse continue;
1140 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));1131 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
1141 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));1132 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
src/link/Elf/SharedObject.zig+125-47
...@@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},...@@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
11verstrings: std.ArrayListUnmanaged(u32) = .{},11verstrings: std.ArrayListUnmanaged(u32) = .{},
1212
13symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},13symbols: std.ArrayListUnmanaged(Symbol) = .{},
14symbols_extra: std.ArrayListUnmanaged(u32) = .{},
15symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
16
14aliases: ?std.ArrayListUnmanaged(u32) = null,17aliases: ?std.ArrayListUnmanaged(u32) = null,
15dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},18dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},
1619
...@@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void {...@@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void {
38 self.versyms.deinit(allocator);41 self.versyms.deinit(allocator);
39 self.verstrings.deinit(allocator);42 self.verstrings.deinit(allocator);
40 self.symbols.deinit(allocator);43 self.symbols.deinit(allocator);
44 self.symbols_extra.deinit(allocator);
45 self.symbols_resolver.deinit(allocator);
41 if (self.aliases) |*aliases| aliases.deinit(allocator);46 if (self.aliases) |*aliases| aliases.deinit(allocator);
42 self.dynamic_table.deinit(allocator);47 self.dynamic_table.deinit(allocator);
43}48}
...@@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {...@@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
129 .versym_sect_index = versym_sect_index,134 .versym_sect_index = versym_sect_index,
130 });135 });
131136
132 try self.initSymtab(elf_file, .{137 try self.initSymbols(elf_file, .{
133 .symtab = symtab,138 .symtab = symtab,
134 .strtab = strtab,139 .strtab = strtab,
135 });140 });
...@@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts:...@@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts:
188 }193 }
189}194}
190195
191fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {196fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct {
192 symtab: []align(1) const elf.Elf64_Sym,197 symtab: []align(1) const elf.Elf64_Sym,
193 strtab: []const u8,198 strtab: []const u8,
194}) !void {199}) !void {
195 const comp = elf_file.base.comp;200 const gpa = elf_file.base.comp.gpa;
196 const gpa = comp.gpa;201 const nsyms = opts.symtab.len;
197202
198 try self.strtab.appendSlice(gpa, opts.strtab);203 try self.strtab.appendSlice(gpa, opts.strtab);
199 try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len);204 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
200 try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len);205 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
206 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
207 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
208 self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
209 @memset(self.symbols_resolver.items, 0);
201210
202 for (opts.symtab, 0..) |sym, i| {211 for (opts.symtab, 0..) |sym, i| {
203 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;212 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
...@@ -214,41 +223,56 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {...@@ -214,41 +223,56 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {
214 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});223 try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
215 break :blk name_off;224 break :blk name_off;
216 } else sym.st_name;225 } else sym.st_name;
217 const out_sym = self.symtab.addOneAssumeCapacity();226 const out_esym_index: u32 = @intCast(self.symtab.items.len);
218 out_sym.* = sym;227 const out_esym = self.symtab.addOneAssumeCapacity();
219 out_sym.st_name = name_off;228 out_esym.* = sym;
220 const gop = try elf_file.getOrPutGlobal(self.getString(name_off));229 out_esym.st_name = name_off;
221 self.symbols.addOneAssumeCapacity().* = gop.index;230 const out_sym_index = self.addSymbolAssumeCapacity();
231 const out_sym = &self.symbols.items[out_sym_index];
232 out_sym.* = .{
233 .value = @intCast(out_esym.st_value),
234 .ref = .{ .index = 0, .file = 0 },
235 .esym_index = out_esym_index,
236 .version_index = self.versyms.items[out_esym_index],
237 .extra_index = self.addSymbolExtraAssumeCapacity(.{}),
238 };
222 }239 }
223}240}
224241
225pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {242pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
226 for (self.globals(), 0..) |index, i| {243 const gpa = elf_file.base.comp.gpa;
227 const esym_index = @as(u32, @intCast(i));244
228 const this_sym = self.symtab.items[esym_index];245 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
246 const gop = try elf_file.resolver.getOrPut(gpa, .{
247 .index = @intCast(i),
248 .file = self.index,
249 }, elf_file);
250 if (!gop.found_existing) {
251 gop.ref.* = .{ .index = 0, .file = 0 };
252 }
253 resolv.* = gop.index;
229254
230 if (this_sym.st_shndx == elf.SHN_UNDEF) continue;255 if (esym.st_shndx == elf.SHN_UNDEF) continue;
256 if (elf_file.symbol(gop.ref.*) == null) {
257 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
258 continue;
259 }
231260
232 const global = elf_file.symbol(index);261 if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {262 gop.ref.* = .{ .index = @intCast(i), .file = self.index };
234 global.value = @intCast(this_sym.st_value);
235 global.ref = .{ .index = 0, .file = 0 };
236 global.esym_index = esym_index;
237 global.version_index = self.versyms.items[esym_index];
238 global.file_index = self.index;
239 }263 }
240 }264 }
241}265}
242266
243pub fn markLive(self: *SharedObject, elf_file: *Elf) void {267pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
244 for (self.globals(), 0..) |index, i| {268 for (self.symtab.items, 0..) |esym, i| {
245 const sym = self.symtab.items[i];269 if (esym.st_shndx != elf.SHN_UNDEF) continue;
246 if (sym.st_shndx != elf.SHN_UNDEF) continue;
247270
248 const global = elf_file.symbol(index);271 const ref = self.resolveSymbol(@intCast(i), elf_file);
249 const file = global.file(elf_file) orelse continue;272 const sym = elf_file.symbol(ref) orelse continue;
273 const file = sym.file(elf_file).?;
250 const should_drop = switch (file) {274 const should_drop = switch (file) {
251 .shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK,275 .shared_object => |sh| !sh.needed and esym.st_bind() == elf.STB_WEAK,
252 else => false,276 else => false,
253 };277 };
254 if (!should_drop and !file.isAlive()) {278 if (!should_drop and !file.isAlive()) {
...@@ -262,24 +286,24 @@ pub fn globals(self: SharedObject) []const Symbol.Index {...@@ -262,24 +286,24 @@ pub fn globals(self: SharedObject) []const Symbol.Index {
262 return self.symbols.items;286 return self.symbols.items;
263}287}
264288
265pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void {289pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
266 for (self.globals()) |global_index| {290 for (self.globals(), self.symbols_resolver.items) |*global, resolv| {
267 const global = elf_file.symbol(global_index);291 const ref = elf_file.resolver.get(resolv).?;
268 const file_ptr = global.file(elf_file) orelse continue;292 const ref_sym = elf_file.symbol(ref) orelse continue;
269 if (file_ptr.index() != self.index) continue;293 if (ref_sym.file(elf_file).?.index() != self.index) continue;
270 if (global.isLocal(elf_file)) continue;294 if (global.isLocal(elf_file)) continue;
271 global.flags.output_symtab = true;295 global.flags.output_symtab = true;
272 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);296 global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
273 self.output_symtab_ctx.nglobals += 1;297 self.output_symtab_ctx.nglobals += 1;
274 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;298 self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
275 }299 }
276}300}
277301
278pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void {302pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void {
279 for (self.globals()) |global_index| {303 for (self.globals(), self.symbols_resolver.items) |global, resolv| {
280 const global = elf_file.symbol(global_index);304 const ref = elf_file.resolver.get(resolv).?;
281 const file_ptr = global.file(elf_file) orelse continue;305 const ref_sym = elf_file.symbol(ref) orelse continue;
282 if (file_ptr.index() != self.index) continue;306 if (ref_sym.file(elf_file).?.index() != self.index) continue;
283 const idx = global.outputSymtabIndex(elf_file) orelse continue;307 const idx = global.outputSymtabIndex(elf_file) orelse continue;
284 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));308 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
285 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));309 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
...@@ -332,10 +356,10 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -332,10 +356,10 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
332 defer aliases.deinit();356 defer aliases.deinit();
333 try aliases.ensureTotalCapacityPrecise(self.globals().len);357 try aliases.ensureTotalCapacityPrecise(self.globals().len);
334358
335 for (self.globals()) |index| {359 for (self.symbols_resolvers.items, 0..) |resolv, index| {
336 const global = elf_file.symbol(index);360 const ref = elf_file.resolver.get(resolv).?;
337 const global_file = global.file(elf_file) orelse continue;361 const ref_sym = elf_file.symbol(ref) orelse continue;
338 if (global_file.index() != self.index) continue;362 if (ref_sym.file(elf_file).?.index() != self.index) continue;
339 aliases.appendAssumeCapacity(index);363 aliases.appendAssumeCapacity(index);
340 }364 }
341365
...@@ -347,16 +371,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -347,16 +371,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
347pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {371pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {
348 assert(self.aliases != null);372 assert(self.aliases != null);
349373
350 const symbol = elf_file.symbol(index).elfSym(elf_file);374 const symbol = self.symbol(index).elfSym(elf_file);
351 const aliases = self.aliases.?;375 const aliases = self.aliases.?;
352376
353 const start = for (aliases.items, 0..) |alias, i| {377 const start = for (aliases.items, 0..) |alias, i| {
354 const alias_sym = elf_file.symbol(alias).elfSym(elf_file);378 const alias_sym = self.symbol(alias).elfSym(elf_file);
355 if (symbol.st_value == alias_sym.st_value) break i;379 if (symbol.st_value == alias_sym.st_value) break i;
356 } else aliases.items.len;380 } else aliases.items.len;
357381
358 const end = for (aliases.items[start..], 0..) |alias, i| {382 const end = for (aliases.items[start..], 0..) |alias, i| {
359 const alias_sym = elf_file.symbol(alias).elfSym(elf_file);383 const alias_sym = self.symbol(alias).elfSym(elf_file);
360 if (symbol.st_value < alias_sym.st_value) break i + start;384 if (symbol.st_value < alias_sym.st_value) break i + start;
361 } else aliases.items.len;385 } else aliases.items.len;
362386
...@@ -368,6 +392,60 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 {...@@ -368,6 +392,60 @@ pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
368 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);392 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
369}393}
370394
395pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
396 const resolv = self.symbols_resolver.items[index];
397 return elf_file.resolver.get(resolv).?;
398}
399
400pub fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index {
401 try self.symbols.ensureUnusedCapacity(allocator, 1);
402 const index: Symbol.Index = @intCast(self.symbols.items.len);
403 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
404 return index;
405}
406
407pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
408 const fields = @typeInfo(Symbol.Extra).Struct.fields;
409 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
410 return self.addSymbolExtraAssumeCapacity(extra);
411}
412
413pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
414 const index = @as(u32, @intCast(self.symbols_extra.items.len));
415 const fields = @typeInfo(Symbol.Extra).Struct.fields;
416 inline for (fields) |field| {
417 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
418 u32 => @field(extra, field.name),
419 else => @compileError("bad field type"),
420 });
421 }
422 return index;
423}
424
425pub fn symbolExtra(self: *SharedObject, index: u32) Symbol.Extra {
426 const fields = @typeInfo(Symbol.Extra).Struct.fields;
427 var i: usize = index;
428 var result: Symbol.Extra = undefined;
429 inline for (fields) |field| {
430 @field(result, field.name) = switch (field.type) {
431 u32 => self.symbols_extra.items[i],
432 else => @compileError("bad field type"),
433 };
434 i += 1;
435 }
436 return result;
437}
438
439pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void {
440 const fields = @typeInfo(Symbol.Extra).Struct.fields;
441 inline for (fields, 0..) |field, i| {
442 self.symbols_extra.items[index + i] = switch (field.type) {
443 u32 => @field(extra, field.name),
444 else => @compileError("bad field type"),
445 };
446 }
447}
448
371pub fn format(449pub fn format(
372 self: SharedObject,450 self: SharedObject,
373 comptime unused_fmt_string: []const u8,451 comptime unused_fmt_string: []const u8,