authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-30 18:49:39+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-30 18:49:39+02:00
log30b4a87db711c368853b3eff8e214ab681810ef9
tree7a2f72eeebba5f8fd6a457edee99ab6c720d4f5b
parentf219286573a7a1edafe3e1b5bc1e521a379ee2e2
parent3f10217a47ff259ca3671dd8bb89a04417bccdc2
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20873 from ziglang/elf-ownership

elf: clean up resource ownership in the linker

17 files changed, 1203 insertions(+), 1006 deletions(-)

src/link/Elf.zig+166-532
......@@ -54,7 +54,7 @@ phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
5454shdr_table_offset: ?u64 = null,
5555/// Table of lists of atoms per output section.
5656/// This table is not used to track incrementally generated atoms.
57output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Atom.Index)) = .{},
57output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Ref)) = .{},
5858output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},
5959
6060/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
......@@ -93,7 +93,6 @@ phdr_gnu_stack_index: ?u16 = null,
9393/// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
9494phdr_tls_index: ?u16 = null,
9595
96entry_index: ?Symbol.Index = null,
9796page_size: u32,
9897default_sym_version: elf.Elf64_Versym,
9998
......@@ -174,25 +173,6 @@ shstrtab_section_index: ?u32 = null,
174173strtab_section_index: ?u32 = null,
175174symtab_section_index: ?u32 = null,
176175
177// Linker-defined symbols
178dynamic_index: ?Symbol.Index = null,
179ehdr_start_index: ?Symbol.Index = null,
180init_array_start_index: ?Symbol.Index = null,
181init_array_end_index: ?Symbol.Index = null,
182fini_array_start_index: ?Symbol.Index = null,
183fini_array_end_index: ?Symbol.Index = null,
184preinit_array_start_index: ?Symbol.Index = null,
185preinit_array_end_index: ?Symbol.Index = null,
186got_index: ?Symbol.Index = null,
187plt_index: ?Symbol.Index = null,
188end_index: ?Symbol.Index = null,
189gnu_eh_frame_hdr_index: ?Symbol.Index = null,
190dso_handle_index: ?Symbol.Index = null,
191rela_iplt_start_index: ?Symbol.Index = null,
192rela_iplt_end_index: ?Symbol.Index = null,
193global_pointer_index: ?Symbol.Index = null,
194start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
195
196176/// An array of symbols parsed across all input files.
197177symbols: std.ArrayListUnmanaged(Symbol) = .{},
198178symbols_extra: std.ArrayListUnmanaged(u32) = .{},
......@@ -203,30 +183,17 @@ resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
203183has_text_reloc: bool = false,
204184num_ifunc_dynrelocs: usize = 0,
205185
206/// List of atoms that are owned directly by the linker.
207atoms: std.ArrayListUnmanaged(Atom) = .{},
208atoms_extra: std.ArrayListUnmanaged(u32) = .{},
209
210186/// List of range extension thunks.
211187thunks: std.ArrayListUnmanaged(Thunk) = .{},
212188
213189/// List of output merge sections with deduped contents.
214190merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
215/// List of output merge subsections.
216/// Each subsection is akin to Atom but belongs to a MergeSection.
217merge_subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
218/// List of input merge sections as parsed from input relocatables.
219merge_input_sections: std.ArrayListUnmanaged(InputMergeSection) = .{},
220191
221192/// Table of last atom index in a section and matching atom free list if any.
222193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
223194
224comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
225comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
226comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
227
228195/// Global string table used to provide quick access to global symbol resolvers
229/// such as `resolver` and `comdat_groups_table`.
196/// such as `resolver`.
230197strings: StringTable = .{},
231198
232199first_eflags: ?elf.Elf64_Word = null,
......@@ -378,20 +345,15 @@ pub fn createEmpty(
378345 try self.symbols.append(gpa, .{});
379346 // Index 0 is always a null symbol.
380347 try self.symbols_extra.append(gpa, 0);
381 // Allocate atom index 0 to null atom
382 try self.atoms.append(gpa, .{});
383 try self.atoms_extra.append(gpa, 0);
384348 // Append null file at index 0
385349 try self.files.append(gpa, .null);
386350 // Append null byte to string tables
387351 try self.shstrtab.append(gpa, 0);
388352 try self.strtab.append(gpa, 0);
389353 // There must always be a null shdr in index 0
390 _ = try self.addSection(.{ .name = "" });
354 _ = try self.addSection(.{});
391355 // Append null symbol in output symtab
392356 try self.symtab.append(gpa, null_sym);
393 // Append null input merge section.
394 try self.merge_input_sections.append(gpa, .{});
395357
396358 if (!is_obj_or_ar) {
397359 try self.dynstrtab.append(gpa, 0);
......@@ -502,10 +464,7 @@ pub fn deinit(self: *Elf) void {
502464 self.symbols_extra.deinit(gpa);
503465 self.symbols_free_list.deinit(gpa);
504466 self.resolver.deinit(gpa);
505 self.start_stop_indexes.deinit(gpa);
506467
507 self.atoms.deinit(gpa);
508 self.atoms_extra.deinit(gpa);
509468 for (self.thunks.items) |*th| {
510469 th.deinit(gpa);
511470 }
......@@ -514,19 +473,11 @@ pub fn deinit(self: *Elf) void {
514473 sect.deinit(gpa);
515474 }
516475 self.merge_sections.deinit(gpa);
517 self.merge_subsections.deinit(gpa);
518 for (self.merge_input_sections.items) |*sect| {
519 sect.deinit(gpa);
520 }
521 self.merge_input_sections.deinit(gpa);
522476 for (self.last_atom_and_free_list_table.values()) |*value| {
523477 value.free_list.deinit(gpa);
524478 }
525479 self.last_atom_and_free_list_table.deinit(gpa);
526480
527 self.comdat_groups.deinit(gpa);
528 self.comdat_groups_owners.deinit(gpa);
529 self.comdat_groups_table.deinit(gpa);
530481 self.strings.deinit(gpa);
531482
532483 self.got.deinit(gpa);
......@@ -744,7 +695,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
744695
745696 if (self.zig_text_section_index == null) {
746697 self.zig_text_section_index = try self.addSection(.{
747 .name = ".text.zig",
698 .name = try self.insertShString(".text.zig"),
748699 .type = elf.SHT_PROGBITS,
749700 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
750701 .addralign = 1,
......@@ -753,7 +704,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
753704 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
754705 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
755706 if (self.base.isRelocatable()) {
756 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
707 const rela_shndx = try self.addRelaShdr(try self.insertShString(".rela.text.zig"), self.zig_text_section_index.?);
757708 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
758709 .shndx = rela_shndx,
759710 });
......@@ -770,7 +721,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
770721
771722 if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
772723 self.zig_got_section_index = try self.addSection(.{
773 .name = ".got.zig",
724 .name = try self.insertShString(".got.zig"),
774725 .type = elf.SHT_PROGBITS,
775726 .addralign = ptr_size,
776727 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
......@@ -791,7 +742,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
791742
792743 if (self.zig_data_rel_ro_section_index == null) {
793744 self.zig_data_rel_ro_section_index = try self.addSection(.{
794 .name = ".data.rel.ro.zig",
745 .name = try self.insertShString(".data.rel.ro.zig"),
795746 .type = elf.SHT_PROGBITS,
796747 .addralign = 1,
797748 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
......@@ -801,7 +752,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
801752 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
802753 if (self.base.isRelocatable()) {
803754 const rela_shndx = try self.addRelaShdr(
804 ".rela.data.rel.ro.zig",
755 try self.insertShString(".rela.data.rel.ro.zig"),
805756 self.zig_data_rel_ro_section_index.?,
806757 );
807758 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{
......@@ -820,7 +771,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
820771
821772 if (self.zig_data_section_index == null) {
822773 self.zig_data_section_index = try self.addSection(.{
823 .name = ".data.zig",
774 .name = try self.insertShString(".data.zig"),
824775 .type = elf.SHT_PROGBITS,
825776 .addralign = ptr_size,
826777 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
......@@ -830,7 +781,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
830781 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
831782 if (self.base.isRelocatable()) {
832783 const rela_shndx = try self.addRelaShdr(
833 ".rela.data.zig",
784 try self.insertShString(".rela.data.zig"),
834785 self.zig_data_section_index.?,
835786 );
836787 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{
......@@ -849,7 +800,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
849800
850801 if (self.zig_bss_section_index == null) {
851802 self.zig_bss_section_index = try self.addSection(.{
852 .name = ".bss.zig",
803 .name = try self.insertShString(".bss.zig"),
853804 .type = elf.SHT_NOBITS,
854805 .addralign = ptr_size,
855806 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
......@@ -873,7 +824,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
873824 assert(dw.strtab.buffer.items.len == 0);
874825 try dw.strtab.buffer.append(gpa, 0);
875826 self.debug_str_section_index = try self.addSection(.{
876 .name = ".debug_str",
827 .name = try self.insertShString(".debug_str"),
877828 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
878829 .entsize = 1,
879830 .type = elf.SHT_PROGBITS,
......@@ -891,7 +842,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
891842
892843 if (self.debug_info_section_index == null) {
893844 self.debug_info_section_index = try self.addSection(.{
894 .name = ".debug_info",
845 .name = try self.insertShString(".debug_info"),
895846 .type = elf.SHT_PROGBITS,
896847 .addralign = 1,
897848 .offset = std.math.maxInt(u64),
......@@ -907,7 +858,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
907858
908859 if (self.debug_abbrev_section_index == null) {
909860 self.debug_abbrev_section_index = try self.addSection(.{
910 .name = ".debug_abbrev",
861 .name = try self.insertShString(".debug_abbrev"),
911862 .type = elf.SHT_PROGBITS,
912863 .addralign = 1,
913864 .offset = std.math.maxInt(u64),
......@@ -923,7 +874,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
923874
924875 if (self.debug_aranges_section_index == null) {
925876 self.debug_aranges_section_index = try self.addSection(.{
926 .name = ".debug_aranges",
877 .name = try self.insertShString(".debug_aranges"),
927878 .type = elf.SHT_PROGBITS,
928879 .addralign = 16,
929880 .offset = std.math.maxInt(u64),
......@@ -939,7 +890,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
939890
940891 if (self.debug_line_section_index == null) {
941892 self.debug_line_section_index = try self.addSection(.{
942 .name = ".debug_line",
893 .name = try self.insertShString(".debug_line"),
943894 .type = elf.SHT_PROGBITS,
944895 .addralign = 1,
945896 .offset = std.math.maxInt(u64),
......@@ -1315,6 +1266,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13151266 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
13161267 self.files.set(index, .{ .linker_defined = .{ .index = index } });
13171268 self.linker_defined_index = index;
1269 const object = self.linkerDefinedPtr().?;
1270 try object.init(gpa);
1271 try object.initSymbols(self);
13181272 }
13191273
13201274 // Now, we are ready to resolve the symbols across all input files.
......@@ -1322,20 +1276,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13221276 // input Object files.
13231277 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
13241278 // symbol for potential resolution at load-time.
1325 self.resolveSymbols();
1279 try self.resolveSymbols();
13261280 self.markEhFrameAtomsDead();
13271281 try self.resolveMergeSections();
13281282
13291283 try self.convertCommonSymbols();
13301284 self.markImportsExports();
13311285
1332 // Look for entry address in objects if not set by the incremental compiler.
1333 if (self.entry_index == null) {
1334 if (self.entry_name) |name| {
1335 self.entry_index = self.globalByName(name);
1336 }
1337 }
1338
13391286 if (self.base.gc_sections) {
13401287 try gc.gcAtoms(self);
13411288
......@@ -1353,7 +1300,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13531300 try self.finalizeMergeSections();
13541301 try self.initOutputSections();
13551302 try self.initMergeSections();
1356 try self.addLinkerDefinedSymbols();
13571303 self.claimUnresolved();
13581304
13591305 // Scan and create missing synthetic entries such as GOT indirection.
......@@ -1379,7 +1325,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13791325 try self.sortPhdrs();
13801326 try self.allocateNonAllocSections();
13811327 self.allocateSpecialPhdrs();
1382 self.allocateLinkerDefinedSymbols();
1328 if (self.linkerDefinedPtr()) |obj| {
1329 obj.allocateSymbols(self);
1330 }
13831331
13841332 // Dump the state for easy debugging.
13851333 // State can be dumped via `--debug-log link_state`.
......@@ -1389,15 +1337,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13891337
13901338 // Beyond this point, everything has been allocated a virtual address and we can resolve
13911339 // the relocations, and commit objects to file.
1392 if (self.zigObjectPtr()) |zig_object| {
1340 if (self.zigObjectPtr()) |zo| {
13931341 var has_reloc_errors = false;
1394 for (zig_object.atoms.items) |atom_index| {
1395 const atom_ptr = self.atom(atom_index) orelse continue;
1396 if (!atom_ptr.flags.alive) continue;
1397 const out_shndx = atom_ptr.outputShndx() orelse continue;
1342 for (zo.atoms_indexes.items) |atom_index| {
1343 const atom_ptr = zo.atom(atom_index) orelse continue;
1344 if (!atom_ptr.alive) continue;
1345 const out_shndx = atom_ptr.output_section_index;
13981346 const shdr = &self.shdrs.items[out_shndx];
13991347 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1400 const code = try zig_object.codeAlloc(self, atom_index);
1348 const code = try zo.codeAlloc(self, atom_index);
14011349 defer gpa.free(code);
14021350 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
14031351 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
......@@ -1427,7 +1375,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
14271375 else => |e| return e,
14281376 };
14291377
1430 if (self.entry_index == null and self.base.isExe()) {
1378 if (self.base.isExe() and self.linkerDefinedPtr().?.entry_index == null) {
14311379 log.debug("flushing. no_entry_point_found = true", .{});
14321380 comp.link_error_flags.no_entry_point_found = true;
14331381 } else {
......@@ -1972,12 +1920,13 @@ fn accessLibPath(
19721920/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
19731921/// 5. Remove references to dead objects/shared objects
19741922/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1975pub fn resolveSymbols(self: *Elf) void {
1923pub fn resolveSymbols(self: *Elf) !void {
19761924 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
19771925 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
19781926 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
19791927 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
19801928 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
1929 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
19811930
19821931 // Mark live objects.
19831932 self.markLive();
......@@ -1986,6 +1935,7 @@ pub fn resolveSymbols(self: *Elf) void {
19861935 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
19871936 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
19881937 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
1938 if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
19891939
19901940 // Prune dead objects and shared objects.
19911941 var i: usize = 0;
......@@ -2003,41 +1953,25 @@ pub fn resolveSymbols(self: *Elf) void {
20031953 } else i += 1;
20041954 }
20051955
2006 // Dedup comdat groups.
2007 for (self.objects.items) |index| {
2008 const object = self.file(index).?.object;
2009 for (object.comdat_groups.items) |cg_index| {
2010 const cg = self.comdatGroup(cg_index);
2011 const cg_owner = self.comdatGroupOwner(cg.owner);
2012 const owner_file_index = if (self.file(cg_owner.file)) |file_ptr|
2013 file_ptr.object.index
2014 else
2015 std.math.maxInt(File.Index);
2016 cg_owner.file = @min(owner_file_index, index);
1956 {
1957 // Dedup comdat groups.
1958 var table = std.StringHashMap(Ref).init(self.base.comp.gpa);
1959 defer table.deinit();
1960
1961 for (self.objects.items) |index| {
1962 try self.file(index).?.object.resolveComdatGroups(self, &table);
20171963 }
2018 }
20191964
2020 for (self.objects.items) |index| {
2021 const object = self.file(index).?.object;
2022 for (object.comdat_groups.items) |cg_index| {
2023 const cg = self.comdatGroup(cg_index);
2024 const cg_owner = self.comdatGroupOwner(cg.owner);
2025 if (cg_owner.file != index) {
2026 for (cg.comdatGroupMembers(self)) |shndx| {
2027 const atom_index = object.atoms.items[shndx];
2028 if (self.atom(atom_index)) |atom_ptr| {
2029 atom_ptr.flags.alive = false;
2030 atom_ptr.markFdesDead(self);
2031 }
2032 }
2033 }
1965 for (self.objects.items) |index| {
1966 self.file(index).?.object.markComdatGroupsDead(self);
20341967 }
20351968 }
20361969
20371970 // Re-resolve the symbols.
2038 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
1971 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
20391972 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
20401973 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
1974 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
20411975}
20421976
20431977/// Traverses all objects and shared objects marking any object referenced by
......@@ -2129,7 +2063,7 @@ fn claimUnresolved(self: *Elf) void {
21292063fn scanRelocs(self: *Elf) !void {
21302064 const gpa = self.base.comp.gpa;
21312065
2132 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
2066 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
21332067 defer {
21342068 var it = undefs.iterator();
21352069 while (it.next()) |entry| {
......@@ -2976,10 +2910,10 @@ pub fn writeElfHeader(self: *Elf) !void {
29762910 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
29772911 index += 4;
29782912
2979 const e_entry = if (self.entry_index) |entry_index|
2980 @as(u64, @intCast(self.symbol(entry_index).address(.{}, self)))
2981 else
2982 0;
2913 const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {
2914 const entry_index = obj.entry_index orelse break :blk 0;
2915 break :blk @intCast(self.symbol(entry_index).address(.{}, self));
2916 } else 0;
29832917 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
29842918 switch (self.ptr_width) {
29852919 .p32 => {
......@@ -3106,205 +3040,6 @@ pub fn deleteExport(
31063040 return self.zigObjectPtr().?.deleteExport(self, exported, name);
31073041}
31083042
3109fn addLinkerDefinedSymbols(self: *Elf) !void {
3110 const comp = self.base.comp;
3111 const gpa = comp.gpa;
3112
3113 const linker_defined_index = self.linker_defined_index orelse return;
3114 const linker_defined = self.file(linker_defined_index).?.linker_defined;
3115 self.dynamic_index = try linker_defined.addGlobal("_DYNAMIC", self);
3116 self.ehdr_start_index = try linker_defined.addGlobal("__ehdr_start", self);
3117 self.init_array_start_index = try linker_defined.addGlobal("__init_array_start", self);
3118 self.init_array_end_index = try linker_defined.addGlobal("__init_array_end", self);
3119 self.fini_array_start_index = try linker_defined.addGlobal("__fini_array_start", self);
3120 self.fini_array_end_index = try linker_defined.addGlobal("__fini_array_end", self);
3121 self.preinit_array_start_index = try linker_defined.addGlobal("__preinit_array_start", self);
3122 self.preinit_array_end_index = try linker_defined.addGlobal("__preinit_array_end", self);
3123 self.got_index = try linker_defined.addGlobal("_GLOBAL_OFFSET_TABLE_", self);
3124 self.plt_index = try linker_defined.addGlobal("_PROCEDURE_LINKAGE_TABLE_", self);
3125 self.end_index = try linker_defined.addGlobal("_end", self);
3126
3127 if (comp.link_eh_frame_hdr) {
3128 self.gnu_eh_frame_hdr_index = try linker_defined.addGlobal("__GNU_EH_FRAME_HDR", self);
3129 }
3130
3131 if (self.globalByName("__dso_handle")) |index| {
3132 if (self.symbol(index).file(self) == null)
3133 self.dso_handle_index = try linker_defined.addGlobal("__dso_handle", self);
3134 }
3135
3136 self.rela_iplt_start_index = try linker_defined.addGlobal("__rela_iplt_start", self);
3137 self.rela_iplt_end_index = try linker_defined.addGlobal("__rela_iplt_end", self);
3138
3139 for (self.shdrs.items) |shdr| {
3140 if (self.getStartStopBasename(shdr)) |name| {
3141 try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
3142
3143 const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
3144 defer gpa.free(start);
3145 const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
3146 defer gpa.free(stop);
3147
3148 self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(start, self));
3149 self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(stop, self));
3150 }
3151 }
3152
3153 if (self.getTarget().cpu.arch.isRISCV() and self.isEffectivelyDynLib()) {
3154 self.global_pointer_index = try linker_defined.addGlobal("__global_pointer$", self);
3155 }
3156
3157 linker_defined.resolveSymbols(self);
3158}
3159
3160fn allocateLinkerDefinedSymbols(self: *Elf) void {
3161 const comp = self.base.comp;
3162 const link_mode = comp.config.link_mode;
3163
3164 // _DYNAMIC
3165 if (self.dynamic_section_index) |shndx| {
3166 const shdr = &self.shdrs.items[shndx];
3167 const symbol_ptr = self.symbol(self.dynamic_index.?);
3168 symbol_ptr.value = @intCast(shdr.sh_addr);
3169 symbol_ptr.output_section_index = shndx;
3170 }
3171
3172 // __ehdr_start
3173 {
3174 const symbol_ptr = self.symbol(self.ehdr_start_index.?);
3175 symbol_ptr.value = @intCast(self.image_base);
3176 symbol_ptr.output_section_index = 1;
3177 }
3178
3179 // __init_array_start, __init_array_end
3180 if (self.sectionByName(".init_array")) |shndx| {
3181 const start_sym = self.symbol(self.init_array_start_index.?);
3182 const end_sym = self.symbol(self.init_array_end_index.?);
3183 const shdr = &self.shdrs.items[shndx];
3184 start_sym.output_section_index = shndx;
3185 start_sym.value = @intCast(shdr.sh_addr);
3186 end_sym.output_section_index = shndx;
3187 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3188 }
3189
3190 // __fini_array_start, __fini_array_end
3191 if (self.sectionByName(".fini_array")) |shndx| {
3192 const start_sym = self.symbol(self.fini_array_start_index.?);
3193 const end_sym = self.symbol(self.fini_array_end_index.?);
3194 const shdr = &self.shdrs.items[shndx];
3195 start_sym.output_section_index = shndx;
3196 start_sym.value = @intCast(shdr.sh_addr);
3197 end_sym.output_section_index = shndx;
3198 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3199 }
3200
3201 // __preinit_array_start, __preinit_array_end
3202 if (self.sectionByName(".preinit_array")) |shndx| {
3203 const start_sym = self.symbol(self.preinit_array_start_index.?);
3204 const end_sym = self.symbol(self.preinit_array_end_index.?);
3205 const shdr = &self.shdrs.items[shndx];
3206 start_sym.output_section_index = shndx;
3207 start_sym.value = @intCast(shdr.sh_addr);
3208 end_sym.output_section_index = shndx;
3209 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
3210 }
3211
3212 // _GLOBAL_OFFSET_TABLE_
3213 if (self.getTarget().cpu.arch == .x86_64) {
3214 if (self.got_plt_section_index) |shndx| {
3215 const shdr = self.shdrs.items[shndx];
3216 const sym = self.symbol(self.got_index.?);
3217 sym.value = @intCast(shdr.sh_addr);
3218 sym.output_section_index = shndx;
3219 }
3220 } else {
3221 if (self.got_section_index) |shndx| {
3222 const shdr = self.shdrs.items[shndx];
3223 const sym = self.symbol(self.got_index.?);
3224 sym.value = @intCast(shdr.sh_addr);
3225 sym.output_section_index = shndx;
3226 }
3227 }
3228
3229 // _PROCEDURE_LINKAGE_TABLE_
3230 if (self.plt_section_index) |shndx| {
3231 const shdr = &self.shdrs.items[shndx];
3232 const symbol_ptr = self.symbol(self.plt_index.?);
3233 symbol_ptr.value = @intCast(shdr.sh_addr);
3234 symbol_ptr.output_section_index = shndx;
3235 }
3236
3237 // __dso_handle
3238 if (self.dso_handle_index) |index| {
3239 const shdr = &self.shdrs.items[1];
3240 const symbol_ptr = self.symbol(index);
3241 symbol_ptr.value = @intCast(shdr.sh_addr);
3242 symbol_ptr.output_section_index = 0;
3243 }
3244
3245 // __GNU_EH_FRAME_HDR
3246 if (self.eh_frame_hdr_section_index) |shndx| {
3247 const shdr = &self.shdrs.items[shndx];
3248 const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);
3249 symbol_ptr.value = @intCast(shdr.sh_addr);
3250 symbol_ptr.output_section_index = shndx;
3251 }
3252
3253 // __rela_iplt_start, __rela_iplt_end
3254 if (self.rela_dyn_section_index) |shndx| blk: {
3255 if (link_mode != .static or comp.config.pie) break :blk;
3256 const shdr = &self.shdrs.items[shndx];
3257 const end_addr = shdr.sh_addr + shdr.sh_size;
3258 const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
3259 const start_sym = self.symbol(self.rela_iplt_start_index.?);
3260 const end_sym = self.symbol(self.rela_iplt_end_index.?);
3261 start_sym.value = @intCast(start_addr);
3262 start_sym.output_section_index = shndx;
3263 end_sym.value = @intCast(end_addr);
3264 end_sym.output_section_index = shndx;
3265 }
3266
3267 // _end
3268 {
3269 const end_symbol = self.symbol(self.end_index.?);
3270 for (self.shdrs.items, 0..) |shdr, shndx| {
3271 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
3272 end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);
3273 end_symbol.output_section_index = @intCast(shndx);
3274 }
3275 }
3276 }
3277
3278 // __start_*, __stop_*
3279 {
3280 var index: usize = 0;
3281 while (index < self.start_stop_indexes.items.len) : (index += 2) {
3282 const start = self.symbol(self.start_stop_indexes.items[index]);
3283 const name = start.name(self);
3284 const stop = self.symbol(self.start_stop_indexes.items[index + 1]);
3285 const shndx = self.sectionByName(name["__start_".len..]).?;
3286 const shdr = &self.shdrs.items[shndx];
3287 start.value = @intCast(shdr.sh_addr);
3288 start.output_section_index = shndx;
3289 stop.value = @intCast(shdr.sh_addr + shdr.sh_size);
3290 stop.output_section_index = shndx;
3291 }
3292 }
3293
3294 // __global_pointer$
3295 if (self.global_pointer_index) |index| {
3296 const sym = self.symbol(index);
3297 if (self.sectionByName(".sdata")) |shndx| {
3298 const shdr = self.shdrs.items[shndx];
3299 sym.value = @intCast(shdr.sh_addr + 0x800);
3300 sym.output_section_index = shndx;
3301 } else {
3302 sym.value = 0;
3303 sym.output_section_index = 0;
3304 }
3305 }
3306}
3307
33083043fn checkDuplicates(self: *Elf) !void {
33093044 const gpa = self.base.comp.gpa;
33103045
......@@ -3327,12 +3062,13 @@ fn checkDuplicates(self: *Elf) !void {
33273062}
33283063
33293064pub fn addCommentString(self: *Elf) !void {
3065 const gpa = self.base.comp.gpa;
33303066 const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, elf.SHT_PROGBITS);
33313067 const msec = self.mergeSection(msec_index);
3332 const res = try msec.insertZ(self.base.comp.gpa, "zig " ++ builtin.zig_version_string);
3068 const res = try msec.insertZ(gpa, "zig " ++ builtin.zig_version_string);
33333069 if (res.found_existing) return;
3334 const msub_index = try self.addMergeSubsection();
3335 const msub = self.mergeSubsection(msub_index);
3070 const msub_index = try msec.addMergeSubsection(gpa);
3071 const msub = msec.mergeSubsection(msub_index);
33363072 msub.merge_section_index = msec_index;
33373073 msub.string_index = res.key.pos;
33383074 msub.alignment = .@"1";
......@@ -3350,7 +3086,7 @@ pub fn resolveMergeSections(self: *Elf) !void {
33503086 for (self.objects.items) |index| {
33513087 const file_ptr = self.file(index).?;
33523088 if (!file_ptr.isAlive()) continue;
3353 file_ptr.object.initMergeSections(self) catch |err| switch (err) {
3089 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {
33543090 error.MalformedObject => has_errors = true,
33553091 else => |e| return e,
33563092 };
......@@ -3358,6 +3094,12 @@ pub fn resolveMergeSections(self: *Elf) !void {
33583094
33593095 if (has_errors) return error.FlushFailure;
33603096
3097 for (self.objects.items) |index| {
3098 const file_ptr = self.file(index).?;
3099 if (!file_ptr.isAlive()) continue;
3100 try file_ptr.object.initOutputMergeSections(self);
3101 }
3102
33613103 for (self.objects.items) |index| {
33623104 const file_ptr = self.file(index).?;
33633105 if (!file_ptr.isAlive()) continue;
......@@ -3372,15 +3114,15 @@ pub fn resolveMergeSections(self: *Elf) !void {
33723114
33733115pub fn finalizeMergeSections(self: *Elf) !void {
33743116 for (self.merge_sections.items) |*msec| {
3375 try msec.finalize(self);
3117 try msec.finalize(self.base.comp.gpa);
33763118 }
33773119}
33783120
33793121pub fn updateMergeSectionSizes(self: *Elf) !void {
33803122 for (self.merge_sections.items) |*msec| {
33813123 const shdr = &self.shdrs.items[msec.output_section_index];
3382 for (msec.subsections.items) |msub_index| {
3383 const msub = self.mergeSubsection(msub_index);
3124 for (msec.finalized_subsections.items) |msub_index| {
3125 const msub = msec.mergeSubsection(msub_index);
33843126 assert(msub.alive);
33853127 const offset = msub.alignment.forward(shdr.sh_size);
33863128 const padding = offset - shdr.sh_size;
......@@ -3396,14 +3138,14 @@ pub fn writeMergeSections(self: *Elf) !void {
33963138 var buffer = std.ArrayList(u8).init(gpa);
33973139 defer buffer.deinit();
33983140
3399 for (self.merge_sections.items) |msec| {
3141 for (self.merge_sections.items) |*msec| {
34003142 const shdr = self.shdrs.items[msec.output_section_index];
34013143 const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
34023144 try buffer.ensureTotalCapacity(size);
34033145 buffer.appendNTimesAssumeCapacity(0, size);
34043146
3405 for (msec.subsections.items) |msub_index| {
3406 const msub = self.mergeSubsection(msub_index);
3147 for (msec.finalized_subsections.items) |msub_index| {
3148 const msub = msec.mergeSubsection(msub_index);
34073149 assert(msub.alive);
34083150 const string = msub.getString(self);
34093151 const off = math.cast(usize, msub.value) orelse return error.Overflow;
......@@ -3423,18 +3165,18 @@ fn initOutputSections(self: *Elf) !void {
34233165
34243166pub fn initMergeSections(self: *Elf) !void {
34253167 for (self.merge_sections.items) |*msec| {
3426 if (msec.subsections.items.len == 0) continue;
3168 if (msec.finalized_subsections.items.len == 0) continue;
34273169 const name = msec.name(self);
34283170 const shndx = self.sectionByName(name) orelse try self.addSection(.{
3429 .name = name,
3171 .name = msec.name_offset,
34303172 .type = msec.type,
34313173 .flags = msec.flags,
34323174 });
34333175 msec.output_section_index = shndx;
34343176
3435 var entsize = self.mergeSubsection(msec.subsections.items[0]).entsize;
3436 for (msec.subsections.items) |index| {
3437 const msub = self.mergeSubsection(index);
3177 var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize;
3178 for (msec.finalized_subsections.items) |msub_index| {
3179 const msub = msec.mergeSubsection(msub_index);
34383180 entsize = @min(entsize, msub.entsize);
34393181 }
34403182 const shdr = &self.shdrs.items[shndx];
......@@ -3452,7 +3194,7 @@ fn initSyntheticSections(self: *Elf) !void {
34523194 } else false;
34533195 if (needs_eh_frame) {
34543196 self.eh_frame_section_index = try self.addSection(.{
3455 .name = ".eh_frame",
3197 .name = try self.insertShString(".eh_frame"),
34563198 .type = elf.SHT_PROGBITS,
34573199 .flags = elf.SHF_ALLOC,
34583200 .addralign = ptr_size,
......@@ -3461,7 +3203,7 @@ fn initSyntheticSections(self: *Elf) !void {
34613203
34623204 if (comp.link_eh_frame_hdr) {
34633205 self.eh_frame_hdr_section_index = try self.addSection(.{
3464 .name = ".eh_frame_hdr",
3206 .name = try self.insertShString(".eh_frame_hdr"),
34653207 .type = elf.SHT_PROGBITS,
34663208 .flags = elf.SHF_ALLOC,
34673209 .addralign = 4,
......@@ -3472,7 +3214,7 @@ fn initSyntheticSections(self: *Elf) !void {
34723214
34733215 if (self.got.entries.items.len > 0) {
34743216 self.got_section_index = try self.addSection(.{
3475 .name = ".got",
3217 .name = try self.insertShString(".got"),
34763218 .type = elf.SHT_PROGBITS,
34773219 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
34783220 .addralign = ptr_size,
......@@ -3481,7 +3223,7 @@ fn initSyntheticSections(self: *Elf) !void {
34813223 }
34823224
34833225 self.got_plt_section_index = try self.addSection(.{
3484 .name = ".got.plt",
3226 .name = try self.insertShString(".got.plt"),
34853227 .type = elf.SHT_PROGBITS,
34863228 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
34873229 .addralign = @alignOf(u64),
......@@ -3501,7 +3243,7 @@ fn initSyntheticSections(self: *Elf) !void {
35013243 };
35023244 if (needs_rela_dyn) {
35033245 self.rela_dyn_section_index = try self.addSection(.{
3504 .name = ".rela.dyn",
3246 .name = try self.insertShString(".rela.dyn"),
35053247 .type = elf.SHT_RELA,
35063248 .flags = elf.SHF_ALLOC,
35073249 .addralign = @alignOf(elf.Elf64_Rela),
......@@ -3512,14 +3254,14 @@ fn initSyntheticSections(self: *Elf) !void {
35123254
35133255 if (self.plt.symbols.items.len > 0) {
35143256 self.plt_section_index = try self.addSection(.{
3515 .name = ".plt",
3257 .name = try self.insertShString(".plt"),
35163258 .type = elf.SHT_PROGBITS,
35173259 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
35183260 .addralign = 16,
35193261 .offset = std.math.maxInt(u64),
35203262 });
35213263 self.rela_plt_section_index = try self.addSection(.{
3522 .name = ".rela.plt",
3264 .name = try self.insertShString(".rela.plt"),
35233265 .type = elf.SHT_RELA,
35243266 .flags = elf.SHF_ALLOC,
35253267 .addralign = @alignOf(elf.Elf64_Rela),
......@@ -3530,7 +3272,7 @@ fn initSyntheticSections(self: *Elf) !void {
35303272
35313273 if (self.plt_got.symbols.items.len > 0) {
35323274 self.plt_got_section_index = try self.addSection(.{
3533 .name = ".plt.got",
3275 .name = try self.insertShString(".plt.got"),
35343276 .type = elf.SHT_PROGBITS,
35353277 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
35363278 .addralign = 16,
......@@ -3540,7 +3282,7 @@ fn initSyntheticSections(self: *Elf) !void {
35403282
35413283 if (self.copy_rel.symbols.items.len > 0) {
35423284 self.copy_rel_section_index = try self.addSection(.{
3543 .name = ".copyrel",
3285 .name = try self.insertShString(".copyrel"),
35443286 .type = elf.SHT_NOBITS,
35453287 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
35463288 .offset = std.math.maxInt(u64),
......@@ -3558,7 +3300,7 @@ fn initSyntheticSections(self: *Elf) !void {
35583300 };
35593301 if (needs_interp) {
35603302 self.interp_section_index = try self.addSection(.{
3561 .name = ".interp",
3303 .name = try self.insertShString(".interp"),
35623304 .type = elf.SHT_PROGBITS,
35633305 .flags = elf.SHF_ALLOC,
35643306 .addralign = 1,
......@@ -3568,7 +3310,7 @@ fn initSyntheticSections(self: *Elf) !void {
35683310
35693311 if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
35703312 self.dynstrtab_section_index = try self.addSection(.{
3571 .name = ".dynstr",
3313 .name = try self.insertShString(".dynstr"),
35723314 .flags = elf.SHF_ALLOC,
35733315 .type = elf.SHT_STRTAB,
35743316 .entsize = 1,
......@@ -3576,7 +3318,7 @@ fn initSyntheticSections(self: *Elf) !void {
35763318 .offset = std.math.maxInt(u64),
35773319 });
35783320 self.dynamic_section_index = try self.addSection(.{
3579 .name = ".dynamic",
3321 .name = try self.insertShString(".dynamic"),
35803322 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
35813323 .type = elf.SHT_DYNAMIC,
35823324 .entsize = @sizeOf(elf.Elf64_Dyn),
......@@ -3584,7 +3326,7 @@ fn initSyntheticSections(self: *Elf) !void {
35843326 .offset = std.math.maxInt(u64),
35853327 });
35863328 self.dynsymtab_section_index = try self.addSection(.{
3587 .name = ".dynsym",
3329 .name = try self.insertShString(".dynsym"),
35883330 .flags = elf.SHF_ALLOC,
35893331 .type = elf.SHT_DYNSYM,
35903332 .addralign = @alignOf(elf.Elf64_Sym),
......@@ -3593,7 +3335,7 @@ fn initSyntheticSections(self: *Elf) !void {
35933335 .offset = std.math.maxInt(u64),
35943336 });
35953337 self.hash_section_index = try self.addSection(.{
3596 .name = ".hash",
3338 .name = try self.insertShString(".hash"),
35973339 .flags = elf.SHF_ALLOC,
35983340 .type = elf.SHT_HASH,
35993341 .addralign = 4,
......@@ -3601,7 +3343,7 @@ fn initSyntheticSections(self: *Elf) !void {
36013343 .offset = std.math.maxInt(u64),
36023344 });
36033345 self.gnu_hash_section_index = try self.addSection(.{
3604 .name = ".gnu.hash",
3346 .name = try self.insertShString(".gnu.hash"),
36053347 .flags = elf.SHF_ALLOC,
36063348 .type = elf.SHT_GNU_HASH,
36073349 .addralign = 8,
......@@ -3614,7 +3356,7 @@ fn initSyntheticSections(self: *Elf) !void {
36143356 } else false;
36153357 if (needs_versions) {
36163358 self.versym_section_index = try self.addSection(.{
3617 .name = ".gnu.version",
3359 .name = try self.insertShString(".gnu.version"),
36183360 .flags = elf.SHF_ALLOC,
36193361 .type = elf.SHT_GNU_VERSYM,
36203362 .addralign = @alignOf(elf.Elf64_Versym),
......@@ -3622,7 +3364,7 @@ fn initSyntheticSections(self: *Elf) !void {
36223364 .offset = std.math.maxInt(u64),
36233365 });
36243366 self.verneed_section_index = try self.addSection(.{
3625 .name = ".gnu.version_r",
3367 .name = try self.insertShString(".gnu.version_r"),
36263368 .flags = elf.SHF_ALLOC,
36273369 .type = elf.SHT_GNU_VERNEED,
36283370 .addralign = @alignOf(elf.Elf64_Verneed),
......@@ -3642,7 +3384,7 @@ pub fn initSymtab(self: *Elf) !void {
36423384 };
36433385 if (self.symtab_section_index == null) {
36443386 self.symtab_section_index = try self.addSection(.{
3645 .name = ".symtab",
3387 .name = try self.insertShString(".symtab"),
36463388 .type = elf.SHT_SYMTAB,
36473389 .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),
36483390 .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),
......@@ -3651,7 +3393,7 @@ pub fn initSymtab(self: *Elf) !void {
36513393 }
36523394 if (self.strtab_section_index == null) {
36533395 self.strtab_section_index = try self.addSection(.{
3654 .name = ".strtab",
3396 .name = try self.insertShString(".strtab"),
36553397 .type = elf.SHT_STRTAB,
36563398 .entsize = 1,
36573399 .addralign = 1,
......@@ -3663,7 +3405,7 @@ pub fn initSymtab(self: *Elf) !void {
36633405pub fn initShStrtab(self: *Elf) !void {
36643406 if (self.shstrtab_section_index == null) {
36653407 self.shstrtab_section_index = try self.addSection(.{
3666 .name = ".shstrtab",
3408 .name = try self.insertShString(".shstrtab"),
36673409 .type = elf.SHT_STRTAB,
36683410 .entsize = 1,
36693411 .addralign = 1,
......@@ -3733,11 +3475,11 @@ fn sortInitFini(self: *Elf) !void {
37333475
37343476 const Entry = struct {
37353477 priority: i32,
3736 atom_index: Atom.Index,
3478 atom_ref: Ref,
37373479
37383480 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
37393481 if (lhs.priority == rhs.priority) {
3740 return ctx.atom(lhs.atom_index).?.priority(ctx) < ctx.atom(rhs.atom_index).?.priority(ctx);
3482 return ctx.atom(lhs.atom_ref).?.priority(ctx) < ctx.atom(rhs.atom_ref).?.priority(ctx);
37413483 }
37423484 return lhs.priority < rhs.priority;
37433485 }
......@@ -3768,8 +3510,8 @@ fn sortInitFini(self: *Elf) !void {
37683510 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
37693511 defer entries.deinit();
37703512
3771 for (atom_list.items) |atom_index| {
3772 const atom_ptr = self.atom(atom_index).?;
3513 for (atom_list.items) |ref| {
3514 const atom_ptr = self.atom(ref).?;
37733515 const object = atom_ptr.file(self).?.object;
37743516 const priority = blk: {
37753517 if (is_ctor_dtor) {
......@@ -3782,14 +3524,14 @@ fn sortInitFini(self: *Elf) !void {
37823524 const priority = std.fmt.parseUnsigned(u16, it.first(), 10) catch default;
37833525 break :blk priority;
37843526 };
3785 entries.appendAssumeCapacity(.{ .priority = priority, .atom_index = atom_index });
3527 entries.appendAssumeCapacity(.{ .priority = priority, .atom_ref = ref });
37863528 }
37873529
37883530 mem.sort(Entry, entries.items, self, Entry.lessThan);
37893531
37903532 atom_list.clearRetainingCapacity();
37913533 for (entries.items) |entry| {
3792 atom_list.appendAssumeCapacity(entry.atom_index);
3534 atom_list.appendAssumeCapacity(entry.atom_ref);
37933535 }
37943536 }
37953537}
......@@ -4155,26 +3897,11 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
41553897 }
41563898 }
41573899
4158 if (self.zigObjectPtr()) |zig_object| {
4159 for (zig_object.atoms.items) |atom_index| {
4160 const atom_ptr = self.atom(atom_index) orelse continue;
3900 if (self.zigObjectPtr()) |zo| {
3901 for (zo.atoms_indexes.items) |atom_index| {
3902 const atom_ptr = zo.atom(atom_index) orelse continue;
41613903 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
41623904 }
4163
4164 for (zig_object.locals()) |local_index| {
4165 const local = self.symbol(local_index);
4166 local.output_section_index = backlinks[local.output_section_index];
4167 }
4168
4169 for (zig_object.globals()) |global_index| {
4170 const global = self.symbol(global_index);
4171 const atom_ptr = global.atom(self) orelse continue;
4172 if (!atom_ptr.flags.alive) continue;
4173 // TODO claim unresolved for objects
4174 if (global.file(self).?.index() != zig_object.index) continue;
4175 const out_shndx = global.outputShndx() orelse continue;
4176 global.output_section_index = backlinks[out_shndx];
4177 }
41783905 }
41793906
41803907 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {
......@@ -4194,9 +3921,9 @@ fn updateSectionSizes(self: *Elf) !void {
41943921 const shdr = &self.shdrs.items[shndx];
41953922 if (atom_list.items.len == 0) continue;
41963923 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
4197 for (atom_list.items) |atom_index| {
4198 const atom_ptr = self.atom(atom_index) orelse continue;
4199 if (!atom_ptr.flags.alive) continue;
3924 for (atom_list.items) |ref| {
3925 const atom_ptr = self.atom(ref) orelse continue;
3926 if (!atom_ptr.alive) continue;
42003927 const offset = atom_ptr.alignment.forward(shdr.sh_size);
42013928 const padding = offset - shdr.sh_size;
42023929 atom_ptr.value = @intCast(offset);
......@@ -4630,7 +4357,7 @@ fn allocateSpecialPhdrs(self: *Elf) void {
46304357fn writeAtoms(self: *Elf) !void {
46314358 const gpa = self.base.comp.gpa;
46324359
4633 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
4360 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
46344361 defer {
46354362 var it = undefs.iterator();
46364363 while (it.next()) |entry| {
......@@ -4678,21 +4405,21 @@ fn writeAtoms(self: *Elf) !void {
46784405 0;
46794406 @memset(buffer, padding_byte);
46804407
4681 for (atom_list.items) |atom_index| {
4682 const atom_ptr = self.atom(atom_index).?;
4683 assert(atom_ptr.flags.alive);
4408 for (atom_list.items) |ref| {
4409 const atom_ptr = self.atom(ref).?;
4410 assert(atom_ptr.alive);
46844411
46854412 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
46864413 return error.Overflow;
46874414 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
46884415
4689 log.debug("writing atom({d}) at 0x{x}", .{ atom_index, sh_offset + offset });
4416 log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset });
46904417
46914418 // TODO decompress directly into provided buffer
46924419 const out_code = buffer[offset..][0..size];
46934420 const in_code = switch (atom_ptr.file(self).?) {
4694 .object => |x| try x.codeDecompressAlloc(self, atom_index),
4695 .zig_object => |x| try x.codeAlloc(self, atom_index),
4421 .object => |x| try x.codeDecompressAlloc(self, ref.index),
4422 .zig_object => |x| try x.codeAlloc(self, ref.index),
46964423 else => unreachable,
46974424 };
46984425 defer gpa.free(in_code);
......@@ -5015,9 +4742,8 @@ pub fn writeSymtab(self: *Elf) !void {
50154742 file_ptr.writeSymtab(self);
50164743 }
50174744
5018 if (self.linker_defined_index) |index| {
5019 const file_ptr = self.file(index).?;
5020 file_ptr.writeSymtab(self);
4745 if (self.linkerDefinedPtr()) |obj| {
4746 obj.asFile().writeSymtab(self);
50214747 }
50224748
50234749 if (self.zig_got_section_index) |_| {
......@@ -5479,7 +5205,7 @@ fn addPhdr(self: *Elf, opts: struct {
54795205 return index;
54805206}
54815207
5482pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u32) !u32 {
5208pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 {
54835209 const entsize: u64 = switch (self.ptr_width) {
54845210 .p32 => @sizeOf(elf.Elf32_Rela),
54855211 .p64 => @sizeOf(elf.Elf64_Rela),
......@@ -5500,7 +5226,7 @@ pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u32) !u32 {
55005226}
55015227
55025228pub const AddSectionOpts = struct {
5503 name: [:0]const u8,
5229 name: u32 = 0,
55045230 type: u32 = elf.SHT_NULL,
55055231 flags: u64 = 0,
55065232 link: u32 = 0,
......@@ -5515,7 +5241,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
55155241 const index = @as(u32, @intCast(self.shdrs.items.len));
55165242 const shdr = try self.shdrs.addOne(gpa);
55175243 shdr.* = .{
5518 .sh_name = try self.insertShString(opts.name),
5244 .sh_name = opts.name,
55195245 .sh_type = opts.type,
55205246 .sh_flags = opts.flags,
55215247 .sh_addr = 0,
......@@ -5580,7 +5306,7 @@ fn sortRelaDyn(self: *Elf) void {
55805306 mem.sort(elf.Elf64_Rela, self.rela_dyn.items, self, Sort.lessThan);
55815307}
55825308
5583fn calcNumIRelativeRelocs(self: *Elf) usize {
5309pub fn calcNumIRelativeRelocs(self: *Elf) usize {
55845310 var count: usize = self.num_ifunc_dynrelocs;
55855311
55865312 for (self.got.entries.items) |entry| {
......@@ -5602,7 +5328,7 @@ pub fn isCIdentifier(name: []const u8) bool {
56025328 return true;
56035329}
56045330
5605fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
5331pub fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
56065332 const name = self.getShString(shdr.sh_name);
56075333 if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
56085334 if (isCIdentifier(name)) return name;
......@@ -5610,64 +5336,6 @@ fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
56105336 return null;
56115337}
56125338
5613pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
5614 if (atom_index == 0) return null;
5615 assert(atom_index < self.atoms.items.len);
5616 return &self.atoms.items[atom_index];
5617}
5618
5619pub fn addAtom(self: *Elf) !Atom.Index {
5620 const gpa = self.base.comp.gpa;
5621 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
5622 const atom_ptr = try self.atoms.addOne(gpa);
5623 atom_ptr.* = .{ .atom_index = index };
5624 return index;
5625}
5626
5627pub fn addAtomExtra(self: *Elf, extra: Atom.Extra) !u32 {
5628 const fields = @typeInfo(Atom.Extra).Struct.fields;
5629 try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len);
5630 return self.addAtomExtraAssumeCapacity(extra);
5631}
5632
5633pub fn addAtomExtraAssumeCapacity(self: *Elf, extra: Atom.Extra) u32 {
5634 const index = @as(u32, @intCast(self.atoms_extra.items.len));
5635 const fields = @typeInfo(Atom.Extra).Struct.fields;
5636 inline for (fields) |field| {
5637 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
5638 u32 => @field(extra, field.name),
5639 else => @compileError("bad field type"),
5640 });
5641 }
5642 return index;
5643}
5644
5645pub fn atomExtra(self: *Elf, index: u32) ?Atom.Extra {
5646 if (index == 0) return null;
5647 const fields = @typeInfo(Atom.Extra).Struct.fields;
5648 var i: usize = index;
5649 var result: Atom.Extra = undefined;
5650 inline for (fields) |field| {
5651 @field(result, field.name) = switch (field.type) {
5652 u32 => self.atoms_extra.items[i],
5653 else => @compileError("bad field type"),
5654 };
5655 i += 1;
5656 }
5657 return result;
5658}
5659
5660pub fn setAtomExtra(self: *Elf, index: u32, extra: Atom.Extra) void {
5661 assert(index > 0);
5662 const fields = @typeInfo(Atom.Extra).Struct.fields;
5663 inline for (fields, 0..) |field, i| {
5664 self.atoms_extra.items[index + i] = switch (field.type) {
5665 u32 => @field(extra, field.name),
5666 else => @compileError("bad field type"),
5667 };
5668 }
5669}
5670
56715339pub fn addThunk(self: *Elf) !Thunk.Index {
56725340 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
56735341 const th = try self.thunks.addOne(self.base.comp.gpa);
......@@ -5704,6 +5372,15 @@ pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
57045372 return self.file_handles.items[index];
57055373}
57065374
5375pub fn atom(self: *Elf, ref: Ref) ?*Atom {
5376 const file_ptr = self.file(ref.file) orelse return null;
5377 return file_ptr.atom(ref.index);
5378}
5379
5380pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {
5381 return self.file(ref.file).?.comdatGroup(ref.index);
5382}
5383
57075384/// Returns pointer-to-symbol described at sym_index.
57085385pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
57095386 return &self.symbols.items[sym_index];
......@@ -5795,11 +5472,6 @@ pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
57955472 };
57965473}
57975474
5798pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
5799 const name_off = self.strings.getOffset(name) orelse return null;
5800 return self.resolver.get(name_off);
5801}
5802
58035475pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
58045476 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
58055477}
......@@ -5809,69 +5481,12 @@ pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
58095481 return self.file(index).?.zig_object;
58105482}
58115483
5812const GetOrCreateComdatGroupOwnerResult = struct {
5813 found_existing: bool,
5814 index: ComdatGroupOwner.Index,
5815};
5816
5817pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
5818 const gpa = self.base.comp.gpa;
5819 const off = try self.strings.insert(gpa, name);
5820 const gop = try self.comdat_groups_table.getOrPut(gpa, off);
5821 if (!gop.found_existing) {
5822 const index: ComdatGroupOwner.Index = @intCast(self.comdat_groups_owners.items.len);
5823 const owner = try self.comdat_groups_owners.addOne(gpa);
5824 owner.* = .{};
5825 gop.value_ptr.* = index;
5826 }
5827 return .{
5828 .found_existing = gop.found_existing,
5829 .index = gop.value_ptr.*,
5830 };
5831}
5832
5833pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index {
5834 const gpa = self.base.comp.gpa;
5835 const index = @as(ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
5836 _ = try self.comdat_groups.addOne(gpa);
5837 return index;
5838}
5839
5840pub fn comdatGroup(self: *Elf, index: ComdatGroup.Index) *ComdatGroup {
5841 assert(index < self.comdat_groups.items.len);
5842 return &self.comdat_groups.items[index];
5843}
5844
5845pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupOwner {
5846 assert(index < self.comdat_groups_owners.items.len);
5847 return &self.comdat_groups_owners.items[index];
5484pub fn linkerDefinedPtr(self: *Elf) ?*LinkerDefined {
5485 const index = self.linker_defined_index orelse return null;
5486 return self.file(index).?.linker_defined;
58485487}
58495488
5850pub fn addInputMergeSection(self: *Elf) !InputMergeSection.Index {
5851 const index: InputMergeSection.Index = @intCast(self.merge_input_sections.items.len);
5852 const msec = try self.merge_input_sections.addOne(self.base.comp.gpa);
5853 msec.* = .{};
5854 return index;
5855}
5856
5857pub fn inputMergeSection(self: *Elf, index: InputMergeSection.Index) ?*InputMergeSection {
5858 if (index == 0) return null;
5859 return &self.merge_input_sections.items[index];
5860}
5861
5862pub fn addMergeSubsection(self: *Elf) !MergeSubsection.Index {
5863 const index: MergeSubsection.Index = @intCast(self.merge_subsections.items.len);
5864 const msec = try self.merge_subsections.addOne(self.base.comp.gpa);
5865 msec.* = .{};
5866 return index;
5867}
5868
5869pub fn mergeSubsection(self: *Elf, index: MergeSubsection.Index) *MergeSubsection {
5870 assert(index < self.merge_subsections.items.len);
5871 return &self.merge_subsections.items[index];
5872}
5873
5874pub fn getOrCreateMergeSection(self: *Elf, name: []const u8, flags: u64, @"type": u32) !MergeSection.Index {
5489pub fn getOrCreateMergeSection(self: *Elf, name: [:0]const u8, flags: u64, @"type": u32) !MergeSection.Index {
58755490 const gpa = self.base.comp.gpa;
58765491 const out_name = name: {
58775492 if (self.base.isRelocatable()) break :name name;
......@@ -5879,11 +5494,11 @@ pub fn getOrCreateMergeSection(self: *Elf, name: []const u8, flags: u64, @"type"
58795494 break :name if (flags & elf.SHF_STRINGS != 0) ".rodata.str" else ".rodata.cst";
58805495 break :name name;
58815496 };
5882 const out_off = try self.strings.insert(gpa, out_name);
5883 const out_flags = flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP);
58845497 for (self.merge_sections.items, 0..) |msec, index| {
5885 if (msec.name_offset == out_off) return @intCast(index);
5498 if (mem.eql(u8, msec.name(self), out_name)) return @intCast(index);
58865499 }
5500 const out_off = try self.insertShString(out_name);
5501 const out_flags = flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP);
58875502 const index = @as(MergeSection.Index, @intCast(self.merge_sections.items.len));
58885503 const msec = try self.merge_sections.addOne(gpa);
58895504 msec.* = .{
......@@ -5974,9 +5589,9 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
59745589 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
59755590 try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
59765591
5977 for (atoms[0..natoms]) |atom_index| {
5978 const atom_ptr = self.atom(atom_index).?;
5979 const file_ptr = self.file(atom_ptr.file_index).?;
5592 for (atoms[0..natoms]) |ref| {
5593 const atom_ptr = self.atom(ref).?;
5594 const file_ptr = self.file(ref.file).?;
59805595 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
59815596 }
59825597
......@@ -6253,7 +5868,7 @@ fn fmtDumpState(
62535868
62545869 try writer.writeAll("Output COMDAT groups\n");
62555870 for (self.comdat_group_sections.items) |cg| {
6256 try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index });
5871 try writer.print(" shdr({d}) : COMDAT({})\n", .{ cg.shndx, cg.cg_ref });
62575872 }
62585873
62595874 try writer.writeAll("\nOutput merge sections\n");
......@@ -6340,21 +5955,24 @@ const default_entry_addr = 0x8000000;
63405955
63415956pub const base_tag: link.File.Tag = .elf;
63425957
6343const ComdatGroupOwner = struct {
6344 file: File.Index = 0,
6345
6346 const Index = u32;
6347};
6348
63495958pub const ComdatGroup = struct {
6350 owner: ComdatGroupOwner.Index,
6351 file: File.Index,
5959 signature_off: u32,
5960 file_index: File.Index,
63525961 shndx: u32,
63535962 members_start: u32,
63545963 members_len: u32,
5964 alive: bool = true,
5965
5966 pub fn file(cg: ComdatGroup, elf_file: *Elf) File {
5967 return elf_file.file(cg.file_index).?;
5968 }
5969
5970 pub fn signature(cg: ComdatGroup, elf_file: *Elf) [:0]const u8 {
5971 return cg.file(elf_file).object.getString(cg.signature_off);
5972 }
63555973
63565974 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {
6357 const object = elf_file.file(cg.file).?.object;
5975 const object = cg.file(elf_file).object;
63585976 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];
63595977 }
63605978
......@@ -6396,6 +6014,22 @@ pub const SystemLib = struct {
63966014 path: []const u8,
63976015};
63986016
6017pub const Ref = struct {
6018 index: u32,
6019 file: u32,
6020
6021 pub fn format(
6022 ref: Ref,
6023 comptime unused_fmt_string: []const u8,
6024 options: std.fmt.FormatOptions,
6025 writer: anytype,
6026 ) !void {
6027 _ = unused_fmt_string;
6028 _ = options;
6029 try writer.print("ref({},{})", .{ ref.index, ref.file });
6030 }
6031};
6032
63996033const LastAtomAndFreeList = struct {
64006034 /// Index of the last allocated atom in this section.
64016035 last_atom_index: Atom.Index = 0,
......@@ -6421,7 +6055,7 @@ const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndF
64216055
64226056const RelaSection = struct {
64236057 shndx: u32,
6424 atom_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6058 atom_list: std.ArrayListUnmanaged(Ref) = .{},
64256059};
64266060const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
64276061
src/link/Elf/Atom.zig+54-68
......@@ -30,14 +30,17 @@ atom_index: Index = 0,
3030prev_index: Index = 0,
3131next_index: Index = 0,
3232
33/// Flags we use for state tracking.
34flags: Flags = .{},
33/// Specifies whether this atom is alive or has been garbage collected.
34alive: bool = true,
35
36/// Specifies if the atom has been visited during garbage collection.
37visited: bool = false,
3538
3639extra_index: u32 = 0,
3740
3841pub const Alignment = @import("../../InternPool.zig").Alignment;
3942
40pub fn name(self: Atom, elf_file: *Elf) []const u8 {
43pub fn name(self: Atom, elf_file: *Elf) [:0]const u8 {
4144 const file_ptr = self.file(elf_file).?;
4245 return switch (file_ptr) {
4346 inline else => |x| x.getString(self.name_offset),
......@@ -45,8 +48,7 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
4548}
4649
4750pub fn address(self: Atom, elf_file: *Elf) i64 {
48 const shndx = self.outputShndx() orelse return self.value;
49 const shdr = elf_file.shdrs.items[shndx];
51 const shdr = elf_file.shdrs.items[self.output_section_index];
5052 return @as(i64, @intCast(shdr.sh_addr)) + self.value;
5153}
5254
......@@ -55,7 +57,7 @@ pub fn debugTombstoneValue(self: Atom, target: Symbol, elf_file: *Elf) ?u64 {
5557 if (msub.alive) return null;
5658 }
5759 if (target.atom(elf_file)) |atom_ptr| {
58 if (atom_ptr.flags.alive) return null;
60 if (atom_ptr.alive) return null;
5961 }
6062 const atom_name = self.name(elf_file);
6163 if (!mem.startsWith(u8, atom_name, ".debug")) return null;
......@@ -67,8 +69,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
6769}
6870
6971pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {
70 assert(self.flags.thunk);
71 const extras = self.extra(elf_file).?;
72 const extras = self.extra(elf_file);
7273 return elf_file.thunk(extras.thunk);
7374}
7475
......@@ -85,11 +86,6 @@ pub fn relocsShndx(self: Atom) ?u32 {
8586 return self.relocs_section_index;
8687}
8788
88pub fn outputShndx(self: Atom) ?u32 {
89 if (self.output_section_index == 0) return null;
90 return self.output_section_index;
91}
92
9389pub fn priority(self: Atom, elf_file: *Elf) u64 {
9490 const index = self.file(elf_file).?.index();
9591 return (@as(u64, @intCast(index)) << 32) | @as(u64, @intCast(self.input_section_index));
......@@ -99,7 +95,8 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
9995/// File offset relocation happens transparently, so it is not included in
10096/// this calculation.
10197pub fn capacity(self: Atom, elf_file: *Elf) u64 {
102 const next_addr = if (elf_file.atom(self.next_index)) |next|
98 const zo = elf_file.zigObjectPtr().?;
99 const next_addr = if (zo.atom(self.next_index)) |next|
103100 next.address(elf_file)
104101 else
105102 std.math.maxInt(u32);
......@@ -107,8 +104,9 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
107104}
108105
109106pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
107 const zo = elf_file.zigObjectPtr().?;
110108 // No need to keep a free list node for the last block.
111 const next = elf_file.atom(self.next_index) orelse return false;
109 const next = zo.atom(self.next_index) orelse return false;
112110 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
113111 const ideal_cap = Elf.padToIdeal(self.size);
114112 if (cap <= ideal_cap) return false;
......@@ -117,8 +115,9 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
117115}
118116
119117pub fn allocate(self: *Atom, elf_file: *Elf) !void {
120 const shdr = &elf_file.shdrs.items[self.outputShndx().?];
121 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;
118 const zo = elf_file.zigObjectPtr().?;
119 const shdr = &elf_file.shdrs.items[self.output_section_index];
120 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;
122121 const free_list = &meta.free_list;
123122 const last_atom_index = &meta.last_atom_index;
124123 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
......@@ -137,7 +136,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
137136 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
138137 while (i < free_list.items.len) {
139138 const big_atom_index = free_list.items[i];
140 const big_atom = elf_file.atom(big_atom_index).?;
139 const big_atom = zo.atom(big_atom_index).?;
141140 // We now have a pointer to a live atom that has too much capacity.
142141 // Is it enough that we could fit this new atom?
143142 const cap = big_atom.capacity(elf_file);
......@@ -169,7 +168,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
169168 free_list_removal = i;
170169 }
171170 break :blk @intCast(new_start_vaddr);
172 } else if (elf_file.atom(last_atom_index.*)) |last| {
171 } else if (zo.atom(last_atom_index.*)) |last| {
173172 const ideal_capacity = Elf.padToIdeal(last.size);
174173 const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;
175174 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
......@@ -189,12 +188,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
189188 });
190189
191190 const expand_section = if (atom_placement) |placement_index|
192 elf_file.atom(placement_index).?.next_index == 0
191 zo.atom(placement_index).?.next_index == 0
193192 else
194193 true;
195194 if (expand_section) {
196195 const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size)));
197 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
196 try elf_file.growAllocSection(self.output_section_index, needed_size);
198197 last_atom_index.* = self.atom_index;
199198
200199 const zig_object = elf_file.zigObjectPtr().?;
......@@ -214,15 +213,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
214213 // This function can also reallocate an atom.
215214 // In this case we need to "unplug" it from its previous location before
216215 // plugging it in to its new location.
217 if (elf_file.atom(self.prev_index)) |prev| {
216 if (zo.atom(self.prev_index)) |prev| {
218217 prev.next_index = self.next_index;
219218 }
220 if (elf_file.atom(self.next_index)) |next| {
219 if (zo.atom(self.next_index)) |next| {
221220 next.prev_index = self.prev_index;
222221 }
223222
224223 if (atom_placement) |big_atom_index| {
225 const big_atom = elf_file.atom(big_atom_index).?;
224 const big_atom = zo.atom(big_atom_index).?;
226225 self.prev_index = big_atom_index;
227226 self.next_index = big_atom.next_index;
228227 big_atom.next_index = self.atom_index;
......@@ -234,7 +233,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
234233 _ = free_list.swapRemove(i);
235234 }
236235
237 self.flags.alive = true;
236 self.alive = true;
238237}
239238
240239pub fn shrink(self: *Atom, elf_file: *Elf) void {
......@@ -250,9 +249,10 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {
250249pub fn free(self: *Atom, elf_file: *Elf) void {
251250 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
252251
252 const zo = elf_file.zigObjectPtr().?;
253253 const comp = elf_file.base.comp;
254254 const gpa = comp.gpa;
255 const shndx = self.outputShndx().?;
255 const shndx = self.output_section_index;
256256 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
257257 const free_list = &meta.free_list;
258258 const last_atom_index = &meta.last_atom_index;
......@@ -272,9 +272,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
272272 }
273273 }
274274
275 if (elf_file.atom(last_atom_index.*)) |last_atom| {
275 if (zo.atom(last_atom_index.*)) |last_atom| {
276276 if (last_atom.atom_index == self.atom_index) {
277 if (elf_file.atom(self.prev_index)) |_| {
277 if (zo.atom(self.prev_index)) |_| {
278278 // TODO shrink the section size here
279279 last_atom_index.* = self.prev_index;
280280 } else {
......@@ -283,7 +283,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
283283 }
284284 }
285285
286 if (elf_file.atom(self.prev_index)) |prev| {
286 if (zo.atom(self.prev_index)) |prev| {
287287 prev.next_index = self.next_index;
288288 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
289289 // The free list is heuristics, it doesn't have to be perfect, so we can
......@@ -294,7 +294,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
294294 self.prev_index = 0;
295295 }
296296
297 if (elf_file.atom(self.next_index)) |next| {
297 if (zo.atom(self.next_index)) |next| {
298298 next.prev_index = self.prev_index;
299299 } else {
300300 self.next_index = 0;
......@@ -313,7 +313,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
313313 switch (self.file(elf_file).?) {
314314 .zig_object => |x| return x.relocs.items[shndx].items,
315315 .object => |x| {
316 const extras = self.extra(elf_file).?;
316 const extras = self.extra(elf_file);
317317 return x.relocs.items[extras.rel_index..][0..extras.rel_count];
318318 },
319319 else => unreachable,
......@@ -337,12 +337,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
337337 var r_addend = rel.r_addend;
338338 var r_sym: u32 = 0;
339339 switch (target.type(elf_file)) {
340 elf.STT_SECTION => if (target.mergeSubsection(elf_file)) |msub| {
341 r_addend += @intCast(target.address(.{}, elf_file));
342 r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);
343 } else {
340 elf.STT_SECTION => {
344341 r_addend += @intCast(target.address(.{}, elf_file));
345 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
342 r_sym = if (target.outputShndx(elf_file)) |osec|
343 elf_file.sectionSymbolOutputSymtabIndex(osec)
344 else
345 0;
346346 },
347347 else => {
348348 r_sym = target.outputSymtabIndex(elf_file) orelse 0;
......@@ -366,10 +366,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
366366}
367367
368368pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
369 if (!self.flags.fde) return &[0]Fde{};
370 const extras = self.extra(elf_file).?;
371 const object = self.file(elf_file).?.object;
372 return object.fdes.items[extras.fde_start..][0..extras.fde_count];
369 const extras = self.extra(elf_file);
370 return switch (self.file(elf_file).?) {
371 .shared_object => unreachable,
372 .linker_defined, .zig_object => &[0]Fde{},
373 .object => |x| x.fdes.items[extras.fde_start..][0..extras.fde_count],
374 };
373375}
374376
375377pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
......@@ -712,9 +714,9 @@ fn reportUndefined(
712714 {
713715 const gop = try undefs.getOrPut(sym_index);
714716 if (!gop.found_existing) {
715 gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);
717 gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
716718 }
717 try gop.value_ptr.append(self.atom_index);
719 try gop.value_ptr.append(.{ .index = self.atom_index, .file = self.file_index });
718720 return true;
719721 }
720722
......@@ -1001,25 +1003,23 @@ const AddExtraOpts = struct {
10011003 rel_count: ?u32 = null,
10021004};
10031005
1004pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void {
1005 if (atom.extra(elf_file) == null) {
1006 atom.extra_index = try elf_file.addAtomExtra(.{});
1007 }
1008 var extras = atom.extra(elf_file).?;
1006pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) void {
1007 const file_ptr = atom.file(elf_file).?;
1008 var extras = file_ptr.atomExtra(atom.extra_index);
10091009 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
10101010 if (@field(opts, field.name)) |x| {
10111011 @field(extras, field.name) = x;
10121012 }
10131013 }
1014 atom.setExtra(extras, elf_file);
1014 file_ptr.setAtomExtra(atom.extra_index, extras);
10151015}
10161016
1017pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {
1018 return elf_file.atomExtra(atom.extra_index);
1017pub inline fn extra(atom: Atom, elf_file: *Elf) Extra {
1018 return atom.file(elf_file).?.atomExtra(atom.extra_index);
10191019}
10201020
10211021pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
1022 elf_file.setAtomExtra(atom.extra_index, extras);
1022 atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras);
10231023}
10241024
10251025pub fn format(
......@@ -1061,9 +1061,9 @@ fn format2(
10611061 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
10621062 atom.output_section_index, atom.alignment, atom.size,
10631063 });
1064 if (atom.flags.fde) {
1064 if (atom.fdes(elf_file).len > 0) {
10651065 try writer.writeAll(" : fdes{ ");
1066 const extras = atom.extra(elf_file).?;
1066 const extras = atom.extra(elf_file);
10671067 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
10681068 try writer.print("{d}", .{i});
10691069 if (!fde.alive) try writer.writeAll("([*])");
......@@ -1071,27 +1071,13 @@ fn format2(
10711071 }
10721072 try writer.writeAll(" }");
10731073 }
1074 if (!atom.flags.alive) {
1074 if (!atom.alive) {
10751075 try writer.writeAll(" : [*]");
10761076 }
10771077}
10781078
10791079pub const Index = u32;
10801080
1081pub const Flags = packed struct {
1082 /// Specifies whether this atom is alive or has been garbage collected.
1083 alive: bool = true,
1084
1085 /// Specifies if the atom has been visited during garbage collection.
1086 visited: bool = false,
1087
1088 /// Whether this atom has a range extension thunk.
1089 thunk: bool = false,
1090
1091 /// Whether this atom has FDE records.
1092 fde: bool = false,
1093};
1094
10951081const x86_64 = struct {
10961082 fn scanReloc(
10971083 atom: Atom,
src/link/Elf/LinkerDefined.zig+223-2
......@@ -1,17 +1,89 @@
11index: File.Index,
2
23symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
34strtab: std.ArrayListUnmanaged(u8) = .{},
45symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
56
7entry_index: ?Symbol.Index = null,
8dynamic_index: ?Symbol.Index = null,
9ehdr_start_index: ?Symbol.Index = null,
10init_array_start_index: ?Symbol.Index = null,
11init_array_end_index: ?Symbol.Index = null,
12fini_array_start_index: ?Symbol.Index = null,
13fini_array_end_index: ?Symbol.Index = null,
14preinit_array_start_index: ?Symbol.Index = null,
15preinit_array_end_index: ?Symbol.Index = null,
16got_index: ?Symbol.Index = null,
17plt_index: ?Symbol.Index = null,
18end_index: ?Symbol.Index = null,
19gnu_eh_frame_hdr_index: ?Symbol.Index = null,
20dso_handle_index: ?Symbol.Index = null,
21rela_iplt_start_index: ?Symbol.Index = null,
22rela_iplt_end_index: ?Symbol.Index = null,
23global_pointer_index: ?Symbol.Index = null,
24start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
25
626output_symtab_ctx: Elf.SymtabCtx = .{},
727
828pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
929 self.symtab.deinit(allocator);
1030 self.strtab.deinit(allocator);
1131 self.symbols.deinit(allocator);
32 self.start_stop_indexes.deinit(allocator);
33}
34
35pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
36 // Null byte in strtab
37 try self.strtab.append(allocator, 0);
1238}
1339
14pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32 {
40pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
41 const gpa = elf_file.base.comp.gpa;
42
43 if (elf_file.entry_name) |name| {
44 self.entry_index = try self.addGlobal(name, elf_file);
45 }
46
47 self.dynamic_index = try self.addGlobal("_DYNAMIC", elf_file);
48 self.ehdr_start_index = try self.addGlobal("__ehdr_start", elf_file);
49 self.init_array_start_index = try self.addGlobal("__init_array_start", elf_file);
50 self.init_array_end_index = try self.addGlobal("__init_array_end", elf_file);
51 self.fini_array_start_index = try self.addGlobal("__fini_array_start", elf_file);
52 self.fini_array_end_index = try self.addGlobal("__fini_array_end", elf_file);
53 self.preinit_array_start_index = try self.addGlobal("__preinit_array_start", elf_file);
54 self.preinit_array_end_index = try self.addGlobal("__preinit_array_end", elf_file);
55 self.got_index = try self.addGlobal("_GLOBAL_OFFSET_TABLE_", elf_file);
56 self.plt_index = try self.addGlobal("_PROCEDURE_LINKAGE_TABLE_", elf_file);
57 self.end_index = try self.addGlobal("_end", elf_file);
58
59 if (elf_file.base.comp.link_eh_frame_hdr) {
60 self.gnu_eh_frame_hdr_index = try self.addGlobal("__GNU_EH_FRAME_HDR", elf_file);
61 }
62
63 self.dso_handle_index = try self.addGlobal("__dso_handle", elf_file);
64 self.rela_iplt_start_index = try self.addGlobal("__rela_iplt_start", elf_file);
65 self.rela_iplt_end_index = try self.addGlobal("__rela_iplt_end", elf_file);
66
67 for (elf_file.shdrs.items) |shdr| {
68 if (elf_file.getStartStopBasename(shdr)) |name| {
69 try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
70
71 const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
72 defer gpa.free(start);
73 const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
74 defer gpa.free(stop);
75
76 self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(start, elf_file));
77 self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(stop, elf_file));
78 }
79 }
80
81 if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
82 self.global_pointer_index = try self.addGlobal("__global_pointer$", elf_file);
83 }
84}
85
86fn addGlobal(self: *LinkerDefined, name: []const u8, elf_file: *Elf) !u32 {
1587 const comp = elf_file.base.comp;
1688 const gpa = comp.gpa;
1789 try self.symtab.ensureUnusedCapacity(gpa, 1);
......@@ -41,7 +113,7 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
41113 const global = elf_file.symbol(index);
42114 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
43115 global.value = 0;
44 global.atom_index = 0;
116 global.ref = .{ .index = 0, .file = 0 };
45117 global.file_index = self.index;
46118 global.esym_index = sym_idx;
47119 global.version_index = elf_file.default_sym_version;
......@@ -49,6 +121,154 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
49121 }
50122}
51123
124pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
125 const comp = elf_file.base.comp;
126 const link_mode = comp.config.link_mode;
127
128 // _DYNAMIC
129 if (elf_file.dynamic_section_index) |shndx| {
130 const shdr = &elf_file.shdrs.items[shndx];
131 const symbol_ptr = elf_file.symbol(self.dynamic_index.?);
132 symbol_ptr.value = @intCast(shdr.sh_addr);
133 symbol_ptr.output_section_index = shndx;
134 }
135
136 // __ehdr_start
137 {
138 const symbol_ptr = elf_file.symbol(self.ehdr_start_index.?);
139 symbol_ptr.value = @intCast(elf_file.image_base);
140 symbol_ptr.output_section_index = 1;
141 }
142
143 // __init_array_start, __init_array_end
144 if (elf_file.sectionByName(".init_array")) |shndx| {
145 const start_sym = elf_file.symbol(self.init_array_start_index.?);
146 const end_sym = elf_file.symbol(self.init_array_end_index.?);
147 const shdr = &elf_file.shdrs.items[shndx];
148 start_sym.output_section_index = shndx;
149 start_sym.value = @intCast(shdr.sh_addr);
150 end_sym.output_section_index = shndx;
151 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
152 }
153
154 // __fini_array_start, __fini_array_end
155 if (elf_file.sectionByName(".fini_array")) |shndx| {
156 const start_sym = elf_file.symbol(self.fini_array_start_index.?);
157 const end_sym = elf_file.symbol(self.fini_array_end_index.?);
158 const shdr = &elf_file.shdrs.items[shndx];
159 start_sym.output_section_index = shndx;
160 start_sym.value = @intCast(shdr.sh_addr);
161 end_sym.output_section_index = shndx;
162 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
163 }
164
165 // __preinit_array_start, __preinit_array_end
166 if (elf_file.sectionByName(".preinit_array")) |shndx| {
167 const start_sym = elf_file.symbol(self.preinit_array_start_index.?);
168 const end_sym = elf_file.symbol(self.preinit_array_end_index.?);
169 const shdr = &elf_file.shdrs.items[shndx];
170 start_sym.output_section_index = shndx;
171 start_sym.value = @intCast(shdr.sh_addr);
172 end_sym.output_section_index = shndx;
173 end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
174 }
175
176 // _GLOBAL_OFFSET_TABLE_
177 if (elf_file.getTarget().cpu.arch == .x86_64) {
178 if (elf_file.got_plt_section_index) |shndx| {
179 const shdr = elf_file.shdrs.items[shndx];
180 const sym = elf_file.symbol(self.got_index.?);
181 sym.value = @intCast(shdr.sh_addr);
182 sym.output_section_index = shndx;
183 }
184 } else {
185 if (elf_file.got_section_index) |shndx| {
186 const shdr = elf_file.shdrs.items[shndx];
187 const sym = elf_file.symbol(self.got_index.?);
188 sym.value = @intCast(shdr.sh_addr);
189 sym.output_section_index = shndx;
190 }
191 }
192
193 // _PROCEDURE_LINKAGE_TABLE_
194 if (elf_file.plt_section_index) |shndx| {
195 const shdr = &elf_file.shdrs.items[shndx];
196 const symbol_ptr = elf_file.symbol(self.plt_index.?);
197 symbol_ptr.value = @intCast(shdr.sh_addr);
198 symbol_ptr.output_section_index = shndx;
199 }
200
201 // __dso_handle
202 if (self.dso_handle_index) |index| {
203 const shdr = &elf_file.shdrs.items[1];
204 const symbol_ptr = elf_file.symbol(index);
205 symbol_ptr.value = @intCast(shdr.sh_addr);
206 symbol_ptr.output_section_index = 0;
207 }
208
209 // __GNU_EH_FRAME_HDR
210 if (elf_file.eh_frame_hdr_section_index) |shndx| {
211 const shdr = &elf_file.shdrs.items[shndx];
212 const symbol_ptr = elf_file.symbol(self.gnu_eh_frame_hdr_index.?);
213 symbol_ptr.value = @intCast(shdr.sh_addr);
214 symbol_ptr.output_section_index = shndx;
215 }
216
217 // __rela_iplt_start, __rela_iplt_end
218 if (elf_file.rela_dyn_section_index) |shndx| blk: {
219 if (link_mode != .static or comp.config.pie) break :blk;
220 const shdr = &elf_file.shdrs.items[shndx];
221 const end_addr = shdr.sh_addr + shdr.sh_size;
222 const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
223 const start_sym = elf_file.symbol(self.rela_iplt_start_index.?);
224 const end_sym = elf_file.symbol(self.rela_iplt_end_index.?);
225 start_sym.value = @intCast(start_addr);
226 start_sym.output_section_index = shndx;
227 end_sym.value = @intCast(end_addr);
228 end_sym.output_section_index = shndx;
229 }
230
231 // _end
232 {
233 const end_symbol = elf_file.symbol(self.end_index.?);
234 for (elf_file.shdrs.items, 0..) |shdr, shndx| {
235 if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
236 end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);
237 end_symbol.output_section_index = @intCast(shndx);
238 }
239 }
240 }
241
242 // __start_*, __stop_*
243 {
244 var index: usize = 0;
245 while (index < self.start_stop_indexes.items.len) : (index += 2) {
246 const start = elf_file.symbol(self.start_stop_indexes.items[index]);
247 const name = start.name(elf_file);
248 const stop = elf_file.symbol(self.start_stop_indexes.items[index + 1]);
249 const shndx = elf_file.sectionByName(name["__start_".len..]).?;
250 const shdr = &elf_file.shdrs.items[shndx];
251 start.value = @intCast(shdr.sh_addr);
252 start.output_section_index = shndx;
253 stop.value = @intCast(shdr.sh_addr + shdr.sh_size);
254 stop.output_section_index = shndx;
255 }
256 }
257
258 // __global_pointer$
259 if (self.global_pointer_index) |index| {
260 const sym = elf_file.symbol(index);
261 if (elf_file.sectionByName(".sdata")) |shndx| {
262 const shdr = elf_file.shdrs.items[shndx];
263 sym.value = @intCast(shdr.sh_addr + 0x800);
264 sym.output_section_index = shndx;
265 } else {
266 sym.value = 0;
267 sym.output_section_index = 0;
268 }
269 }
270}
271
52272pub fn globals(self: LinkerDefined) []const Symbol.Index {
53273 return self.symbols.items;
54274}
......@@ -127,6 +347,7 @@ const mem = std.mem;
127347const std = @import("std");
128348
129349const Allocator = mem.Allocator;
350const Atom = @import("Atom.zig");
130351const Elf = @import("../Elf.zig");
131352const File = @import("file.zig").File;
132353const LinkerDefined = @This();
src/link/Elf/Object.zig+333-200
......@@ -10,12 +10,17 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
1010strtab: std.ArrayListUnmanaged(u8) = .{},
1111first_global: ?Symbol.Index = null,
1212symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
14comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
15comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
1613relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
1714
18merge_sections: std.ArrayListUnmanaged(InputMergeSection.Index) = .{},
15atoms: std.ArrayListUnmanaged(Atom) = .{},
16atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
17atoms_extra: std.ArrayListUnmanaged(u32) = .{},
18
19comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},
20comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
21
22input_merge_sections: std.ArrayListUnmanaged(InputMergeSection) = .{},
23input_merge_sections_indexes: std.ArrayListUnmanaged(InputMergeSection.Index) = .{},
1924
2025fdes: std.ArrayListUnmanaged(Fde) = .{},
2126cies: std.ArrayListUnmanaged(Cie) = .{},
......@@ -47,13 +52,19 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
4752 self.strtab.deinit(allocator);
4853 self.symbols.deinit(allocator);
4954 self.atoms.deinit(allocator);
55 self.atoms_indexes.deinit(allocator);
56 self.atoms_extra.deinit(allocator);
5057 self.comdat_groups.deinit(allocator);
5158 self.comdat_group_data.deinit(allocator);
5259 self.relocs.deinit(allocator);
5360 self.fdes.deinit(allocator);
5461 self.cies.deinit(allocator);
5562 self.eh_frame_data.deinit(allocator);
56 self.merge_sections.deinit(allocator);
63 for (self.input_merge_sections.items) |*isec| {
64 isec.deinit(allocator);
65 }
66 self.input_merge_sections.deinit(allocator);
67 self.input_merge_sections_indexes.deinit(allocator);
5768}
5869
5970pub fn parse(self: *Object, elf_file: *Elf) !void {
......@@ -62,14 +73,20 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
6273 const handle = elf_file.fileHandle(self.file_handle);
6374
6475 try self.parseCommon(gpa, handle, elf_file);
76
77 // Append null input merge section
78 try self.input_merge_sections.append(gpa, .{});
79 // Allocate atom index 0 to null atom
80 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
81
6582 try self.initAtoms(gpa, handle, elf_file);
6683 try self.initSymtab(gpa, elf_file);
6784
6885 for (self.shdrs.items, 0..) |shdr, i| {
69 const atom = elf_file.atom(self.atoms.items[i]) orelse continue;
70 if (!atom.flags.alive) continue;
86 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
87 if (!atom_ptr.alive) continue;
7188 if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
72 mem.eql(u8, atom.name(elf_file), ".eh_frame"))
89 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"))
7390 {
7491 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
7592 }
......@@ -169,8 +186,11 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
169186
170187fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
171188 const shdrs = self.shdrs.items;
172 try self.atoms.resize(allocator, shdrs.len);
173 @memset(self.atoms.items, 0);
189 try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len);
190 try self.atoms_extra.ensureTotalCapacityPrecise(allocator, shdrs.len * @sizeOf(Atom.Extra));
191 try self.atoms_indexes.ensureTotalCapacityPrecise(allocator, shdrs.len);
192 try self.atoms_indexes.resize(allocator, shdrs.len);
193 @memset(self.atoms_indexes.items, 0);
174194
175195 for (shdrs, 0..) |shdr, i| {
176196 if (shdr.sh_flags & elf.SHF_EXCLUDE != 0 and
......@@ -188,37 +208,53 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
188208 const group_signature = blk: {
189209 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
190210 const sym_shdr = shdrs[group_info_sym.st_shndx];
191 break :blk self.getString(sym_shdr.sh_name);
211 break :blk sym_shdr.sh_name;
192212 }
193 break :blk self.getString(group_info_sym.st_name);
213 break :blk group_info_sym.st_name;
194214 };
195215
196216 const shndx = @as(u32, @intCast(i));
197217 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
198218 defer allocator.free(group_raw_data);
199 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
219 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
220 try elf_file.reportParseError2(
221 self.index,
222 "corrupt section group: not evenly divisible ",
223 .{},
224 );
225 return error.MalformedObject;
226 };
227 if (group_nmembers == 0) {
228 try elf_file.reportParseError2(
229 self.index,
230 "corrupt section group: empty section",
231 .{},
232 );
233 return error.MalformedObject;
234 }
200235 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
201236
202237 if (group_members[0] != elf.GRP_COMDAT) {
203 // TODO convert into an error
204 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
205 continue;
238 try elf_file.reportParseError2(
239 self.index,
240 "corrupt section group: unknown SHT_GROUP format",
241 .{},
242 );
243 return error.MalformedObject;
206244 }
207245
208246 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));
209247 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
210248
211 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
212 const comdat_group_index = try elf_file.addComdatGroup();
213 const comdat_group = elf_file.comdatGroup(comdat_group_index);
249 const comdat_group_index = try self.addComdatGroup(allocator);
250 const comdat_group = self.comdatGroup(comdat_group_index);
214251 comdat_group.* = .{
215 .owner = gop.index,
216 .file = self.index,
252 .signature_off = group_signature,
253 .file_index = self.index,
217254 .shndx = shndx,
218255 .members_start = group_start,
219256 .members_len = @intCast(group_nmembers - 1),
220257 };
221 try self.comdat_groups.append(allocator, comdat_group_index);
222258 },
223259
224260 elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),
......@@ -233,7 +269,19 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
233269 else => {
234270 const shndx = @as(u32, @intCast(i));
235271 if (self.skipShdr(shndx, elf_file)) continue;
236 try self.addAtom(allocator, handle, shdr, shndx, elf_file);
272 const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: {
273 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
274 defer allocator.free(data);
275 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
276 break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) };
277 } else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) };
278 const atom_index = self.addAtomAssumeCapacity(.{
279 .name = shdr.sh_name,
280 .shndx = shndx,
281 .size = size,
282 .alignment = alignment,
283 });
284 self.atoms_indexes.items[shndx] = atom_index;
237285 },
238286 }
239287 }
......@@ -241,14 +289,14 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
241289 // Parse relocs sections if any.
242290 for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) {
243291 elf.SHT_REL, elf.SHT_RELA => {
244 const atom_index = self.atoms.items[shdr.sh_info];
245 if (elf_file.atom(atom_index)) |atom| {
292 const atom_index = self.atoms_indexes.items[shdr.sh_info];
293 if (self.atom(atom_index)) |atom_ptr| {
246294 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
247295 defer allocator.free(relocs);
248 atom.relocs_section_index = @intCast(i);
296 atom_ptr.relocs_section_index = @intCast(i);
249297 const rel_index: u32 = @intCast(self.relocs.items.len);
250298 const rel_count: u32 = @intCast(relocs.len);
251 try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
299 atom_ptr.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
252300 try self.relocs.appendUnalignedSlice(allocator, relocs);
253301 if (elf_file.getTarget().cpu.arch == .riscv64) {
254302 sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
......@@ -259,27 +307,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
259307 };
260308}
261309
262fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void {
263 const atom_index = try elf_file.addAtom();
264 const atom = elf_file.atom(atom_index).?;
265 atom.atom_index = atom_index;
266 atom.name_offset = shdr.sh_name;
267 atom.file_index = self.index;
268 atom.input_section_index = shndx;
269 self.atoms.items[shndx] = atom_index;
270
271 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
272 const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
273 defer allocator.free(data);
274 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
275 atom.size = chdr.ch_size;
276 atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
277 } else {
278 atom.size = shdr.sh_size;
279 atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
280 }
281}
282
283310fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
284311 const name = blk: {
285312 const name = self.getString(shdr.sh_name);
......@@ -327,7 +354,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O
327354 const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
328355 .type = @"type",
329356 .flags = flags,
330 .name = name,
357 .name = try elf_file.insertShString(name),
331358 });
332359 return out_shndx;
333360}
......@@ -359,8 +386,10 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
359386 sym_ptr.value = @intCast(sym.st_value);
360387 sym_ptr.name_offset = sym.st_name;
361388 sym_ptr.esym_index = @as(u32, @intCast(i));
362 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
363389 sym_ptr.file_index = self.index;
390 if (sym.st_shndx != elf.SHN_ABS) {
391 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
392 }
364393 }
365394
366395 for (self.symtab.items[first_global..]) |sym| {
......@@ -447,15 +476,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
447476 var i: u32 = @as(u32, @intCast(fdes_start));
448477 while (i < self.fdes.items.len) {
449478 const fde = self.fdes.items[i];
450 const atom = fde.atom(elf_file);
479 const atom_ptr = fde.atom(elf_file);
451480 const start = i;
452481 i += 1;
453482 while (i < self.fdes.items.len) : (i += 1) {
454483 const next_fde = self.fdes.items[i];
455 if (atom.atom_index != next_fde.atom(elf_file).atom_index) break;
484 if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break;
456485 }
457 try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
458 atom.flags.fde = true;
486 atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
459487 }
460488}
461489
......@@ -498,19 +526,19 @@ fn filterRelocs(
498526pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
499527 const comp = elf_file.base.comp;
500528 const gpa = comp.gpa;
501 for (self.atoms.items) |atom_index| {
502 const atom = elf_file.atom(atom_index) orelse continue;
503 if (!atom.flags.alive) continue;
504 const shdr = atom.inputShdr(elf_file);
529 for (self.atoms_indexes.items) |atom_index| {
530 const atom_ptr = self.atom(atom_index) orelse continue;
531 if (!atom_ptr.alive) continue;
532 const shdr = atom_ptr.inputShdr(elf_file);
505533 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
506534 if (shdr.sh_type == elf.SHT_NOBITS) continue;
507 if (atom.scanRelocsRequiresCode(elf_file)) {
535 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
508536 // TODO ideally, we don't have to decompress at this stage (should already be done)
509537 // and we just fetch the code slice.
510538 const code = try self.codeDecompressAlloc(elf_file, atom_index);
511539 defer gpa.free(code);
512 try atom.scanRelocs(elf_file, code, undefs);
513 } else try atom.scanRelocs(elf_file, null, undefs);
540 try atom_ptr.scanRelocs(elf_file, code, undefs);
541 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
514542 }
515543
516544 for (self.cies.items) |cie| {
......@@ -538,19 +566,21 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
538566 if (esym.st_shndx == elf.SHN_UNDEF) continue;
539567
540568 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
541 const atom_index = self.atoms.items[esym.st_shndx];
542 const atom = elf_file.atom(atom_index) orelse continue;
543 if (!atom.flags.alive) continue;
569 const atom_index = self.atoms_indexes.items[esym.st_shndx];
570 const atom_ptr = self.atom(atom_index) orelse continue;
571 if (!atom_ptr.alive) continue;
544572 }
545573
546574 const global = elf_file.symbol(index);
547575 if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {
548 const atom_index = switch (esym.st_shndx) {
549 elf.SHN_ABS, elf.SHN_COMMON => 0,
550 else => self.atoms.items[esym.st_shndx],
551 };
576 switch (esym.st_shndx) {
577 elf.SHN_ABS, elf.SHN_COMMON => {},
578 else => global.ref = .{
579 .index = self.atoms_indexes.items[esym.st_shndx],
580 .file = self.index,
581 },
582 }
552583 global.value = @intCast(esym.st_value);
553 global.atom_index = atom_index;
554584 global.esym_index = esym_index;
555585 global.file_index = self.index;
556586 global.version_index = elf_file.default_sym_version;
......@@ -579,7 +609,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
579609 };
580610
581611 global.value = 0;
582 global.atom_index = 0;
612 global.ref = .{ .index = 0, .file = 0 };
583613 global.esym_index = esym_index;
584614 global.file_index = self.index;
585615 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
......@@ -600,7 +630,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
600630 }
601631
602632 global.value = 0;
603 global.atom_index = 0;
633 global.ref = .{ .index = 0, .file = 0 };
604634 global.esym_index = esym_index;
605635 global.file_index = self.index;
606636 }
......@@ -624,13 +654,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {
624654 }
625655}
626656
627pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
657pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
628658 const cpu_arch = elf_file.getTarget().cpu.arch;
629 for (self.atoms.items) |atom_index| {
630 const atom = elf_file.atom(atom_index) orelse continue;
631 const is_eh_frame = (cpu_arch == .x86_64 and atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
632 mem.eql(u8, atom.name(elf_file), ".eh_frame");
633 if (atom.flags.alive and is_eh_frame) atom.flags.alive = false;
659 for (self.atoms_indexes.items) |atom_index| {
660 const atom_ptr = self.atom(atom_index) orelse continue;
661 const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
662 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame");
663 if (atom_ptr.alive and is_eh_frame) atom_ptr.alive = false;
634664 }
635665}
636666
......@@ -648,9 +678,9 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
648678 sym.st_shndx == elf.SHN_COMMON) continue;
649679
650680 if (sym.st_shndx != elf.SHN_ABS) {
651 const atom_index = self.atoms.items[sym.st_shndx];
652 const atom = elf_file.atom(atom_index) orelse continue;
653 if (!atom.flags.alive) continue;
681 const atom_index = self.atoms_indexes.items[sym.st_shndx];
682 const atom_ptr = self.atom(atom_index) orelse continue;
683 if (!atom_ptr.alive) continue;
654684 }
655685
656686 const gop = try dupes.getOrPut(index);
......@@ -661,25 +691,24 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
661691 }
662692}
663693
664pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
694pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
665695 const gpa = elf_file.base.comp.gpa;
666696
667 try self.merge_sections.resize(gpa, self.shdrs.items.len);
668 @memset(self.merge_sections.items, 0);
697 try self.input_merge_sections.ensureUnusedCapacity(gpa, self.shdrs.items.len);
698 try self.input_merge_sections_indexes.resize(gpa, self.shdrs.items.len);
699 @memset(self.input_merge_sections_indexes.items, 0);
669700
670701 for (self.shdrs.items, 0..) |shdr, shndx| {
671702 if (shdr.sh_flags & elf.SHF_MERGE == 0) continue;
672703
673 const atom_index = self.atoms.items[shndx];
674 const atom_ptr = elf_file.atom(atom_index) orelse continue;
675 if (!atom_ptr.flags.alive) continue;
704 const atom_index = self.atoms_indexes.items[shndx];
705 const atom_ptr = self.atom(atom_index) orelse continue;
706 if (!atom_ptr.alive) continue;
676707 if (atom_ptr.relocs(elf_file).len > 0) continue;
677708
678 const imsec_idx = try elf_file.addInputMergeSection();
679 const imsec = elf_file.inputMergeSection(imsec_idx).?;
680 self.merge_sections.items[shndx] = imsec_idx;
681
682 imsec.merge_section_index = try elf_file.getOrCreateMergeSection(atom_ptr.name(elf_file), shdr.sh_flags, shdr.sh_type);
709 const imsec_idx = try self.addInputMergeSection(gpa);
710 const imsec = self.inputMergeSection(imsec_idx).?;
711 self.input_merge_sections_indexes.items[shndx] = imsec_idx;
683712 imsec.atom_index = atom_index;
684713
685714 const data = try self.codeDecompressAlloc(elf_file, atom_index);
......@@ -734,18 +763,31 @@ pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
734763 }
735764 }
736765
737 atom_ptr.flags.alive = false;
766 atom_ptr.alive = false;
767 }
768}
769
770pub fn initOutputMergeSections(self: *Object, elf_file: *Elf) !void {
771 for (self.input_merge_sections_indexes.items) |index| {
772 const imsec = self.inputMergeSection(index) orelse continue;
773 const atom_ptr = self.atom(imsec.atom_index).?;
774 const shdr = atom_ptr.inputShdr(elf_file);
775 imsec.merge_section_index = try elf_file.getOrCreateMergeSection(
776 atom_ptr.name(elf_file),
777 shdr.sh_flags,
778 shdr.sh_type,
779 );
738780 }
739781}
740782
741783pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
742784 const gpa = elf_file.base.comp.gpa;
743785
744 for (self.merge_sections.items) |index| {
745 const imsec = elf_file.inputMergeSection(index) orelse continue;
786 for (self.input_merge_sections_indexes.items) |index| {
787 const imsec = self.inputMergeSection(index) orelse continue;
746788 if (imsec.offsets.items.len == 0) continue;
747789 const msec = elf_file.mergeSection(imsec.merge_section_index);
748 const atom_ptr = elf_file.atom(imsec.atom_index).?;
790 const atom_ptr = self.atom(imsec.atom_index).?;
749791 const isec = atom_ptr.inputShdr(elf_file);
750792
751793 try imsec.subsections.resize(gpa, imsec.strings.items.len);
......@@ -754,8 +796,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
754796 const string = imsec.bytes.items[str.pos..][0..str.len];
755797 const res = try msec.insert(gpa, string);
756798 if (!res.found_existing) {
757 const msub_index = try elf_file.addMergeSubsection();
758 const msub = elf_file.mergeSubsection(msub_index);
799 const msub_index = try msec.addMergeSubsection(gpa);
800 const msub = msec.mergeSubsection(msub_index);
759801 msub.merge_section_index = imsec.merge_section_index;
760802 msub.string_index = res.key.pos;
761803 msub.alignment = atom_ptr.alignment;
......@@ -776,10 +818,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
776818
777819 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
778820
779 const imsec_index = self.merge_sections.items[esym.st_shndx];
780 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
821 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
822 const imsec = self.inputMergeSection(imsec_index) orelse continue;
781823 if (imsec.offsets.items.len == 0) continue;
782 const msub_index, const offset = imsec.findSubsection(@intCast(esym.st_value)) orelse {
824 const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {
783825 var err = try elf_file.base.addErrorWithNotes(2);
784826 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
785827 try err.addNote("for symbol {s}", .{sym.name(elf_file)});
......@@ -787,45 +829,44 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
787829 return error.MalformedObject;
788830 };
789831
790 try sym.addExtra(.{ .subsection = msub_index }, elf_file);
832 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
791833 sym.flags.merge_subsection = true;
792 sym.value = offset;
834 sym.value = res.offset;
793835 }
794836
795 for (self.atoms.items) |atom_index| {
796 const atom_ptr = elf_file.atom(atom_index) orelse continue;
797 if (!atom_ptr.flags.alive) continue;
798 const extras = atom_ptr.extra(elf_file) orelse continue;
837 for (self.atoms_indexes.items) |atom_index| {
838 const atom_ptr = self.atom(atom_index) orelse continue;
839 if (!atom_ptr.alive) continue;
840 const extras = atom_ptr.extra(elf_file);
799841 const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];
800842 for (relocs) |*rel| {
801843 const esym = self.symtab.items[rel.r_sym()];
802844 if (esym.st_type() != elf.STT_SECTION) continue;
803845
804 const imsec_index = self.merge_sections.items[esym.st_shndx];
805 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
846 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
847 const imsec = self.inputMergeSection(imsec_index) orelse continue;
806848 if (imsec.offsets.items.len == 0) continue;
807 const msub_index, const offset = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
849 const msec = elf_file.mergeSection(imsec.merge_section_index);
850 const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
808851 var err = try elf_file.base.addErrorWithNotes(1);
809852 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
810853 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
811854 return error.MalformedObject;
812855 };
813 const msub = elf_file.mergeSubsection(msub_index);
814 const msec = msub.mergeSection(elf_file);
815856
816857 const out_sym_idx: u64 = @intCast(self.symbols.items.len);
817858 try self.symbols.ensureUnusedCapacity(gpa, 1);
818 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), msub_index });
859 const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });
819860 defer gpa.free(name);
820861 const sym_index = try elf_file.addSymbol();
821862 const sym = elf_file.symbol(sym_index);
822863 sym.* = .{
823 .value = @bitCast(@as(i64, @intCast(offset)) - rel.r_addend),
864 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
824865 .name_offset = try self.addString(gpa, name),
825866 .esym_index = rel.r_sym(),
826867 .file_index = self.index,
827868 };
828 try sym.addExtra(.{ .subsection = msub_index }, elf_file);
869 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
829870 sym.flags.merge_subsection = true;
830871 self.symbols.addOneAssumeCapacity().* = sym_index;
831872 rel.r_info = (out_sym_idx << 32) | rel.r_type();
......@@ -857,21 +898,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
857898 const comp = elf_file.base.comp;
858899 const gpa = comp.gpa;
859900
860 const atom_index = try elf_file.addAtom();
861 try self.atoms.append(gpa, atom_index);
862
863901 const is_tls = global.type(elf_file) == elf.STT_TLS;
864902 const name = if (is_tls) ".tls_common" else ".common";
865
866 const atom = elf_file.atom(atom_index).?;
867903 const name_offset = @as(u32, @intCast(self.strtab.items.len));
868904 try self.strtab.writer(gpa).print("{s}\x00", .{name});
869 atom.atom_index = atom_index;
870 atom.name_offset = name_offset;
871 atom.file_index = self.index;
872 atom.size = this_sym.st_size;
873 const alignment = this_sym.st_value;
874 atom.alignment = Alignment.fromNonzeroByteUnits(alignment);
875905
876906 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
877907 if (is_tls) sh_flags |= elf.SHF_TLS;
......@@ -887,78 +917,84 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
887917 .sh_size = sh_size,
888918 .sh_link = 0,
889919 .sh_info = 0,
890 .sh_addralign = alignment,
920 .sh_addralign = this_sym.st_value,
891921 .sh_entsize = 0,
892922 };
893 atom.input_section_index = shndx;
923
924 const atom_index = try self.addAtom(gpa, .{
925 .name = name_offset,
926 .shndx = shndx,
927 .size = this_sym.st_size,
928 .alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),
929 });
930 try self.atoms_indexes.append(gpa, atom_index);
894931
895932 global.value = 0;
896 global.atom_index = atom_index;
933 global.ref = .{ .index = atom_index, .file = self.index };
897934 global.flags.weak = false;
898935 }
899936}
900937
901pub fn initOutputSections(self: Object, elf_file: *Elf) !void {
902 for (self.atoms.items) |atom_index| {
903 const atom = elf_file.atom(atom_index) orelse continue;
904 if (!atom.flags.alive) continue;
905 const shdr = atom.inputShdr(elf_file);
938pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
939 for (self.comdat_groups.items, 0..) |*cg, cgi| {
940 const signature = cg.signature(elf_file);
941 const gop = try table.getOrPut(signature);
942 if (!gop.found_existing) {
943 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
944 continue;
945 }
946 const current = elf_file.comdatGroup(gop.value_ptr.*);
947 cg.alive = false;
948 if (self.index < current.file_index) {
949 current.alive = false;
950 cg.alive = true;
951 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
952 }
953 }
954}
955
956pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
957 for (self.comdat_groups.items) |cg| {
958 if (cg.alive) continue;
959 for (cg.comdatGroupMembers(elf_file)) |shndx| {
960 const atom_index = self.atoms_indexes.items[shndx];
961 if (self.atom(atom_index)) |atom_ptr| {
962 atom_ptr.alive = false;
963 atom_ptr.markFdesDead(elf_file);
964 }
965 }
966 }
967}
968
969pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
970 for (self.atoms_indexes.items) |atom_index| {
971 const atom_ptr = self.atom(atom_index) orelse continue;
972 if (!atom_ptr.alive) continue;
973 const shdr = atom_ptr.inputShdr(elf_file);
906974 _ = try self.initOutputSection(elf_file, shdr);
907975 }
908976}
909977
910978pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
911 for (self.atoms.items) |atom_index| {
912 const atom = elf_file.atom(atom_index) orelse continue;
913 if (!atom.flags.alive) continue;
914 const shdr = atom.inputShdr(elf_file);
915 atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
979 for (self.atoms_indexes.items) |atom_index| {
980 const atom_ptr = self.atom(atom_index) orelse continue;
981 if (!atom_ptr.alive) continue;
982 const shdr = atom_ptr.inputShdr(elf_file);
983 atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
916984
917985 const comp = elf_file.base.comp;
918986 const gpa = comp.gpa;
919 const gop = try elf_file.output_sections.getOrPut(gpa, atom.output_section_index);
987 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
920988 if (!gop.found_existing) gop.value_ptr.* = .{};
921 try gop.value_ptr.append(gpa, atom_index);
922 }
923
924 for (self.locals()) |local_index| {
925 const local = elf_file.symbol(local_index);
926 if (local.mergeSubsection(elf_file)) |msub| {
927 if (!msub.alive) continue;
928 local.output_section_index = msub.mergeSection(elf_file).output_section_index;
929 continue;
930 }
931 const atom = local.atom(elf_file) orelse continue;
932 if (!atom.flags.alive) continue;
933 local.output_section_index = atom.output_section_index;
934 }
935
936 for (self.globals()) |global_index| {
937 const global = elf_file.symbol(global_index);
938 if (global.file(elf_file).?.index() != self.index) continue;
939 if (global.mergeSubsection(elf_file)) |msub| {
940 if (!msub.alive) continue;
941 global.output_section_index = msub.mergeSection(elf_file).output_section_index;
942 continue;
943 }
944 const atom = global.atom(elf_file) orelse continue;
945 if (!atom.flags.alive) continue;
946 global.output_section_index = atom.output_section_index;
947 }
948
949 for (self.symbols.items[self.symtab.items.len..]) |local_index| {
950 const local = elf_file.symbol(local_index);
951 const msub = local.mergeSubsection(elf_file).?;
952 if (!msub.alive) continue;
953 local.output_section_index = msub.mergeSection(elf_file).output_section_index;
989 try gop.value_ptr.append(gpa, .{ .index = atom_index, .file = self.index });
954990 }
955991}
956992
957pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
958 for (self.atoms.items) |atom_index| {
959 const atom = elf_file.atom(atom_index) orelse continue;
960 if (!atom.flags.alive) continue;
961 const shndx = atom.relocsShndx() orelse continue;
993pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
994 for (self.atoms_indexes.items) |atom_index| {
995 const atom_ptr = self.atom(atom_index) orelse continue;
996 if (!atom_ptr.alive) continue;
997 const shndx = atom_ptr.relocsShndx() orelse continue;
962998 const shdr = self.shdrs.items[shndx];
963999 const out_shndx = try self.initOutputSection(elf_file, shdr);
9641000 const out_shdr = &elf_file.shdrs.items[out_shndx];
......@@ -968,24 +1004,24 @@ pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
9681004 }
9691005}
9701006
971pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
972 for (self.atoms.items) |atom_index| {
973 const atom = elf_file.atom(atom_index) orelse continue;
974 if (!atom.flags.alive) continue;
1007pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
1008 for (self.atoms_indexes.items) |atom_index| {
1009 const atom_ptr = self.atom(atom_index) orelse continue;
1010 if (!atom_ptr.alive) continue;
9751011 const shndx = blk: {
976 const shndx = atom.relocsShndx() orelse continue;
1012 const shndx = atom_ptr.relocsShndx() orelse continue;
9771013 const shdr = self.shdrs.items[shndx];
9781014 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
9791015 };
9801016 const shdr = &elf_file.shdrs.items[shndx];
981 shdr.sh_info = atom.outputShndx().?;
1017 shdr.sh_info = atom_ptr.output_section_index;
9821018 shdr.sh_link = elf_file.symtab_section_index.?;
9831019
9841020 const comp = elf_file.base.comp;
9851021 const gpa = comp.gpa;
986 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
1022 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom_ptr.output_section_index);
9871023 if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };
988 try gop.value_ptr.atom_list.append(gpa, atom_index);
1024 try gop.value_ptr.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
9891025 }
9901026}
9911027
......@@ -1041,7 +1077,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
10411077 const isAlive = struct {
10421078 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
10431079 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
1044 if (sym.atom(ctx)) |atom_ptr| return atom_ptr.flags.alive;
1080 if (sym.atom(ctx)) |atom_ptr| return atom_ptr.alive;
10451081 return true;
10461082 }
10471083 }.isAlive;
......@@ -1119,11 +1155,10 @@ pub fn globals(self: Object) []const Symbol.Index {
11191155
11201156/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
11211157/// Caller owns the memory.
1122pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
1158pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
11231159 const comp = elf_file.base.comp;
11241160 const gpa = comp.gpa;
1125 const atom_ptr = elf_file.atom(atom_index).?;
1126 assert(atom_ptr.file_index == self.index);
1161 const atom_ptr = self.atom(atom_index).?;
11271162 const shdr = atom_ptr.inputShdr(elf_file);
11281163 const handle = elf_file.fileHandle(self.file_handle);
11291164 const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index);
......@@ -1184,6 +1219,105 @@ fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shn
11841219 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
11851220}
11861221
1222const AddAtomArgs = struct {
1223 name: u32,
1224 shndx: u32,
1225 size: u64,
1226 alignment: Alignment,
1227};
1228
1229fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
1230 try self.atoms.ensureUnusedCapacity(allocator, 1);
1231 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1232 return self.addAtomAssumeCapacity(args);
1233}
1234
1235fn addAtomAssumeCapacity(self: *Object, args: AddAtomArgs) Atom.Index {
1236 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
1237 const atom_ptr = self.atoms.addOneAssumeCapacity();
1238 atom_ptr.* = .{
1239 .atom_index = atom_index,
1240 .name_offset = args.name,
1241 .file_index = self.index,
1242 .input_section_index = args.shndx,
1243 .extra_index = self.addAtomExtraAssumeCapacity(.{}),
1244 .size = args.size,
1245 .alignment = args.alignment,
1246 };
1247 return atom_index;
1248}
1249
1250pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom {
1251 if (atom_index == 0) return null;
1252 assert(atom_index < self.atoms.items.len);
1253 return &self.atoms.items[atom_index];
1254}
1255
1256pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
1257 const fields = @typeInfo(Atom.Extra).Struct.fields;
1258 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
1259 return self.addAtomExtraAssumeCapacity(extra);
1260}
1261
1262pub fn addAtomExtraAssumeCapacity(self: *Object, extra: Atom.Extra) u32 {
1263 const index = @as(u32, @intCast(self.atoms_extra.items.len));
1264 const fields = @typeInfo(Atom.Extra).Struct.fields;
1265 inline for (fields) |field| {
1266 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
1267 u32 => @field(extra, field.name),
1268 else => @compileError("bad field type"),
1269 });
1270 }
1271 return index;
1272}
1273
1274pub fn atomExtra(self: *Object, index: u32) Atom.Extra {
1275 const fields = @typeInfo(Atom.Extra).Struct.fields;
1276 var i: usize = index;
1277 var result: Atom.Extra = undefined;
1278 inline for (fields) |field| {
1279 @field(result, field.name) = switch (field.type) {
1280 u32 => self.atoms_extra.items[i],
1281 else => @compileError("bad field type"),
1282 };
1283 i += 1;
1284 }
1285 return result;
1286}
1287
1288pub fn setAtomExtra(self: *Object, index: u32, extra: Atom.Extra) void {
1289 const fields = @typeInfo(Atom.Extra).Struct.fields;
1290 inline for (fields, 0..) |field, i| {
1291 self.atoms_extra.items[index + i] = switch (field.type) {
1292 u32 => @field(extra, field.name),
1293 else => @compileError("bad field type"),
1294 };
1295 }
1296}
1297
1298fn addInputMergeSection(self: *Object, allocator: Allocator) !InputMergeSection.Index {
1299 const index: InputMergeSection.Index = @intCast(self.input_merge_sections.items.len);
1300 const msec = try self.input_merge_sections.addOne(allocator);
1301 msec.* = .{};
1302 return index;
1303}
1304
1305fn inputMergeSection(self: *Object, index: InputMergeSection.Index) ?*InputMergeSection {
1306 if (index == 0) return null;
1307 return &self.input_merge_sections.items[index];
1308}
1309
1310fn addComdatGroup(self: *Object, allocator: Allocator) !Elf.ComdatGroup.Index {
1311 const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
1312 _ = try self.comdat_groups.addOne(allocator);
1313 return index;
1314}
1315
1316pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
1317 assert(index < self.comdat_groups.items.len);
1318 return &self.comdat_groups.items[index];
1319}
1320
11871321pub fn format(
11881322 self: *Object,
11891323 comptime unused_fmt_string: []const u8,
......@@ -1247,9 +1381,9 @@ fn formatAtoms(
12471381 _ = options;
12481382 const object = ctx.object;
12491383 try writer.writeAll(" atoms\n");
1250 for (object.atoms.items) |atom_index| {
1251 const atom = ctx.elf_file.atom(atom_index) orelse continue;
1252 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
1384 for (object.atoms_indexes.items) |atom_index| {
1385 const atom_ptr = object.atom(atom_index) orelse continue;
1386 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
12531387 }
12541388}
12551389
......@@ -1315,16 +1449,15 @@ fn formatComdatGroups(
13151449 const object = ctx.object;
13161450 const elf_file = ctx.elf_file;
13171451 try writer.writeAll(" COMDAT groups\n");
1318 for (object.comdat_groups.items) |cg_index| {
1319 const cg = elf_file.comdatGroup(cg_index);
1320 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
1321 if (cg_owner.file != object.index) continue;
1322 try writer.print(" COMDAT({d})\n", .{cg_index});
1452 for (object.comdat_groups.items, 0..) |cg, cg_index| {
1453 try writer.print(" COMDAT({d})", .{cg_index});
1454 if (!cg.alive) try writer.writeAll(" : [*]");
1455 try writer.writeByte('\n');
13231456 const cg_members = cg.comdatGroupMembers(elf_file);
13241457 for (cg_members) |shndx| {
1325 const atom_index = object.atoms.items[shndx];
1326 const atom = elf_file.atom(atom_index) orelse continue;
1327 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
1458 const atom_index = object.atoms_indexes.items[shndx];
1459 const atom_ptr = object.atom(atom_index) orelse continue;
1460 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
13281461 }
13291462 }
13301463}
src/link/Elf/SharedObject.zig+1-1
......@@ -232,7 +232,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
232232 const global = elf_file.symbol(index);
233233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
234234 global.value = @intCast(this_sym.st_value);
235 global.atom_index = 0;
235 global.ref = .{ .index = 0, .file = 0 };
236236 global.esym_index = esym_index;
237237 global.version_index = self.versyms.items[esym_index];
238238 global.file_index = self.index;
src/link/Elf/Symbol.zig+25-20
......@@ -9,10 +9,9 @@ name_offset: u32 = 0,
99/// Index of file where this symbol is defined.
1010file_index: File.Index = 0,
1111
12/// Index of atom containing this symbol.
13/// Index of 0 means there is no associated atom with this symbol.
14/// Use `atom` to get the pointer to the atom.
15atom_index: Atom.Index = 0,
12/// Reference to Atom or merge subsection containing this symbol if any.
13/// Use `atom` or `mergeSubsection` to get the pointer to the atom.
14ref: Elf.Ref = .{ .index = 0, .file = 0 },
1615
1716/// Assigned output section index for this symbol.
1817output_section_index: u32 = 0,
......@@ -34,11 +33,15 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
3433 const file_ptr = symbol.file(elf_file).?;
3534 if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;
3635 return !symbol.flags.import and symbol.atom(elf_file) == null and
37 symbol.mergeSubsection(elf_file) == null and symbol.outputShndx() == null and
36 symbol.mergeSubsection(elf_file) == null and symbol.outputShndx(elf_file) == null and
3837 file_ptr != .linker_defined;
3938}
4039
41pub fn outputShndx(symbol: Symbol) ?u32 {
40pub fn outputShndx(symbol: Symbol, elf_file: *Elf) ?u32 {
41 if (symbol.mergeSubsection(elf_file)) |msub|
42 return if (msub.alive) msub.mergeSection(elf_file).output_section_index else null;
43 if (symbol.atom(elf_file)) |atom_ptr|
44 return if (atom_ptr.alive) atom_ptr.output_section_index else null;
4245 if (symbol.output_section_index == 0) return null;
4346 return symbol.output_section_index;
4447}
......@@ -68,13 +71,15 @@ pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
6871}
6972
7073pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
71 return elf_file.atom(symbol.atom_index);
74 if (symbol.flags.merge_subsection) return null;
75 const file_ptr = elf_file.file(symbol.ref.file) orelse return null;
76 return file_ptr.atom(symbol.ref.index);
7277}
7378
7479pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {
7580 if (!symbol.flags.merge_subsection) return null;
76 const extras = symbol.extra(elf_file).?;
77 return elf_file.mergeSubsection(extras.subsection);
81 const msec = elf_file.mergeSection(symbol.ref.file);
82 return msec.mergeSubsection(symbol.ref.index);
7883}
7984
8085pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
......@@ -116,7 +121,7 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
116121 return symbol.pltAddress(elf_file);
117122 }
118123 if (symbol.atom(elf_file)) |atom_ptr| {
119 if (!atom_ptr.flags.alive) {
124 if (!atom_ptr.alive) {
120125 if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {
121126 const sym_name = symbol.name(elf_file);
122127 const sh_addr, const sh_size = blk: {
......@@ -258,7 +263,6 @@ const AddExtraOpts = struct {
258263 gottp: ?u32 = null,
259264 tlsdesc: ?u32 = null,
260265 zig_got: ?u32 = null,
261 subsection: ?u32 = null,
262266};
263267
264268pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
......@@ -298,7 +302,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
298302 if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
299303 if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index);
300304 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
301 break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF);
305 break :blk @intCast(symbol.outputShndx(elf_file) orelse elf.SHN_UNDEF);
302306 };
303307 const st_value = blk: {
304308 if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);
......@@ -382,22 +386,23 @@ fn format2(
382386 _ = options;
383387 _ = unused_fmt_string;
384388 const symbol = ctx.symbol;
389 const elf_file = ctx.elf_file;
385390 try writer.print("%{d} : {s} : @{x}", .{
386391 symbol.esym_index,
387 symbol.fmtName(ctx.elf_file),
388 symbol.address(.{}, ctx.elf_file),
392 symbol.fmtName(elf_file),
393 symbol.address(.{}, elf_file),
389394 });
390 if (symbol.file(ctx.elf_file)) |file_ptr| {
391 if (symbol.isAbs(ctx.elf_file)) {
392 if (symbol.elfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
395 if (symbol.file(elf_file)) |file_ptr| {
396 if (symbol.isAbs(elf_file)) {
397 if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) {
393398 try writer.writeAll(" : undef");
394399 } else {
395400 try writer.writeAll(" : absolute");
396401 }
397 } else if (symbol.outputShndx()) |shndx| {
402 } else if (symbol.outputShndx(elf_file)) |shndx| {
398403 try writer.print(" : shdr({d})", .{shndx});
399404 }
400 if (symbol.atom(ctx.elf_file)) |atom_ptr| {
405 if (symbol.atom(elf_file)) |atom_ptr| {
401406 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
402407 }
403408 var buf: [2]u8 = .{'_'} ** 2;
......@@ -483,7 +488,7 @@ pub const Extra = struct {
483488 gottp: u32 = 0,
484489 tlsdesc: u32 = 0,
485490 zig_got: u32 = 0,
486 subsection: u32 = 0,
491 merge_section: u32 = 0,
487492};
488493
489494pub const Index = u32;
src/link/Elf/ZigObject.zig+138-82
......@@ -15,7 +15,9 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1515global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
1616globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
1717
18atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
18atoms: std.ArrayListUnmanaged(Atom) = .{},
19atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
20atoms_extra: std.ArrayListUnmanaged(u32) = .{},
1921relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
2022
2123num_dynrelocs: u32 = 0,
......@@ -80,7 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
8082 const comp = elf_file.base.comp;
8183 const gpa = comp.gpa;
8284
83 try self.atoms.append(gpa, 0); // null input section
85 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
8486 try self.relocs.append(gpa, .{}); // null relocs section
8587 try self.strtab.buffer.append(gpa, 0);
8688
......@@ -117,6 +119,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
117119 self.global_symbols.deinit(allocator);
118120 self.globals_lookup.deinit(allocator);
119121 self.atoms.deinit(allocator);
122 self.atoms_indexes.deinit(allocator);
123 self.atoms_extra.deinit(allocator);
120124 for (self.relocs.items) |*list| {
121125 list.deinit(allocator);
122126 }
......@@ -276,24 +280,20 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
276280 return index | global_symbol_bit;
277281}
278282
279pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
283pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
280284 const gpa = elf_file.base.comp.gpa;
281 const atom_index = try elf_file.addAtom();
285 const atom_index = try self.addAtom(gpa);
282286 const symbol_index = try elf_file.addSymbol();
283287 const esym_index = try self.addLocalEsym(gpa);
284288
285 const shndx = @as(u32, @intCast(self.atoms.items.len));
286 try self.atoms.append(gpa, atom_index);
289 try self.atoms_indexes.append(gpa, atom_index);
287290 try self.local_symbols.append(gpa, symbol_index);
288291
289 const atom_ptr = elf_file.atom(atom_index).?;
290 atom_ptr.file_index = self.index;
291
292292 const symbol_ptr = elf_file.symbol(symbol_index);
293293 symbol_ptr.file_index = self.index;
294 symbol_ptr.atom_index = atom_index;
294 symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
295295
296 self.local_esyms.items(.shndx)[esym_index] = shndx;
296 self.local_esyms.items(.shndx)[esym_index] = atom_index;
297297 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
298298 symbol_ptr.esym_index = esym_index;
299299
......@@ -301,21 +301,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
301301 const relocs_index = @as(u32, @intCast(self.relocs.items.len));
302302 const relocs = try self.relocs.addOne(gpa);
303303 relocs.* = .{};
304
305 const atom_ptr = self.atom(atom_index).?;
304306 atom_ptr.relocs_section_index = relocs_index;
305307
306308 return symbol_index;
307309}
308310
309311/// TODO actually create fake input shdrs and return that instead.
310pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
311 _ = self;
312 const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr;
313 const shndx = atom.outputShndx() orelse return Elf.null_shdr;
312pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
313 const atom_ptr = self.atom(atom_index) orelse return Elf.null_shdr;
314 const shndx = atom_ptr.output_section_index;
314315 var shdr = elf_file.shdrs.items[shndx];
315316 shdr.sh_addr = 0;
316317 shdr.sh_offset = 0;
317 shdr.sh_size = atom.size;
318 shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
318 shdr.sh_size = atom_ptr.size;
319 shdr.sh_addralign = atom_ptr.alignment.toByteUnits() orelse 1;
319320 return shdr;
320321}
321322
......@@ -329,27 +330,21 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
329330
330331 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
331332 assert(esym.st_shndx == SHN_ATOM);
332 const atom_index = self.atoms.items[shndx];
333 const atom = elf_file.atom(atom_index) orelse continue;
334 if (!atom.flags.alive) continue;
333 const atom_ptr = self.atom(shndx) orelse continue;
334 if (!atom_ptr.alive) continue;
335335 }
336336
337337 const global = elf_file.symbol(index);
338338 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
339339 const atom_index = switch (esym.st_shndx) {
340340 elf.SHN_ABS, elf.SHN_COMMON => 0,
341 SHN_ATOM => self.atoms.items[shndx],
341 SHN_ATOM => shndx,
342342 else => unreachable,
343343 };
344 const output_section_index = if (elf_file.atom(atom_index)) |atom|
345 atom.outputShndx().?
346 else
347 elf.SHN_UNDEF;
348344 global.value = @intCast(esym.st_value);
349 global.atom_index = atom_index;
345 global.ref = .{ .index = atom_index, .file = self.index };
350346 global.esym_index = esym_index;
351347 global.file_index = self.index;
352 global.output_section_index = output_section_index;
353348 global.version_index = elf_file.default_sym_version;
354349 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
355350 }
......@@ -376,7 +371,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
376371 };
377372
378373 global.value = 0;
379 global.atom_index = 0;
374 global.ref = .{ .index = 0, .file = 0 };
380375 global.esym_index = esym_index;
381376 global.file_index = self.index;
382377 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
......@@ -397,7 +392,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
397392 }
398393
399394 global.value = 0;
400 global.atom_index = 0;
395 global.ref = .{ .index = 0, .file = 0 };
401396 global.esym_index = esym_index;
402397 global.file_index = self.index;
403398 }
......@@ -405,19 +400,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
405400
406401pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
407402 const gpa = elf_file.base.comp.gpa;
408 for (self.atoms.items) |atom_index| {
409 const atom = elf_file.atom(atom_index) orelse continue;
410 if (!atom.flags.alive) continue;
411 const shdr = atom.inputShdr(elf_file);
403 for (self.atoms_indexes.items) |atom_index| {
404 const atom_ptr = self.atom(atom_index) orelse continue;
405 if (!atom_ptr.alive) continue;
406 const shdr = atom_ptr.inputShdr(elf_file);
412407 if (shdr.sh_type == elf.SHT_NOBITS) continue;
413 if (atom.scanRelocsRequiresCode(elf_file)) {
408 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
414409 // TODO ideally we don't have to fetch the code here.
415410 // Perhaps it would make sense to save the code until flushModule where we
416411 // would free all of generated code?
417412 const code = try self.codeAlloc(elf_file, atom_index);
418413 defer gpa.free(code);
419 try atom.scanRelocs(elf_file, code, undefs);
420 } else try atom.scanRelocs(elf_file, null, undefs);
414 try atom_ptr.scanRelocs(elf_file, code, undefs);
415 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
421416 }
422417}
423418
......@@ -450,9 +445,8 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
450445 esym.st_shndx == elf.SHN_COMMON) continue;
451446
452447 if (esym.st_shndx == SHN_ATOM) {
453 const atom_index = self.atoms.items[shndx];
454 const atom = elf_file.atom(atom_index) orelse continue;
455 if (!atom.flags.alive) continue;
448 const atom_ptr = self.atom(shndx) orelse continue;
449 if (!atom_ptr.alive) continue;
456450 }
457451
458452 const gop = try dupes.getOrPut(index);
......@@ -493,7 +487,7 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *
493487 const global = elf_file.symbol(global_index);
494488 const file_ptr = global.file(elf_file).?;
495489 assert(file_ptr.index() == self.index);
496 if (global.outputShndx() == null) continue;
490 if (global.outputShndx(elf_file) == null) continue;
497491
498492 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
499493 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
......@@ -517,20 +511,20 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
517511 try writer.writeAll(self.data.items);
518512}
519513
520pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
521 for (self.atoms.items) |atom_index| {
522 const atom = elf_file.atom(atom_index) orelse continue;
523 if (!atom.flags.alive) continue;
524 const rela_shndx = atom.relocsShndx() orelse continue;
514pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
515 for (self.atoms_indexes.items) |atom_index| {
516 const atom_ptr = self.atom(atom_index) orelse continue;
517 if (!atom_ptr.alive) continue;
518 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
525519 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
526520 if (self.relocs.items[rela_shndx].items.len == 0) continue;
527 const out_shndx = atom.outputShndx().?;
521 const out_shndx = atom_ptr.output_section_index;
528522 const out_shdr = elf_file.shdrs.items[out_shndx];
529523 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
530524
531525 const gpa = elf_file.base.comp.gpa;
532526 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
533 try sec.atom_list.append(gpa, atom_index);
527 try sec.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
534528 }
535529}
536530
......@@ -561,7 +555,7 @@ pub fn globals(self: ZigObject) []const Symbol.Index {
561555pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
562556 for (self.locals()) |local_index| {
563557 const local = elf_file.symbol(local_index);
564 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
558 if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
565559 const esym = local.elfSym(elf_file);
566560 switch (esym.st_type()) {
567561 elf.STT_SECTION, elf.STT_NOTYPE => continue,
......@@ -577,7 +571,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
577571 const global = elf_file.symbol(global_index);
578572 const file_ptr = global.file(elf_file) orelse continue;
579573 if (file_ptr.index() != self.index) continue;
580 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
574 if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
581575 global.flags.output_symtab = true;
582576 if (global.isLocal(elf_file)) {
583577 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
......@@ -621,11 +615,10 @@ pub fn asFile(self: *ZigObject) File {
621615
622616/// Returns atom's code.
623617/// Caller owns the memory.
624pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
618pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
625619 const gpa = elf_file.base.comp.gpa;
626 const atom = elf_file.atom(atom_index).?;
627 assert(atom.file_index == self.index);
628 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
620 const atom_ptr = self.atom(atom_index).?;
621 const shdr = &elf_file.shdrs.items[atom_ptr.output_section_index];
629622
630623 if (shdr.sh_flags & elf.SHF_TLS != 0) {
631624 const tlv = self.tls_variables.get(atom_index).?;
......@@ -633,13 +626,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
633626 return code;
634627 }
635628
636 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value));
637 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
629 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
630 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
638631 const code = try gpa.alloc(u8, size);
639632 errdefer gpa.free(code);
640633 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
641634 if (amt != code.len) {
642 log.err("fetching code for {s} failed", .{atom.name(elf_file)});
635 log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)});
643636 return error.InputOutput;
644637 }
645638 return code;
......@@ -760,7 +753,7 @@ pub fn getOrCreateMetadataForLazySymbol(
760753 };
761754 switch (metadata.state.*) {
762755 .unused => {
763 const symbol_index = try self.addAtom(elf_file);
756 const symbol_index = try self.newAtom(elf_file);
764757 const sym = elf_file.symbol(symbol_index);
765758 sym.flags.needs_zig_got = true;
766759 metadata.symbol_index.* = symbol_index;
......@@ -824,7 +817,7 @@ pub fn getOrCreateMetadataForDecl(
824817 const gop = try self.decls.getOrPut(gpa, decl_index);
825818 if (!gop.found_existing) {
826819 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
827 const symbol_index = try self.addAtom(elf_file);
820 const symbol_index = try self.newAtom(elf_file);
828821 const mod = elf_file.base.comp.module.?;
829822 const decl = mod.declPtr(decl_index);
830823 const sym = elf_file.symbol(symbol_index);
......@@ -861,14 +854,14 @@ fn getDeclShdrIndex(
861854 if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
862855 .type = elf.SHT_NOBITS,
863856 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
864 .name = ".tbss",
857 .name = try elf_file.insertShString(".tbss"),
865858 .offset = std.math.maxInt(u64),
866859 });
867860
868861 break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
869862 .type = elf.SHT_PROGBITS,
870863 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
871 .name = ".tdata",
864 .name = try elf_file.insertShString(".tdata"),
872865 .offset = std.math.maxInt(u64),
873866 });
874867 }
......@@ -919,14 +912,13 @@ fn updateDeclCode(
919912 const sym = elf_file.symbol(sym_index);
920913 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
921914 const atom_ptr = sym.atom(elf_file).?;
915 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
922916
923 sym.output_section_index = shdr_index;
917 atom_ptr.alive = true;
918 atom_ptr.name_offset = name_offset;
924919 atom_ptr.output_section_index = shdr_index;
925
926 sym.name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
927 atom_ptr.flags.alive = true;
928 atom_ptr.name_offset = sym.name_offset;
929 esym.st_name = sym.name_offset;
920 sym.name_offset = name_offset;
921 esym.st_name = name_offset;
930922 esym.st_info |= stt_bits;
931923 esym.st_size = code.len;
932924
......@@ -1018,16 +1010,17 @@ fn updateTlv(
10181010 const sym = elf_file.symbol(sym_index);
10191011 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
10201012 const atom_ptr = sym.atom(elf_file).?;
1013 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
10211014
10221015 sym.value = 0;
1023 sym.output_section_index = shndx;
1016 sym.name_offset = name_offset;
1017
10241018 atom_ptr.output_section_index = shndx;
1019 atom_ptr.alive = true;
1020 atom_ptr.name_offset = name_offset;
10251021
1026 sym.name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
1027 atom_ptr.flags.alive = true;
1028 atom_ptr.name_offset = sym.name_offset;
10291022 esym.st_value = 0;
1030 esym.st_name = sym.name_offset;
1023 esym.st_name = name_offset;
10311024 esym.st_info = elf.STT_TLS;
10321025 esym.st_size = code.len;
10331026
......@@ -1048,7 +1041,7 @@ fn updateTlv(
10481041 {
10491042 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
10501043 if (!gop.found_existing) gop.value_ptr.* = .{};
1051 try gop.value_ptr.append(gpa, atom_ptr.atom_index);
1044 try gop.value_ptr.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });
10521045 }
10531046}
10541047
......@@ -1242,13 +1235,12 @@ fn updateLazySymbol(
12421235 };
12431236 const local_sym = elf_file.symbol(symbol_index);
12441237 local_sym.name_offset = name_str_index;
1245 local_sym.output_section_index = output_section_index;
12461238 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
12471239 local_esym.st_name = name_str_index;
12481240 local_esym.st_info |= elf.STT_OBJECT;
12491241 local_esym.st_size = code.len;
12501242 const atom_ptr = local_sym.atom(elf_file).?;
1251 atom_ptr.flags.alive = true;
1243 atom_ptr.alive = true;
12521244 atom_ptr.name_offset = name_str_index;
12531245 atom_ptr.alignment = required_alignment;
12541246 atom_ptr.size = code.len;
......@@ -1307,8 +1299,7 @@ pub fn lowerUnnamedConst(
13071299 return error.CodegenFail;
13081300 },
13091301 };
1310 const sym = elf_file.symbol(sym_index);
1311 try unnamed_consts.append(gpa, sym.atom_index);
1302 try unnamed_consts.append(gpa, sym_index);
13121303 return sym_index;
13131304}
13141305
......@@ -1332,7 +1323,7 @@ fn lowerConst(
13321323 var code_buffer = std.ArrayList(u8).init(gpa);
13331324 defer code_buffer.deinit();
13341325
1335 const sym_index = try self.addAtom(elf_file);
1326 const sym_index = try self.newAtom(elf_file);
13361327
13371328 const res = try codegen.generateSymbol(
13381329 &elf_file.base,
......@@ -1351,13 +1342,12 @@ fn lowerConst(
13511342 const local_sym = elf_file.symbol(sym_index);
13521343 const name_str_index = try self.strtab.insert(gpa, name);
13531344 local_sym.name_offset = name_str_index;
1354 local_sym.output_section_index = output_section_index;
13551345 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
13561346 local_esym.st_name = name_str_index;
13571347 local_esym.st_info |= elf.STT_OBJECT;
13581348 local_esym.st_size = code.len;
13591349 const atom_ptr = local_sym.atom(elf_file).?;
1360 atom_ptr.flags.alive = true;
1350 atom_ptr.alive = true;
13611351 atom_ptr.name_offset = name_str_index;
13621352 atom_ptr.alignment = required_alignment;
13631353 atom_ptr.size = code.len;
......@@ -1530,6 +1520,72 @@ pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
15301520 return self.strtab.getAssumeExists(off);
15311521}
15321522
1523fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
1524 try self.atoms.ensureUnusedCapacity(allocator, 1);
1525 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1526 return self.addAtomAssumeCapacity();
1527}
1528
1529fn addAtomAssumeCapacity(self: *ZigObject) Atom.Index {
1530 const atom_index: Atom.Index = @intCast(self.atoms.items.len);
1531 const atom_ptr = self.atoms.addOneAssumeCapacity();
1532 atom_ptr.* = .{
1533 .file_index = self.index,
1534 .atom_index = atom_index,
1535 .extra_index = self.addAtomExtraAssumeCapacity(.{}),
1536 };
1537 return atom_index;
1538}
1539
1540pub fn atom(self: *ZigObject, atom_index: Atom.Index) ?*Atom {
1541 if (atom_index == 0) return null;
1542 assert(atom_index < self.atoms.items.len);
1543 return &self.atoms.items[atom_index];
1544}
1545
1546fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 {
1547 const fields = @typeInfo(Atom.Extra).Struct.fields;
1548 try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
1549 return self.addAtomExtraAssumeCapacity(extra);
1550}
1551
1552fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 {
1553 const index = @as(u32, @intCast(self.atoms_extra.items.len));
1554 const fields = @typeInfo(Atom.Extra).Struct.fields;
1555 inline for (fields) |field| {
1556 self.atoms_extra.appendAssumeCapacity(switch (field.type) {
1557 u32 => @field(extra, field.name),
1558 else => @compileError("bad field type"),
1559 });
1560 }
1561 return index;
1562}
1563
1564pub fn atomExtra(self: ZigObject, index: u32) Atom.Extra {
1565 const fields = @typeInfo(Atom.Extra).Struct.fields;
1566 var i: usize = index;
1567 var result: Atom.Extra = undefined;
1568 inline for (fields) |field| {
1569 @field(result, field.name) = switch (field.type) {
1570 u32 => self.atoms_extra.items[i],
1571 else => @compileError("bad field type"),
1572 };
1573 i += 1;
1574 }
1575 return result;
1576}
1577
1578pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
1579 assert(index > 0);
1580 const fields = @typeInfo(Atom.Extra).Struct.fields;
1581 inline for (fields, 0..) |field, i| {
1582 self.atoms_extra.items[index + i] = switch (field.type) {
1583 u32 => @field(extra, field.name),
1584 else => @compileError("bad field type"),
1585 };
1586 }
1587}
1588
15331589pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
15341590 return .{ .data = .{
15351591 .self = self,
......@@ -1578,9 +1634,9 @@ fn formatAtoms(
15781634 _ = unused_fmt_string;
15791635 _ = options;
15801636 try writer.writeAll(" atoms\n");
1581 for (ctx.self.atoms.items) |atom_index| {
1582 const atom = ctx.elf_file.atom(atom_index) orelse continue;
1583 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
1637 for (ctx.self.atoms_indexes.items) |atom_index| {
1638 const atom_ptr = ctx.self.atom(atom_index) orelse continue;
1639 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
15841640 }
15851641}
15861642
src/link/Elf/eh_frame.zig+3-3
......@@ -42,8 +42,8 @@ pub const Fde = struct {
4242 const object = elf_file.file(fde.file_index).?.object;
4343 const rel = fde.relocs(elf_file)[0];
4444 const sym = object.symtab.items[rel.r_sym()];
45 const atom_index = object.atoms.items[sym.st_shndx];
46 return elf_file.atom(atom_index).?;
45 const atom_index = object.atoms_indexes.items[sym.st_shndx];
46 return object.atom(atom_index).?;
4747 }
4848
4949 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
......@@ -421,7 +421,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re
421421 switch (sym.type(elf_file)) {
422422 elf.STT_SECTION => {
423423 r_addend += @intCast(sym.address(.{}, elf_file));
424 r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
424 r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
425425 },
426426 else => {
427427 r_sym = sym.outputSymtabIndex(elf_file) orelse 0;
src/link/Elf/file.zig+39-3
......@@ -98,11 +98,34 @@ pub const File = union(enum) {
9898 }
9999 }
100100
101 pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {
102 return switch (file) {
103 .shared_object => unreachable,
104 .linker_defined => null,
105 inline else => |x| x.atom(atom_index),
106 };
107 }
108
101109 pub fn atoms(file: File) []const Atom.Index {
102110 return switch (file) {
103 .linker_defined, .shared_object => &[0]Atom.Index{},
104 .zig_object => |x| x.atoms.items,
105 .object => |x| x.atoms.items,
111 .shared_object => unreachable,
112 .linker_defined => &[0]Atom.Index{},
113 .zig_object => |x| x.atoms_indexes.items,
114 .object => |x| x.atoms_indexes.items,
115 };
116 }
117
118 pub fn atomExtra(file: File, extra_index: u32) Atom.Extra {
119 return switch (file) {
120 .shared_object, .linker_defined => unreachable,
121 inline else => |x| x.atomExtra(extra_index),
122 };
123 }
124
125 pub fn setAtomExtra(file: File, extra_index: u32, extra: Atom.Extra) void {
126 return switch (file) {
127 .shared_object, .linker_defined => unreachable,
128 inline else => |x| x.setAtomExtra(extra_index, extra),
106129 };
107130 }
108131
......@@ -114,6 +137,13 @@ pub const File = union(enum) {
114137 };
115138 }
116139
140 pub fn comdatGroup(file: File, ind: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
141 return switch (file) {
142 .linker_defined, .shared_object, .zig_object => unreachable,
143 .object => |x| x.comdatGroup(ind),
144 };
145 }
146
117147 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
118148 return switch (file) {
119149 .zig_object => |x| x.symbol(ind),
......@@ -134,6 +164,12 @@ pub const File = union(enum) {
134164 };
135165 }
136166
167 pub fn getString(file: File, off: u32) [:0]const u8 {
168 return switch (file) {
169 inline else => |x| x.getString(off),
170 };
171 }
172
137173 pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
138174 return switch (file) {
139175 inline else => |x| x.updateSymtabSize(elf_file),
src/link/Elf/gc.zig+23-19
......@@ -16,9 +16,11 @@ pub fn gcAtoms(elf_file: *Elf) !void {
1616}
1717
1818fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {
19 if (elf_file.entry_index) |index| {
20 const global = elf_file.symbol(index);
21 try markSymbol(global, roots, elf_file);
19 if (elf_file.linkerDefinedPtr()) |obj| {
20 if (obj.entry_index) |index| {
21 const global = elf_file.symbol(index);
22 try markSymbol(global, roots, elf_file);
23 }
2224 }
2325
2426 for (files) |index| {
......@@ -35,8 +37,8 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
3537 const file = elf_file.file(index).?;
3638
3739 for (file.atoms()) |atom_index| {
38 const atom = elf_file.atom(atom_index) orelse continue;
39 if (!atom.flags.alive) continue;
40 const atom = file.atom(atom_index) orelse continue;
41 if (!atom.alive) continue;
4042
4143 const shdr = atom.inputShdr(elf_file);
4244 const name = atom.name(elf_file);
......@@ -54,7 +56,7 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
5456 break :blk false;
5557 };
5658 if (is_gc_root and markAtom(atom)) try roots.append(atom);
57 if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.flags.visited = true;
59 if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
5860 }
5961
6062 // Mark every atom referenced by CIE as alive.
......@@ -77,22 +79,22 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void
7779}
7880
7981fn markAtom(atom: *Atom) bool {
80 const already_visited = atom.flags.visited;
81 atom.flags.visited = true;
82 return atom.flags.alive and !already_visited;
82 const already_visited = atom.visited;
83 atom.visited = true;
84 return atom.alive and !already_visited;
8385}
8486
8587fn markLive(atom: *Atom, elf_file: *Elf) void {
8688 if (@import("build_options").enable_logging) track_live_level.incr();
8789
88 assert(atom.flags.visited);
90 assert(atom.visited);
8991 const file = atom.file(elf_file).?;
9092
9193 for (atom.fdes(elf_file)) |fde| {
9294 for (fde.relocs(elf_file)[1..]) |rel| {
9395 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
9496 const target_atom = target_sym.atom(elf_file) orelse continue;
95 target_atom.flags.alive = true;
97 target_atom.alive = true;
9698 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
9799 if (markAtom(target_atom)) markLive(target_atom, elf_file);
98100 }
......@@ -105,7 +107,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
105107 continue;
106108 }
107109 const target_atom = target_sym.atom(elf_file) orelse continue;
108 target_atom.flags.alive = true;
110 target_atom.alive = true;
109111 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
110112 if (markAtom(target_atom)) markLive(target_atom, elf_file);
111113 }
......@@ -120,10 +122,11 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
120122
121123fn prune(files: []const File.Index, elf_file: *Elf) void {
122124 for (files) |index| {
123 for (elf_file.file(index).?.atoms()) |atom_index| {
124 const atom = elf_file.atom(atom_index) orelse continue;
125 if (atom.flags.alive and !atom.flags.visited) {
126 atom.flags.alive = false;
125 const file = elf_file.file(index).?;
126 for (file.atoms()) |atom_index| {
127 const atom = file.atom(atom_index) orelse continue;
128 if (atom.alive and !atom.visited) {
129 atom.alive = false;
127130 atom.markFdesDead(elf_file);
128131 }
129132 }
......@@ -133,9 +136,10 @@ fn prune(files: []const File.Index, elf_file: *Elf) void {
133136pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
134137 const stderr = std.io.getStdErr().writer();
135138 for (elf_file.objects.items) |index| {
136 for (elf_file.file(index).?.object.atoms.items) |atom_index| {
137 const atom = elf_file.atom(atom_index) orelse continue;
138 if (!atom.flags.alive)
139 const file = elf_file.file(index).?;
140 for (file.atoms()) |atom_index| {
141 const atom = file.atom(atom_index) orelse continue;
142 if (!atom.alive)
139143 // TODO should we simply print to stderr?
140144 try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{
141145 atom.name(elf_file),
src/link/Elf/merge_section.zig+40-17
......@@ -10,16 +10,18 @@ pub const MergeSection = struct {
1010 IndexContext,
1111 std.hash_map.default_max_load_percentage,
1212 ) = .{},
13 subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},
13 subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
14 finalized_subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},
1415
1516 pub fn deinit(msec: *MergeSection, allocator: Allocator) void {
1617 msec.bytes.deinit(allocator);
1718 msec.table.deinit(allocator);
1819 msec.subsections.deinit(allocator);
20 msec.finalized_subsections.deinit(allocator);
1921 }
2022
2123 pub fn name(msec: MergeSection, elf_file: *Elf) [:0]const u8 {
22 return elf_file.strings.getAssumeExists(msec.name_offset);
24 return elf_file.getShString(msec.name_offset);
2325 }
2426
2527 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
......@@ -58,25 +60,26 @@ pub const MergeSection = struct {
5860
5961 /// Finalizes the merge section and clears hash table.
6062 /// Sorts all owned subsections.
61 pub fn finalize(msec: *MergeSection, elf_file: *Elf) !void {
62 const gpa = elf_file.base.comp.gpa;
63 try msec.subsections.ensureTotalCapacityPrecise(gpa, msec.table.count());
63 pub fn finalize(msec: *MergeSection, allocator: Allocator) !void {
64 try msec.finalized_subsections.ensureTotalCapacityPrecise(allocator, msec.subsections.items.len);
6465
6566 var it = msec.table.iterator();
6667 while (it.next()) |entry| {
67 const msub = elf_file.mergeSubsection(entry.value_ptr.*);
68 const msub = msec.mergeSubsection(entry.value_ptr.*);
6869 if (!msub.alive) continue;
69 msec.subsections.appendAssumeCapacity(entry.value_ptr.*);
70 msec.finalized_subsections.appendAssumeCapacity(entry.value_ptr.*);
7071 }
71 msec.table.clearAndFree(gpa);
72 msec.table.clearAndFree(allocator);
7273
7374 const sortFn = struct {
74 pub fn sortFn(ctx: *Elf, lhs: MergeSubsection.Index, rhs: MergeSubsection.Index) bool {
75 pub fn sortFn(ctx: *MergeSection, lhs: MergeSubsection.Index, rhs: MergeSubsection.Index) bool {
7576 const lhs_msub = ctx.mergeSubsection(lhs);
7677 const rhs_msub = ctx.mergeSubsection(rhs);
7778 if (lhs_msub.alignment.compareStrict(.eq, rhs_msub.alignment)) {
7879 if (lhs_msub.size == rhs_msub.size) {
79 return mem.order(u8, lhs_msub.getString(ctx), rhs_msub.getString(ctx)) == .lt;
80 const lhs_string = ctx.bytes.items[lhs_msub.string_index..][0..lhs_msub.size];
81 const rhs_string = ctx.bytes.items[rhs_msub.string_index..][0..rhs_msub.size];
82 return mem.order(u8, lhs_string, rhs_string) == .lt;
8083 }
8184 return lhs_msub.size < rhs_msub.size;
8285 }
......@@ -84,7 +87,19 @@ pub const MergeSection = struct {
8487 }
8588 }.sortFn;
8689
87 std.mem.sort(MergeSubsection.Index, msec.subsections.items, elf_file, sortFn);
90 std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
91 }
92
93 pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {
94 const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);
95 const msub = try msec.subsections.addOne(allocator);
96 msub.* = .{};
97 return index;
98 }
99
100 pub fn mergeSubsection(msec: *MergeSection, index: MergeSubsection.Index) *MergeSubsection {
101 assert(index < msec.subsections.items.len);
102 return &msec.subsections.items[index];
88103 }
89104
90105 pub const IndexContext = struct {
......@@ -154,8 +169,8 @@ pub const MergeSection = struct {
154169 msec.type,
155170 msec.flags,
156171 });
157 for (msec.subsections.items) |index| {
158 try writer.print(" {}\n", .{elf_file.mergeSubsection(index).fmt(elf_file)});
172 for (msec.subsections.items) |msub| {
173 try writer.print(" {}\n", .{msub.fmt(elf_file)});
159174 }
160175 }
161176
......@@ -250,18 +265,26 @@ pub const InputMergeSection = struct {
250265 // TODO: imsec.strings.clearAndFree(allocator);
251266 }
252267
253 pub fn findSubsection(imsec: InputMergeSection, offset: u32) ?struct { MergeSubsection.Index, u32 } {
268 const FindSubsectionResult = struct {
269 msub_index: MergeSubsection.Index,
270 offset: u32,
271 };
272
273 pub fn findSubsection(imsec: InputMergeSection, offset: u32) ?FindSubsectionResult {
254274 // TODO: binary search
255275 for (imsec.offsets.items, 0..) |off, index| {
256276 if (offset < off) return .{
257 imsec.subsections.items[index - 1],
258 offset - imsec.offsets.items[index - 1],
277 .msub_index = imsec.subsections.items[index - 1],
278 .offset = offset - imsec.offsets.items[index - 1],
259279 };
260280 }
261281 const last = imsec.offsets.items.len - 1;
262282 const last_off = imsec.offsets.items[last];
263283 const last_len = imsec.strings.items[last].len;
264 if (offset < last_off + last_len) return .{ imsec.subsections.items[last], offset - last_off };
284 if (offset < last_off + last_len) return .{
285 .msub_index = imsec.subsections.items[last],
286 .offset = offset - last_off,
287 };
265288 return null;
266289 }
267290
src/link/Elf/relocatable.zig+27-28
......@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
190190 // Now, we are ready to resolve the symbols across all input files.
191191 // We will first resolve the files in the ZigObject, next in the parsed
192192 // input Object files.
193 elf_file.resolveSymbols();
193 try elf_file.resolveSymbols();
194194 elf_file.markEhFrameAtomsDead();
195195 try elf_file.resolveMergeSections();
196196 try elf_file.addCommentString();
......@@ -299,13 +299,16 @@ fn initSections(elf_file: *Elf) !void {
299299 } else false;
300300 if (needs_eh_frame) {
301301 elf_file.eh_frame_section_index = try elf_file.addSection(.{
302 .name = ".eh_frame",
302 .name = try elf_file.insertShString(".eh_frame"),
303303 .type = elf.SHT_PROGBITS,
304304 .flags = elf.SHF_ALLOC,
305305 .addralign = ptr_size,
306306 .offset = std.math.maxInt(u64),
307307 });
308 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(".rela.eh_frame", elf_file.eh_frame_section_index.?);
308 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
309 try elf_file.insertShString(".rela.eh_frame"),
310 elf_file.eh_frame_section_index.?,
311 );
309312 }
310313
311314 try initComdatGroups(elf_file);
......@@ -318,22 +321,18 @@ fn initComdatGroups(elf_file: *Elf) !void {
318321
319322 for (elf_file.objects.items) |index| {
320323 const object = elf_file.file(index).?.object;
321
322 for (object.comdat_groups.items) |cg_index| {
323 const cg = elf_file.comdatGroup(cg_index);
324 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
325 if (cg_owner.file != index) continue;
326
324 for (object.comdat_groups.items, 0..) |cg, cg_index| {
325 if (!cg.alive) continue;
327326 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);
328327 cg_sec.* = .{
329328 .shndx = try elf_file.addSection(.{
330 .name = ".group",
329 .name = try elf_file.insertShString(".group"),
331330 .type = elf.SHT_GROUP,
332331 .entsize = @sizeOf(u32),
333332 .addralign = @alignOf(u32),
334333 .offset = std.math.maxInt(u64),
335334 }),
336 .cg_index = cg_index,
335 .cg_ref = .{ .index = @intCast(cg_index), .file = index },
337336 };
338337 }
339338 }
......@@ -342,9 +341,9 @@ fn initComdatGroups(elf_file: *Elf) !void {
342341fn updateSectionSizes(elf_file: *Elf) !void {
343342 for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| {
344343 const shdr = &elf_file.shdrs.items[shndx];
345 for (atom_list.items) |atom_index| {
346 const atom_ptr = elf_file.atom(atom_index) orelse continue;
347 if (!atom_ptr.flags.alive) continue;
344 for (atom_list.items) |ref| {
345 const atom_ptr = elf_file.atom(ref) orelse continue;
346 if (!atom_ptr.alive) continue;
348347 const offset = atom_ptr.alignment.forward(shdr.sh_size);
349348 const padding = offset - shdr.sh_size;
350349 atom_ptr.value = @intCast(offset);
......@@ -355,9 +354,9 @@ fn updateSectionSizes(elf_file: *Elf) !void {
355354
356355 for (elf_file.output_rela_sections.values()) |sec| {
357356 const shdr = &elf_file.shdrs.items[sec.shndx];
358 for (sec.atom_list.items) |atom_index| {
359 const atom_ptr = elf_file.atom(atom_index) orelse continue;
360 if (!atom_ptr.flags.alive) continue;
357 for (sec.atom_list.items) |ref| {
358 const atom_ptr = elf_file.atom(ref) orelse continue;
359 if (!atom_ptr.alive) continue;
361360 const relocs = atom_ptr.relocs(elf_file);
362361 shdr.sh_size += shdr.sh_entsize * relocs.len;
363362 }
......@@ -386,7 +385,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
386385
387386 const sym = elf_file.symbol(cg.symbol(elf_file));
388387 shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse
389 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
388 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
390389 }
391390}
392391
......@@ -449,16 +448,16 @@ fn writeAtoms(elf_file: *Elf) !void {
449448 0;
450449 @memset(buffer, padding_byte);
451450
452 for (atom_list.items) |atom_index| {
453 const atom_ptr = elf_file.atom(atom_index).?;
454 assert(atom_ptr.flags.alive);
451 for (atom_list.items) |ref| {
452 const atom_ptr = elf_file.atom(ref).?;
453 assert(atom_ptr.alive);
455454
456455 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
457456 return error.Overflow;
458457 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
459458
460 log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{
461 atom_index,
459 log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
460 ref,
462461 sh_offset + offset,
463462 sh_offset + offset + size,
464463 });
......@@ -466,8 +465,8 @@ fn writeAtoms(elf_file: *Elf) !void {
466465 // TODO decompress directly into provided buffer
467466 const out_code = buffer[offset..][0..size];
468467 const in_code = switch (atom_ptr.file(elf_file).?) {
469 .object => |x| try x.codeDecompressAlloc(elf_file, atom_index),
470 .zig_object => |x| try x.codeAlloc(elf_file, atom_index),
468 .object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
469 .zig_object => |x| try x.codeAlloc(elf_file, ref.index),
471470 else => unreachable,
472471 };
473472 defer gpa.free(in_code);
......@@ -491,9 +490,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
491490 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
492491 defer relocs.deinit();
493492
494 for (sec.atom_list.items) |atom_index| {
495 const atom_ptr = elf_file.atom(atom_index) orelse continue;
496 if (!atom_ptr.flags.alive) continue;
493 for (sec.atom_list.items) |ref| {
494 const atom_ptr = elf_file.atom(ref) orelse continue;
495 if (!atom_ptr.alive) continue;
497496 try atom_ptr.writeRelocs(elf_file, &relocs);
498497 }
499498 assert(relocs.items.len == num_relocs);
src/link/Elf/synthetic_sections.zig+16-17
......@@ -1075,7 +1075,7 @@ pub const GotPltSection = struct {
10751075 _ = got_plt;
10761076 {
10771077 // [0]: _DYNAMIC
1078 const symbol = elf_file.symbol(elf_file.dynamic_index.?);
1078 const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?);
10791079 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
10801080 }
10811081 // [1]: 0x0
......@@ -1670,45 +1670,44 @@ pub const VerneedSection = struct {
16701670
16711671pub const ComdatGroupSection = struct {
16721672 shndx: u32,
1673 cg_index: u32,
1673 cg_ref: Elf.Ref,
16741674
1675 fn file(cgs: ComdatGroupSection, elf_file: *Elf) ?File {
1676 const cg = elf_file.comdatGroup(cgs.cg_index);
1677 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
1678 return elf_file.file(cg_owner.file);
1675 fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {
1676 const cg_file = elf_file.file(cgs.cg_ref.file).?;
1677 return cg_file.object.comdatGroup(cgs.cg_ref.index);
16791678 }
16801679
16811680 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
1682 const cg = elf_file.comdatGroup(cgs.cg_index);
1683 const object = cgs.file(elf_file).?.object;
1681 const cg = cgs.comdatGroup(elf_file);
1682 const object = cg.file(elf_file).object;
16841683 const shdr = object.shdrs.items[cg.shndx];
16851684 return object.symbols.items[shdr.sh_info];
16861685 }
16871686
16881687 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
1689 const cg = elf_file.comdatGroup(cgs.cg_index);
1688 const cg = cgs.comdatGroup(elf_file);
16901689 const members = cg.comdatGroupMembers(elf_file);
16911690 return (members.len + 1) * @sizeOf(u32);
16921691 }
16931692
16941693 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
1695 const cg = elf_file.comdatGroup(cgs.cg_index);
1696 const object = cgs.file(elf_file).?.object;
1694 const cg = cgs.comdatGroup(elf_file);
1695 const object = cg.file(elf_file).object;
16971696 const members = cg.comdatGroupMembers(elf_file);
16981697 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
16991698 for (members) |shndx| {
17001699 const shdr = object.shdrs.items[shndx];
17011700 switch (shdr.sh_type) {
17021701 elf.SHT_RELA => {
1703 const atom_index = object.atoms.items[shdr.sh_info];
1704 const atom = elf_file.atom(atom_index).?;
1705 const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;
1702 const atom_index = object.atoms_indexes.items[shdr.sh_info];
1703 const atom = object.atom(atom_index).?;
1704 const rela = elf_file.output_rela_sections.get(atom.output_section_index).?;
17061705 try writer.writeInt(u32, rela.shndx, .little);
17071706 },
17081707 else => {
1709 const atom_index = object.atoms.items[shndx];
1710 const atom = elf_file.atom(atom_index).?;
1711 try writer.writeInt(u32, atom.outputShndx().?, .little);
1708 const atom_index = object.atoms_indexes.items[shndx];
1709 const atom = object.atom(atom_index).?;
1710 try writer.writeInt(u32, atom.output_section_index, .little);
17121711 },
17131712 }
17141713 }
src/link/Elf/thunks.zig+9-11
......@@ -6,22 +6,21 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
66 const atoms = elf_file.output_sections.get(shndx).?.items;
77 assert(atoms.len > 0);
88
9 for (atoms) |atom_index| {
10 elf_file.atom(atom_index).?.value = -1;
9 for (atoms) |ref| {
10 elf_file.atom(ref).?.value = -1;
1111 }
1212
1313 var i: usize = 0;
1414 while (i < atoms.len) {
1515 const start = i;
1616 const start_atom = elf_file.atom(atoms[start]).?;
17 assert(start_atom.flags.alive);
17 assert(start_atom.alive);
1818 start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment);
1919 i += 1;
2020
2121 while (i < atoms.len) : (i += 1) {
22 const atom_index = atoms[i];
23 const atom = elf_file.atom(atom_index).?;
24 assert(atom.flags.alive);
22 const atom = elf_file.atom(atoms[i]).?;
23 assert(atom.alive);
2524 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
2625 break;
2726 atom.value = try advance(shdr, atom.size, atom.alignment);
......@@ -33,10 +32,10 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
3332 thunk.output_section_index = shndx;
3433
3534 // Scan relocs in the group and create trampolines for any unreachable callsite
36 for (atoms[start..i]) |atom_index| {
37 const atom = elf_file.atom(atom_index).?;
35 for (atoms[start..i]) |ref| {
36 const atom = elf_file.atom(ref).?;
3837 const file = atom.file(elf_file).?;
39 log.debug("atom({d}) {s}", .{ atom_index, atom.name(elf_file) });
38 log.debug("atom({}) {s}", .{ ref, atom.name(elf_file) });
4039 for (atom.relocs(elf_file)) |rel| {
4140 const is_reachable = switch (cpu_arch) {
4241 .aarch64 => aarch64.isReachable(atom, rel, elf_file),
......@@ -51,8 +50,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
5150 };
5251 try thunk.symbols.put(gpa, target, {});
5352 }
54 try atom.addExtra(.{ .thunk = thunk_index }, elf_file);
55 atom.flags.thunk = true;
53 atom.addExtra(.{ .thunk = thunk_index }, elf_file);
5654 }
5755
5856 thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
src/link/MachO/InternalObject.zig+1-2
......@@ -45,8 +45,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
4545
4646pub fn init(self: *InternalObject, allocator: Allocator) !void {
4747 // Atom at index 0 is reserved as null atom.
48 try self.atoms.append(allocator, .{});
49 try self.atoms_extra.append(allocator, 0);
48 try self.atoms.append(allocator, .{ .extra = try self.addAtomExtra(allocator, .{}) });
5049 // Null byte in strtab
5150 try self.strtab.append(allocator, 0);
5251}
src/link/MachO/ZigObject.zig+1-1
......@@ -1634,7 +1634,7 @@ fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {
16341634
16351635fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
16361636 try self.atoms.ensureUnusedCapacity(allocator, 1);
1637 try self.atoms_extra.ensureUnusedCapacity(allocator, 1);
1637 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
16381638 return self.addAtomAssumeCapacity();
16391639}
16401640
test/link/elf.zig+104
......@@ -59,6 +59,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
5959 // Exercise linker with LLVM backend
6060 // musl tests
6161 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));
62 elf_step.dependOn(testComdatElimination(b, .{ .target = musl_target }));
6263 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));
6364 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));
6465 elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));
......@@ -368,6 +369,109 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
368369 return test_step;
369370}
370371
372fn testComdatElimination(b: *Build, opts: Options) *Step {
373 const test_step = addTestStep(b, "comdat-elimination", opts);
374
375 const a_o = addObject(b, opts, .{
376 .name = "a",
377 .cpp_source_bytes =
378 \\#include <stdio.h>
379 \\inline void foo() {
380 \\ printf("calling foo in a\n");
381 \\}
382 \\void hello() {
383 \\ foo();
384 \\}
385 ,
386 });
387 a_o.linkLibCpp();
388
389 const main_o = addObject(b, opts, .{
390 .name = "main",
391 .cpp_source_bytes =
392 \\#include <stdio.h>
393 \\inline void foo() {
394 \\ printf("calling foo in main\n");
395 \\}
396 \\void hello();
397 \\int main() {
398 \\ foo();
399 \\ hello();
400 \\ return 0;
401 \\}
402 ,
403 });
404 main_o.linkLibCpp();
405
406 {
407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 exe.addObject(a_o);
409 exe.addObject(main_o);
410 exe.linkLibCpp();
411
412 const run = addRunArtifact(exe);
413 run.expectStdOutEqual(
414 \\calling foo in a
415 \\calling foo in a
416 \\
417 );
418 test_step.dependOn(&run.step);
419 }
420
421 {
422 const exe = addExecutable(b, opts, .{ .name = "main2" });
423 exe.addObject(main_o);
424 exe.addObject(a_o);
425 exe.linkLibCpp();
426
427 const run = addRunArtifact(exe);
428 run.expectStdOutEqual(
429 \\calling foo in main
430 \\calling foo in main
431 \\
432 );
433 test_step.dependOn(&run.step);
434 }
435
436 {
437 const c_o = addObject(b, opts, .{ .name = "c" });
438 c_o.addObject(main_o);
439 c_o.addObject(a_o);
440
441 const exe = addExecutable(b, opts, .{ .name = "main3" });
442 exe.addObject(c_o);
443 exe.linkLibCpp();
444
445 const run = addRunArtifact(exe);
446 run.expectStdOutEqual(
447 \\calling foo in main
448 \\calling foo in main
449 \\
450 );
451 test_step.dependOn(&run.step);
452 }
453
454 {
455 const d_o = addObject(b, opts, .{ .name = "d" });
456 d_o.addObject(a_o);
457 d_o.addObject(main_o);
458
459 const exe = addExecutable(b, opts, .{ .name = "main4" });
460 exe.addObject(d_o);
461 exe.linkLibCpp();
462
463 const run = addRunArtifact(exe);
464 run.expectStdOutEqual(
465 \\calling foo in a
466 \\calling foo in a
467 \\
468 );
469 test_step.dependOn(&run.step);
470 }
471
472 return test_step;
473}
474
371475fn testCommentString(b: *Build, opts: Options) *Step {
372476 const test_step = addTestStep(b, "comment-string", opts);
373477