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) = .{},...@@ -54,7 +54,7 @@ phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
54shdr_table_offset: ?u64 = null,54shdr_table_offset: ?u64 = null,
55/// Table of lists of atoms per output section.55/// Table of lists of atoms per output section.
56/// This table is not used to track incrementally generated atoms.56/// 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)) = .{},
58output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},58output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},
5959
60/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.60/// 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,...@@ -93,7 +93,6 @@ phdr_gnu_stack_index: ?u16 = null,
93/// TODO I think ELF permits multiple TLS segments but for now, assume one per file.93/// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
94phdr_tls_index: ?u16 = null,94phdr_tls_index: ?u16 = null,
9595
96entry_index: ?Symbol.Index = null,
97page_size: u32,96page_size: u32,
98default_sym_version: elf.Elf64_Versym,97default_sym_version: elf.Elf64_Versym,
9998
...@@ -174,25 +173,6 @@ shstrtab_section_index: ?u32 = null,...@@ -174,25 +173,6 @@ shstrtab_section_index: ?u32 = null,
174strtab_section_index: ?u32 = null,173strtab_section_index: ?u32 = null,
175symtab_section_index: ?u32 = null,174symtab_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
196/// An array of symbols parsed across all input files.176/// An array of symbols parsed across all input files.
197symbols: std.ArrayListUnmanaged(Symbol) = .{},177symbols: std.ArrayListUnmanaged(Symbol) = .{},
198symbols_extra: std.ArrayListUnmanaged(u32) = .{},178symbols_extra: std.ArrayListUnmanaged(u32) = .{},
...@@ -203,30 +183,17 @@ resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},...@@ -203,30 +183,17 @@ resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
203has_text_reloc: bool = false,183has_text_reloc: bool = false,
204num_ifunc_dynrelocs: usize = 0,184num_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
210/// List of range extension thunks.186/// List of range extension thunks.
211thunks: std.ArrayListUnmanaged(Thunk) = .{},187thunks: std.ArrayListUnmanaged(Thunk) = .{},
212188
213/// List of output merge sections with deduped contents.189/// List of output merge sections with deduped contents.
214merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},190merge_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
221/// Table of last atom index in a section and matching atom free list if any.192/// Table of last atom index in a section and matching atom free list if any.
222last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},193last_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
228/// Global string table used to provide quick access to global symbol resolvers195/// Global string table used to provide quick access to global symbol resolvers
229/// such as `resolver` and `comdat_groups_table`.196/// such as `resolver`.
230strings: StringTable = .{},197strings: StringTable = .{},
231198
232first_eflags: ?elf.Elf64_Word = null,199first_eflags: ?elf.Elf64_Word = null,
...@@ -378,20 +345,15 @@ pub fn createEmpty(...@@ -378,20 +345,15 @@ pub fn createEmpty(
378 try self.symbols.append(gpa, .{});345 try self.symbols.append(gpa, .{});
379 // Index 0 is always a null symbol.346 // Index 0 is always a null symbol.
380 try self.symbols_extra.append(gpa, 0);347 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);
384 // Append null file at index 0348 // Append null file at index 0
385 try self.files.append(gpa, .null);349 try self.files.append(gpa, .null);
386 // Append null byte to string tables350 // Append null byte to string tables
387 try self.shstrtab.append(gpa, 0);351 try self.shstrtab.append(gpa, 0);
388 try self.strtab.append(gpa, 0);352 try self.strtab.append(gpa, 0);
389 // There must always be a null shdr in index 0353 // There must always be a null shdr in index 0
390 _ = try self.addSection(.{ .name = "" });354 _ = try self.addSection(.{});
391 // Append null symbol in output symtab355 // Append null symbol in output symtab
392 try self.symtab.append(gpa, null_sym);356 try self.symtab.append(gpa, null_sym);
393 // Append null input merge section.
394 try self.merge_input_sections.append(gpa, .{});
395357
396 if (!is_obj_or_ar) {358 if (!is_obj_or_ar) {
397 try self.dynstrtab.append(gpa, 0);359 try self.dynstrtab.append(gpa, 0);
...@@ -502,10 +464,7 @@ pub fn deinit(self: *Elf) void {...@@ -502,10 +464,7 @@ pub fn deinit(self: *Elf) void {
502 self.symbols_extra.deinit(gpa);464 self.symbols_extra.deinit(gpa);
503 self.symbols_free_list.deinit(gpa);465 self.symbols_free_list.deinit(gpa);
504 self.resolver.deinit(gpa);466 self.resolver.deinit(gpa);
505 self.start_stop_indexes.deinit(gpa);
506467
507 self.atoms.deinit(gpa);
508 self.atoms_extra.deinit(gpa);
509 for (self.thunks.items) |*th| {468 for (self.thunks.items) |*th| {
510 th.deinit(gpa);469 th.deinit(gpa);
511 }470 }
...@@ -514,19 +473,11 @@ pub fn deinit(self: *Elf) void {...@@ -514,19 +473,11 @@ pub fn deinit(self: *Elf) void {
514 sect.deinit(gpa);473 sect.deinit(gpa);
515 }474 }
516 self.merge_sections.deinit(gpa);475 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);
522 for (self.last_atom_and_free_list_table.values()) |*value| {476 for (self.last_atom_and_free_list_table.values()) |*value| {
523 value.free_list.deinit(gpa);477 value.free_list.deinit(gpa);
524 }478 }
525 self.last_atom_and_free_list_table.deinit(gpa);479 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);
530 self.strings.deinit(gpa);481 self.strings.deinit(gpa);
531482
532 self.got.deinit(gpa);483 self.got.deinit(gpa);
...@@ -744,7 +695,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -744,7 +695,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
744695
745 if (self.zig_text_section_index == null) {696 if (self.zig_text_section_index == null) {
746 self.zig_text_section_index = try self.addSection(.{697 self.zig_text_section_index = try self.addSection(.{
747 .name = ".text.zig",698 .name = try self.insertShString(".text.zig"),
748 .type = elf.SHT_PROGBITS,699 .type = elf.SHT_PROGBITS,
749 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,700 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
750 .addralign = 1,701 .addralign = 1,
...@@ -753,7 +704,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -753,7 +704,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
753 const shdr = &self.shdrs.items[self.zig_text_section_index.?];704 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
754 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);705 fillSection(self, shdr, options.program_code_size_hint, self.phdr_zig_load_re_index);
755 if (self.base.isRelocatable()) {706 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.?);
757 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{708 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
758 .shndx = rela_shndx,709 .shndx = rela_shndx,
759 });710 });
...@@ -770,7 +721,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -770,7 +721,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
770721
771 if (self.zig_got_section_index == null and !self.base.isRelocatable()) {722 if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
772 self.zig_got_section_index = try self.addSection(.{723 self.zig_got_section_index = try self.addSection(.{
773 .name = ".got.zig",724 .name = try self.insertShString(".got.zig"),
774 .type = elf.SHT_PROGBITS,725 .type = elf.SHT_PROGBITS,
775 .addralign = ptr_size,726 .addralign = ptr_size,
776 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,727 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
...@@ -791,7 +742,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -791,7 +742,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
791742
792 if (self.zig_data_rel_ro_section_index == null) {743 if (self.zig_data_rel_ro_section_index == null) {
793 self.zig_data_rel_ro_section_index = try self.addSection(.{744 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"),
795 .type = elf.SHT_PROGBITS,746 .type = elf.SHT_PROGBITS,
796 .addralign = 1,747 .addralign = 1,
797 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,748 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
...@@ -801,7 +752,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -801,7 +752,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
801 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);752 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
802 if (self.base.isRelocatable()) {753 if (self.base.isRelocatable()) {
803 const rela_shndx = try self.addRelaShdr(754 const rela_shndx = try self.addRelaShdr(
804 ".rela.data.rel.ro.zig",755 try self.insertShString(".rela.data.rel.ro.zig"),
805 self.zig_data_rel_ro_section_index.?,756 self.zig_data_rel_ro_section_index.?,
806 );757 );
807 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{758 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 {...@@ -820,7 +771,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
820771
821 if (self.zig_data_section_index == null) {772 if (self.zig_data_section_index == null) {
822 self.zig_data_section_index = try self.addSection(.{773 self.zig_data_section_index = try self.addSection(.{
823 .name = ".data.zig",774 .name = try self.insertShString(".data.zig"),
824 .type = elf.SHT_PROGBITS,775 .type = elf.SHT_PROGBITS,
825 .addralign = ptr_size,776 .addralign = ptr_size,
826 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,777 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
...@@ -830,7 +781,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -830,7 +781,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
830 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);781 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
831 if (self.base.isRelocatable()) {782 if (self.base.isRelocatable()) {
832 const rela_shndx = try self.addRelaShdr(783 const rela_shndx = try self.addRelaShdr(
833 ".rela.data.zig",784 try self.insertShString(".rela.data.zig"),
834 self.zig_data_section_index.?,785 self.zig_data_section_index.?,
835 );786 );
836 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{787 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{
...@@ -849,7 +800,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -849,7 +800,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
849800
850 if (self.zig_bss_section_index == null) {801 if (self.zig_bss_section_index == null) {
851 self.zig_bss_section_index = try self.addSection(.{802 self.zig_bss_section_index = try self.addSection(.{
852 .name = ".bss.zig",803 .name = try self.insertShString(".bss.zig"),
853 .type = elf.SHT_NOBITS,804 .type = elf.SHT_NOBITS,
854 .addralign = ptr_size,805 .addralign = ptr_size,
855 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,806 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
...@@ -873,7 +824,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -873,7 +824,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
873 assert(dw.strtab.buffer.items.len == 0);824 assert(dw.strtab.buffer.items.len == 0);
874 try dw.strtab.buffer.append(gpa, 0);825 try dw.strtab.buffer.append(gpa, 0);
875 self.debug_str_section_index = try self.addSection(.{826 self.debug_str_section_index = try self.addSection(.{
876 .name = ".debug_str",827 .name = try self.insertShString(".debug_str"),
877 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,828 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
878 .entsize = 1,829 .entsize = 1,
879 .type = elf.SHT_PROGBITS,830 .type = elf.SHT_PROGBITS,
...@@ -891,7 +842,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -891,7 +842,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
891842
892 if (self.debug_info_section_index == null) {843 if (self.debug_info_section_index == null) {
893 self.debug_info_section_index = try self.addSection(.{844 self.debug_info_section_index = try self.addSection(.{
894 .name = ".debug_info",845 .name = try self.insertShString(".debug_info"),
895 .type = elf.SHT_PROGBITS,846 .type = elf.SHT_PROGBITS,
896 .addralign = 1,847 .addralign = 1,
897 .offset = std.math.maxInt(u64),848 .offset = std.math.maxInt(u64),
...@@ -907,7 +858,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -907,7 +858,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
907858
908 if (self.debug_abbrev_section_index == null) {859 if (self.debug_abbrev_section_index == null) {
909 self.debug_abbrev_section_index = try self.addSection(.{860 self.debug_abbrev_section_index = try self.addSection(.{
910 .name = ".debug_abbrev",861 .name = try self.insertShString(".debug_abbrev"),
911 .type = elf.SHT_PROGBITS,862 .type = elf.SHT_PROGBITS,
912 .addralign = 1,863 .addralign = 1,
913 .offset = std.math.maxInt(u64),864 .offset = std.math.maxInt(u64),
...@@ -923,7 +874,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -923,7 +874,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
923874
924 if (self.debug_aranges_section_index == null) {875 if (self.debug_aranges_section_index == null) {
925 self.debug_aranges_section_index = try self.addSection(.{876 self.debug_aranges_section_index = try self.addSection(.{
926 .name = ".debug_aranges",877 .name = try self.insertShString(".debug_aranges"),
927 .type = elf.SHT_PROGBITS,878 .type = elf.SHT_PROGBITS,
928 .addralign = 16,879 .addralign = 16,
929 .offset = std.math.maxInt(u64),880 .offset = std.math.maxInt(u64),
...@@ -939,7 +890,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {...@@ -939,7 +890,7 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
939890
940 if (self.debug_line_section_index == null) {891 if (self.debug_line_section_index == null) {
941 self.debug_line_section_index = try self.addSection(.{892 self.debug_line_section_index = try self.addSection(.{
942 .name = ".debug_line",893 .name = try self.insertShString(".debug_line"),
943 .type = elf.SHT_PROGBITS,894 .type = elf.SHT_PROGBITS,
944 .addralign = 1,895 .addralign = 1,
945 .offset = std.math.maxInt(u64),896 .offset = std.math.maxInt(u64),
...@@ -1315,6 +1266,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1315,6 +1266,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1315 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1266 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1316 self.files.set(index, .{ .linker_defined = .{ .index = index } });1267 self.files.set(index, .{ .linker_defined = .{ .index = index } });
1317 self.linker_defined_index = index;1268 self.linker_defined_index = index;
1269 const object = self.linkerDefinedPtr().?;
1270 try object.init(gpa);
1271 try object.initSymbols(self);
1318 }1272 }
13191273
1320 // Now, we are ready to resolve the symbols across all input files.1274 // 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...@@ -1322,20 +1276,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1322 // input Object files.1276 // input Object files.
1323 // Any qualifing unresolved symbol will be upgraded to an absolute, weak1277 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1324 // symbol for potential resolution at load-time.1278 // symbol for potential resolution at load-time.
1325 self.resolveSymbols();1279 try self.resolveSymbols();
1326 self.markEhFrameAtomsDead();1280 self.markEhFrameAtomsDead();
1327 try self.resolveMergeSections();1281 try self.resolveMergeSections();
13281282
1329 try self.convertCommonSymbols();1283 try self.convertCommonSymbols();
1330 self.markImportsExports();1284 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
1339 if (self.base.gc_sections) {1286 if (self.base.gc_sections) {
1340 try gc.gcAtoms(self);1287 try gc.gcAtoms(self);
13411288
...@@ -1353,7 +1300,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1353,7 +1300,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1353 try self.finalizeMergeSections();1300 try self.finalizeMergeSections();
1354 try self.initOutputSections();1301 try self.initOutputSections();
1355 try self.initMergeSections();1302 try self.initMergeSections();
1356 try self.addLinkerDefinedSymbols();
1357 self.claimUnresolved();1303 self.claimUnresolved();
13581304
1359 // Scan and create missing synthetic entries such as GOT indirection.1305 // 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...@@ -1379,7 +1325,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1379 try self.sortPhdrs();1325 try self.sortPhdrs();
1380 try self.allocateNonAllocSections();1326 try self.allocateNonAllocSections();
1381 self.allocateSpecialPhdrs();1327 self.allocateSpecialPhdrs();
1382 self.allocateLinkerDefinedSymbols();1328 if (self.linkerDefinedPtr()) |obj| {
1329 obj.allocateSymbols(self);
1330 }
13831331
1384 // Dump the state for easy debugging.1332 // Dump the state for easy debugging.
1385 // State can be dumped via `--debug-log link_state`.1333 // 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...@@ -1389,15 +1337,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
13891337
1390 // Beyond this point, everything has been allocated a virtual address and we can resolve1338 // Beyond this point, everything has been allocated a virtual address and we can resolve
1391 // the relocations, and commit objects to file.1339 // the relocations, and commit objects to file.
1392 if (self.zigObjectPtr()) |zig_object| {1340 if (self.zigObjectPtr()) |zo| {
1393 var has_reloc_errors = false;1341 var has_reloc_errors = false;
1394 for (zig_object.atoms.items) |atom_index| {1342 for (zo.atoms_indexes.items) |atom_index| {
1395 const atom_ptr = self.atom(atom_index) orelse continue;1343 const atom_ptr = zo.atom(atom_index) orelse continue;
1396 if (!atom_ptr.flags.alive) continue;1344 if (!atom_ptr.alive) continue;
1397 const out_shndx = atom_ptr.outputShndx() orelse continue;1345 const out_shndx = atom_ptr.output_section_index;
1398 const shdr = &self.shdrs.items[out_shndx];1346 const shdr = &self.shdrs.items[out_shndx];
1399 if (shdr.sh_type == elf.SHT_NOBITS) continue;1347 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);
1401 defer gpa.free(code);1349 defer gpa.free(code);
1402 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));1350 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
1403 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {1351 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...@@ -1427,7 +1375,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1427 else => |e| return e,1375 else => |e| return e,
1428 };1376 };
14291377
1430 if (self.entry_index == null and self.base.isExe()) {1378 if (self.base.isExe() and self.linkerDefinedPtr().?.entry_index == null) {
1431 log.debug("flushing. no_entry_point_found = true", .{});1379 log.debug("flushing. no_entry_point_found = true", .{});
1432 comp.link_error_flags.no_entry_point_found = true;1380 comp.link_error_flags.no_entry_point_found = true;
1433 } else {1381 } else {
...@@ -1972,12 +1920,13 @@ fn accessLibPath(...@@ -1972,12 +1920,13 @@ fn accessLibPath(
1972/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.1920/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
1973/// 5. Remove references to dead objects/shared objects1921/// 5. Remove references to dead objects/shared objects
1974/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1922/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1975pub fn resolveSymbols(self: *Elf) void {1923pub fn resolveSymbols(self: *Elf) !void {
1976 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1924 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1977 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1925 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
1978 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1926 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1979 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1927 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1980 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1928 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
1929 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
19811930
1982 // Mark live objects.1931 // Mark live objects.
1983 self.markLive();1932 self.markLive();
...@@ -1986,6 +1935,7 @@ pub fn resolveSymbols(self: *Elf) void {...@@ -1986,6 +1935,7 @@ pub fn resolveSymbols(self: *Elf) void {
1986 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);1935 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
1987 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);1936 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1988 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);1937 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
1938 if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
19891939
1990 // Prune dead objects and shared objects.1940 // Prune dead objects and shared objects.
1991 var i: usize = 0;1941 var i: usize = 0;
...@@ -2003,41 +1953,25 @@ pub fn resolveSymbols(self: *Elf) void {...@@ -2003,41 +1953,25 @@ pub fn resolveSymbols(self: *Elf) void {
2003 } else i += 1;1953 } else i += 1;
2004 }1954 }
20051955
2006 // Dedup comdat groups.1956 {
2007 for (self.objects.items) |index| {1957 // Dedup comdat groups.
2008 const object = self.file(index).?.object;1958 var table = std.StringHashMap(Ref).init(self.base.comp.gpa);
2009 for (object.comdat_groups.items) |cg_index| {1959 defer table.deinit();
2010 const cg = self.comdatGroup(cg_index);1960
2011 const cg_owner = self.comdatGroupOwner(cg.owner);1961 for (self.objects.items) |index| {
2012 const owner_file_index = if (self.file(cg_owner.file)) |file_ptr|1962 try self.file(index).?.object.resolveComdatGroups(self, &table);
2013 file_ptr.object.index
2014 else
2015 std.math.maxInt(File.Index);
2016 cg_owner.file = @min(owner_file_index, index);
2017 }1963 }
2018 }
20191964
2020 for (self.objects.items) |index| {1965 for (self.objects.items) |index| {
2021 const object = self.file(index).?.object;1966 self.file(index).?.object.markComdatGroupsDead(self);
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 }
2034 }1967 }
2035 }1968 }
20361969
2037 // Re-resolve the symbols.1970 // 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);
2039 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1972 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
2040 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1973 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
1974 if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
2041}1975}
20421976
2043/// Traverses all objects and shared objects marking any object referenced by1977/// Traverses all objects and shared objects marking any object referenced by
...@@ -2129,7 +2063,7 @@ fn claimUnresolved(self: *Elf) void {...@@ -2129,7 +2063,7 @@ fn claimUnresolved(self: *Elf) void {
2129fn scanRelocs(self: *Elf) !void {2063fn scanRelocs(self: *Elf) !void {
2130 const gpa = self.base.comp.gpa;2064 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);
2133 defer {2067 defer {
2134 var it = undefs.iterator();2068 var it = undefs.iterator();
2135 while (it.next()) |entry| {2069 while (it.next()) |entry| {
...@@ -2976,10 +2910,10 @@ pub fn writeElfHeader(self: *Elf) !void {...@@ -2976,10 +2910,10 @@ pub fn writeElfHeader(self: *Elf) !void {
2976 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);2910 mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
2977 index += 4;2911 index += 4;
29782912
2979 const e_entry = if (self.entry_index) |entry_index|2913 const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {
2980 @as(u64, @intCast(self.symbol(entry_index).address(.{}, self)))2914 const entry_index = obj.entry_index orelse break :blk 0;
2981 else2915 break :blk @intCast(self.symbol(entry_index).address(.{}, self));
2982 0;2916 } else 0;
2983 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;2917 const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
2984 switch (self.ptr_width) {2918 switch (self.ptr_width) {
2985 .p32 => {2919 .p32 => {
...@@ -3106,205 +3040,6 @@ pub fn deleteExport(...@@ -3106,205 +3040,6 @@ pub fn deleteExport(
3106 return self.zigObjectPtr().?.deleteExport(self, exported, name);3040 return self.zigObjectPtr().?.deleteExport(self, exported, name);
3107}3041}
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
3308fn checkDuplicates(self: *Elf) !void {3043fn checkDuplicates(self: *Elf) !void {
3309 const gpa = self.base.comp.gpa;3044 const gpa = self.base.comp.gpa;
33103045
...@@ -3327,12 +3062,13 @@ fn checkDuplicates(self: *Elf) !void {...@@ -3327,12 +3062,13 @@ fn checkDuplicates(self: *Elf) !void {
3327}3062}
33283063
3329pub fn addCommentString(self: *Elf) !void {3064pub fn addCommentString(self: *Elf) !void {
3065 const gpa = self.base.comp.gpa;
3330 const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, elf.SHT_PROGBITS);3066 const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, elf.SHT_PROGBITS);
3331 const msec = self.mergeSection(msec_index);3067 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);
3333 if (res.found_existing) return;3069 if (res.found_existing) return;
3334 const msub_index = try self.addMergeSubsection();3070 const msub_index = try msec.addMergeSubsection(gpa);
3335 const msub = self.mergeSubsection(msub_index);3071 const msub = msec.mergeSubsection(msub_index);
3336 msub.merge_section_index = msec_index;3072 msub.merge_section_index = msec_index;
3337 msub.string_index = res.key.pos;3073 msub.string_index = res.key.pos;
3338 msub.alignment = .@"1";3074 msub.alignment = .@"1";
...@@ -3350,7 +3086,7 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -3350,7 +3086,7 @@ pub fn resolveMergeSections(self: *Elf) !void {
3350 for (self.objects.items) |index| {3086 for (self.objects.items) |index| {
3351 const file_ptr = self.file(index).?;3087 const file_ptr = self.file(index).?;
3352 if (!file_ptr.isAlive()) continue;3088 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) {
3354 error.MalformedObject => has_errors = true,3090 error.MalformedObject => has_errors = true,
3355 else => |e| return e,3091 else => |e| return e,
3356 };3092 };
...@@ -3358,6 +3094,12 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -3358,6 +3094,12 @@ pub fn resolveMergeSections(self: *Elf) !void {
33583094
3359 if (has_errors) return error.FlushFailure;3095 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
3361 for (self.objects.items) |index| {3103 for (self.objects.items) |index| {
3362 const file_ptr = self.file(index).?;3104 const file_ptr = self.file(index).?;
3363 if (!file_ptr.isAlive()) continue;3105 if (!file_ptr.isAlive()) continue;
...@@ -3372,15 +3114,15 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -3372,15 +3114,15 @@ pub fn resolveMergeSections(self: *Elf) !void {
33723114
3373pub fn finalizeMergeSections(self: *Elf) !void {3115pub fn finalizeMergeSections(self: *Elf) !void {
3374 for (self.merge_sections.items) |*msec| {3116 for (self.merge_sections.items) |*msec| {
3375 try msec.finalize(self);3117 try msec.finalize(self.base.comp.gpa);
3376 }3118 }
3377}3119}
33783120
3379pub fn updateMergeSectionSizes(self: *Elf) !void {3121pub fn updateMergeSectionSizes(self: *Elf) !void {
3380 for (self.merge_sections.items) |*msec| {3122 for (self.merge_sections.items) |*msec| {
3381 const shdr = &self.shdrs.items[msec.output_section_index];3123 const shdr = &self.shdrs.items[msec.output_section_index];
3382 for (msec.subsections.items) |msub_index| {3124 for (msec.finalized_subsections.items) |msub_index| {
3383 const msub = self.mergeSubsection(msub_index);3125 const msub = msec.mergeSubsection(msub_index);
3384 assert(msub.alive);3126 assert(msub.alive);
3385 const offset = msub.alignment.forward(shdr.sh_size);3127 const offset = msub.alignment.forward(shdr.sh_size);
3386 const padding = offset - shdr.sh_size;3128 const padding = offset - shdr.sh_size;
...@@ -3396,14 +3138,14 @@ pub fn writeMergeSections(self: *Elf) !void {...@@ -3396,14 +3138,14 @@ pub fn writeMergeSections(self: *Elf) !void {
3396 var buffer = std.ArrayList(u8).init(gpa);3138 var buffer = std.ArrayList(u8).init(gpa);
3397 defer buffer.deinit();3139 defer buffer.deinit();
33983140
3399 for (self.merge_sections.items) |msec| {3141 for (self.merge_sections.items) |*msec| {
3400 const shdr = self.shdrs.items[msec.output_section_index];3142 const shdr = self.shdrs.items[msec.output_section_index];
3401 const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;3143 const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
3402 try buffer.ensureTotalCapacity(size);3144 try buffer.ensureTotalCapacity(size);
3403 buffer.appendNTimesAssumeCapacity(0, size);3145 buffer.appendNTimesAssumeCapacity(0, size);
34043146
3405 for (msec.subsections.items) |msub_index| {3147 for (msec.finalized_subsections.items) |msub_index| {
3406 const msub = self.mergeSubsection(msub_index);3148 const msub = msec.mergeSubsection(msub_index);
3407 assert(msub.alive);3149 assert(msub.alive);
3408 const string = msub.getString(self);3150 const string = msub.getString(self);
3409 const off = math.cast(usize, msub.value) orelse return error.Overflow;3151 const off = math.cast(usize, msub.value) orelse return error.Overflow;
...@@ -3423,18 +3165,18 @@ fn initOutputSections(self: *Elf) !void {...@@ -3423,18 +3165,18 @@ fn initOutputSections(self: *Elf) !void {
34233165
3424pub fn initMergeSections(self: *Elf) !void {3166pub fn initMergeSections(self: *Elf) !void {
3425 for (self.merge_sections.items) |*msec| {3167 for (self.merge_sections.items) |*msec| {
3426 if (msec.subsections.items.len == 0) continue;3168 if (msec.finalized_subsections.items.len == 0) continue;
3427 const name = msec.name(self);3169 const name = msec.name(self);
3428 const shndx = self.sectionByName(name) orelse try self.addSection(.{3170 const shndx = self.sectionByName(name) orelse try self.addSection(.{
3429 .name = name,3171 .name = msec.name_offset,
3430 .type = msec.type,3172 .type = msec.type,
3431 .flags = msec.flags,3173 .flags = msec.flags,
3432 });3174 });
3433 msec.output_section_index = shndx;3175 msec.output_section_index = shndx;
34343176
3435 var entsize = self.mergeSubsection(msec.subsections.items[0]).entsize;3177 var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize;
3436 for (msec.subsections.items) |index| {3178 for (msec.finalized_subsections.items) |msub_index| {
3437 const msub = self.mergeSubsection(index);3179 const msub = msec.mergeSubsection(msub_index);
3438 entsize = @min(entsize, msub.entsize);3180 entsize = @min(entsize, msub.entsize);
3439 }3181 }
3440 const shdr = &self.shdrs.items[shndx];3182 const shdr = &self.shdrs.items[shndx];
...@@ -3452,7 +3194,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3452,7 +3194,7 @@ fn initSyntheticSections(self: *Elf) !void {
3452 } else false;3194 } else false;
3453 if (needs_eh_frame) {3195 if (needs_eh_frame) {
3454 self.eh_frame_section_index = try self.addSection(.{3196 self.eh_frame_section_index = try self.addSection(.{
3455 .name = ".eh_frame",3197 .name = try self.insertShString(".eh_frame"),
3456 .type = elf.SHT_PROGBITS,3198 .type = elf.SHT_PROGBITS,
3457 .flags = elf.SHF_ALLOC,3199 .flags = elf.SHF_ALLOC,
3458 .addralign = ptr_size,3200 .addralign = ptr_size,
...@@ -3461,7 +3203,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3461,7 +3203,7 @@ fn initSyntheticSections(self: *Elf) !void {
34613203
3462 if (comp.link_eh_frame_hdr) {3204 if (comp.link_eh_frame_hdr) {
3463 self.eh_frame_hdr_section_index = try self.addSection(.{3205 self.eh_frame_hdr_section_index = try self.addSection(.{
3464 .name = ".eh_frame_hdr",3206 .name = try self.insertShString(".eh_frame_hdr"),
3465 .type = elf.SHT_PROGBITS,3207 .type = elf.SHT_PROGBITS,
3466 .flags = elf.SHF_ALLOC,3208 .flags = elf.SHF_ALLOC,
3467 .addralign = 4,3209 .addralign = 4,
...@@ -3472,7 +3214,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3472,7 +3214,7 @@ fn initSyntheticSections(self: *Elf) !void {
34723214
3473 if (self.got.entries.items.len > 0) {3215 if (self.got.entries.items.len > 0) {
3474 self.got_section_index = try self.addSection(.{3216 self.got_section_index = try self.addSection(.{
3475 .name = ".got",3217 .name = try self.insertShString(".got"),
3476 .type = elf.SHT_PROGBITS,3218 .type = elf.SHT_PROGBITS,
3477 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,3219 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3478 .addralign = ptr_size,3220 .addralign = ptr_size,
...@@ -3481,7 +3223,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3481,7 +3223,7 @@ fn initSyntheticSections(self: *Elf) !void {
3481 }3223 }
34823224
3483 self.got_plt_section_index = try self.addSection(.{3225 self.got_plt_section_index = try self.addSection(.{
3484 .name = ".got.plt",3226 .name = try self.insertShString(".got.plt"),
3485 .type = elf.SHT_PROGBITS,3227 .type = elf.SHT_PROGBITS,
3486 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,3228 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3487 .addralign = @alignOf(u64),3229 .addralign = @alignOf(u64),
...@@ -3501,7 +3243,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3501,7 +3243,7 @@ fn initSyntheticSections(self: *Elf) !void {
3501 };3243 };
3502 if (needs_rela_dyn) {3244 if (needs_rela_dyn) {
3503 self.rela_dyn_section_index = try self.addSection(.{3245 self.rela_dyn_section_index = try self.addSection(.{
3504 .name = ".rela.dyn",3246 .name = try self.insertShString(".rela.dyn"),
3505 .type = elf.SHT_RELA,3247 .type = elf.SHT_RELA,
3506 .flags = elf.SHF_ALLOC,3248 .flags = elf.SHF_ALLOC,
3507 .addralign = @alignOf(elf.Elf64_Rela),3249 .addralign = @alignOf(elf.Elf64_Rela),
...@@ -3512,14 +3254,14 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3512,14 +3254,14 @@ fn initSyntheticSections(self: *Elf) !void {
35123254
3513 if (self.plt.symbols.items.len > 0) {3255 if (self.plt.symbols.items.len > 0) {
3514 self.plt_section_index = try self.addSection(.{3256 self.plt_section_index = try self.addSection(.{
3515 .name = ".plt",3257 .name = try self.insertShString(".plt"),
3516 .type = elf.SHT_PROGBITS,3258 .type = elf.SHT_PROGBITS,
3517 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,3259 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
3518 .addralign = 16,3260 .addralign = 16,
3519 .offset = std.math.maxInt(u64),3261 .offset = std.math.maxInt(u64),
3520 });3262 });
3521 self.rela_plt_section_index = try self.addSection(.{3263 self.rela_plt_section_index = try self.addSection(.{
3522 .name = ".rela.plt",3264 .name = try self.insertShString(".rela.plt"),
3523 .type = elf.SHT_RELA,3265 .type = elf.SHT_RELA,
3524 .flags = elf.SHF_ALLOC,3266 .flags = elf.SHF_ALLOC,
3525 .addralign = @alignOf(elf.Elf64_Rela),3267 .addralign = @alignOf(elf.Elf64_Rela),
...@@ -3530,7 +3272,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3530,7 +3272,7 @@ fn initSyntheticSections(self: *Elf) !void {
35303272
3531 if (self.plt_got.symbols.items.len > 0) {3273 if (self.plt_got.symbols.items.len > 0) {
3532 self.plt_got_section_index = try self.addSection(.{3274 self.plt_got_section_index = try self.addSection(.{
3533 .name = ".plt.got",3275 .name = try self.insertShString(".plt.got"),
3534 .type = elf.SHT_PROGBITS,3276 .type = elf.SHT_PROGBITS,
3535 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,3277 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
3536 .addralign = 16,3278 .addralign = 16,
...@@ -3540,7 +3282,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3540,7 +3282,7 @@ fn initSyntheticSections(self: *Elf) !void {
35403282
3541 if (self.copy_rel.symbols.items.len > 0) {3283 if (self.copy_rel.symbols.items.len > 0) {
3542 self.copy_rel_section_index = try self.addSection(.{3284 self.copy_rel_section_index = try self.addSection(.{
3543 .name = ".copyrel",3285 .name = try self.insertShString(".copyrel"),
3544 .type = elf.SHT_NOBITS,3286 .type = elf.SHT_NOBITS,
3545 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,3287 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3546 .offset = std.math.maxInt(u64),3288 .offset = std.math.maxInt(u64),
...@@ -3558,7 +3300,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3558,7 +3300,7 @@ fn initSyntheticSections(self: *Elf) !void {
3558 };3300 };
3559 if (needs_interp) {3301 if (needs_interp) {
3560 self.interp_section_index = try self.addSection(.{3302 self.interp_section_index = try self.addSection(.{
3561 .name = ".interp",3303 .name = try self.insertShString(".interp"),
3562 .type = elf.SHT_PROGBITS,3304 .type = elf.SHT_PROGBITS,
3563 .flags = elf.SHF_ALLOC,3305 .flags = elf.SHF_ALLOC,
3564 .addralign = 1,3306 .addralign = 1,
...@@ -3568,7 +3310,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3568,7 +3310,7 @@ fn initSyntheticSections(self: *Elf) !void {
35683310
3569 if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {3311 if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
3570 self.dynstrtab_section_index = try self.addSection(.{3312 self.dynstrtab_section_index = try self.addSection(.{
3571 .name = ".dynstr",3313 .name = try self.insertShString(".dynstr"),
3572 .flags = elf.SHF_ALLOC,3314 .flags = elf.SHF_ALLOC,
3573 .type = elf.SHT_STRTAB,3315 .type = elf.SHT_STRTAB,
3574 .entsize = 1,3316 .entsize = 1,
...@@ -3576,7 +3318,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3576,7 +3318,7 @@ fn initSyntheticSections(self: *Elf) !void {
3576 .offset = std.math.maxInt(u64),3318 .offset = std.math.maxInt(u64),
3577 });3319 });
3578 self.dynamic_section_index = try self.addSection(.{3320 self.dynamic_section_index = try self.addSection(.{
3579 .name = ".dynamic",3321 .name = try self.insertShString(".dynamic"),
3580 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,3322 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
3581 .type = elf.SHT_DYNAMIC,3323 .type = elf.SHT_DYNAMIC,
3582 .entsize = @sizeOf(elf.Elf64_Dyn),3324 .entsize = @sizeOf(elf.Elf64_Dyn),
...@@ -3584,7 +3326,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3584,7 +3326,7 @@ fn initSyntheticSections(self: *Elf) !void {
3584 .offset = std.math.maxInt(u64),3326 .offset = std.math.maxInt(u64),
3585 });3327 });
3586 self.dynsymtab_section_index = try self.addSection(.{3328 self.dynsymtab_section_index = try self.addSection(.{
3587 .name = ".dynsym",3329 .name = try self.insertShString(".dynsym"),
3588 .flags = elf.SHF_ALLOC,3330 .flags = elf.SHF_ALLOC,
3589 .type = elf.SHT_DYNSYM,3331 .type = elf.SHT_DYNSYM,
3590 .addralign = @alignOf(elf.Elf64_Sym),3332 .addralign = @alignOf(elf.Elf64_Sym),
...@@ -3593,7 +3335,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3593,7 +3335,7 @@ fn initSyntheticSections(self: *Elf) !void {
3593 .offset = std.math.maxInt(u64),3335 .offset = std.math.maxInt(u64),
3594 });3336 });
3595 self.hash_section_index = try self.addSection(.{3337 self.hash_section_index = try self.addSection(.{
3596 .name = ".hash",3338 .name = try self.insertShString(".hash"),
3597 .flags = elf.SHF_ALLOC,3339 .flags = elf.SHF_ALLOC,
3598 .type = elf.SHT_HASH,3340 .type = elf.SHT_HASH,
3599 .addralign = 4,3341 .addralign = 4,
...@@ -3601,7 +3343,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3601,7 +3343,7 @@ fn initSyntheticSections(self: *Elf) !void {
3601 .offset = std.math.maxInt(u64),3343 .offset = std.math.maxInt(u64),
3602 });3344 });
3603 self.gnu_hash_section_index = try self.addSection(.{3345 self.gnu_hash_section_index = try self.addSection(.{
3604 .name = ".gnu.hash",3346 .name = try self.insertShString(".gnu.hash"),
3605 .flags = elf.SHF_ALLOC,3347 .flags = elf.SHF_ALLOC,
3606 .type = elf.SHT_GNU_HASH,3348 .type = elf.SHT_GNU_HASH,
3607 .addralign = 8,3349 .addralign = 8,
...@@ -3614,7 +3356,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3614,7 +3356,7 @@ fn initSyntheticSections(self: *Elf) !void {
3614 } else false;3356 } else false;
3615 if (needs_versions) {3357 if (needs_versions) {
3616 self.versym_section_index = try self.addSection(.{3358 self.versym_section_index = try self.addSection(.{
3617 .name = ".gnu.version",3359 .name = try self.insertShString(".gnu.version"),
3618 .flags = elf.SHF_ALLOC,3360 .flags = elf.SHF_ALLOC,
3619 .type = elf.SHT_GNU_VERSYM,3361 .type = elf.SHT_GNU_VERSYM,
3620 .addralign = @alignOf(elf.Elf64_Versym),3362 .addralign = @alignOf(elf.Elf64_Versym),
...@@ -3622,7 +3364,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3622,7 +3364,7 @@ fn initSyntheticSections(self: *Elf) !void {
3622 .offset = std.math.maxInt(u64),3364 .offset = std.math.maxInt(u64),
3623 });3365 });
3624 self.verneed_section_index = try self.addSection(.{3366 self.verneed_section_index = try self.addSection(.{
3625 .name = ".gnu.version_r",3367 .name = try self.insertShString(".gnu.version_r"),
3626 .flags = elf.SHF_ALLOC,3368 .flags = elf.SHF_ALLOC,
3627 .type = elf.SHT_GNU_VERNEED,3369 .type = elf.SHT_GNU_VERNEED,
3628 .addralign = @alignOf(elf.Elf64_Verneed),3370 .addralign = @alignOf(elf.Elf64_Verneed),
...@@ -3642,7 +3384,7 @@ pub fn initSymtab(self: *Elf) !void {...@@ -3642,7 +3384,7 @@ pub fn initSymtab(self: *Elf) !void {
3642 };3384 };
3643 if (self.symtab_section_index == null) {3385 if (self.symtab_section_index == null) {
3644 self.symtab_section_index = try self.addSection(.{3386 self.symtab_section_index = try self.addSection(.{
3645 .name = ".symtab",3387 .name = try self.insertShString(".symtab"),
3646 .type = elf.SHT_SYMTAB,3388 .type = elf.SHT_SYMTAB,
3647 .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),3389 .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),
3648 .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),3390 .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),
...@@ -3651,7 +3393,7 @@ pub fn initSymtab(self: *Elf) !void {...@@ -3651,7 +3393,7 @@ pub fn initSymtab(self: *Elf) !void {
3651 }3393 }
3652 if (self.strtab_section_index == null) {3394 if (self.strtab_section_index == null) {
3653 self.strtab_section_index = try self.addSection(.{3395 self.strtab_section_index = try self.addSection(.{
3654 .name = ".strtab",3396 .name = try self.insertShString(".strtab"),
3655 .type = elf.SHT_STRTAB,3397 .type = elf.SHT_STRTAB,
3656 .entsize = 1,3398 .entsize = 1,
3657 .addralign = 1,3399 .addralign = 1,
...@@ -3663,7 +3405,7 @@ pub fn initSymtab(self: *Elf) !void {...@@ -3663,7 +3405,7 @@ pub fn initSymtab(self: *Elf) !void {
3663pub fn initShStrtab(self: *Elf) !void {3405pub fn initShStrtab(self: *Elf) !void {
3664 if (self.shstrtab_section_index == null) {3406 if (self.shstrtab_section_index == null) {
3665 self.shstrtab_section_index = try self.addSection(.{3407 self.shstrtab_section_index = try self.addSection(.{
3666 .name = ".shstrtab",3408 .name = try self.insertShString(".shstrtab"),
3667 .type = elf.SHT_STRTAB,3409 .type = elf.SHT_STRTAB,
3668 .entsize = 1,3410 .entsize = 1,
3669 .addralign = 1,3411 .addralign = 1,
...@@ -3733,11 +3475,11 @@ fn sortInitFini(self: *Elf) !void {...@@ -3733,11 +3475,11 @@ fn sortInitFini(self: *Elf) !void {
37333475
3734 const Entry = struct {3476 const Entry = struct {
3735 priority: i32,3477 priority: i32,
3736 atom_index: Atom.Index,3478 atom_ref: Ref,
37373479
3738 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {3480 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
3739 if (lhs.priority == rhs.priority) {3481 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);
3741 }3483 }
3742 return lhs.priority < rhs.priority;3484 return lhs.priority < rhs.priority;
3743 }3485 }
...@@ -3768,8 +3510,8 @@ fn sortInitFini(self: *Elf) !void {...@@ -3768,8 +3510,8 @@ fn sortInitFini(self: *Elf) !void {
3768 try entries.ensureTotalCapacityPrecise(atom_list.items.len);3510 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
3769 defer entries.deinit();3511 defer entries.deinit();
37703512
3771 for (atom_list.items) |atom_index| {3513 for (atom_list.items) |ref| {
3772 const atom_ptr = self.atom(atom_index).?;3514 const atom_ptr = self.atom(ref).?;
3773 const object = atom_ptr.file(self).?.object;3515 const object = atom_ptr.file(self).?.object;
3774 const priority = blk: {3516 const priority = blk: {
3775 if (is_ctor_dtor) {3517 if (is_ctor_dtor) {
...@@ -3782,14 +3524,14 @@ fn sortInitFini(self: *Elf) !void {...@@ -3782,14 +3524,14 @@ fn sortInitFini(self: *Elf) !void {
3782 const priority = std.fmt.parseUnsigned(u16, it.first(), 10) catch default;3524 const priority = std.fmt.parseUnsigned(u16, it.first(), 10) catch default;
3783 break :blk priority;3525 break :blk priority;
3784 };3526 };
3785 entries.appendAssumeCapacity(.{ .priority = priority, .atom_index = atom_index });3527 entries.appendAssumeCapacity(.{ .priority = priority, .atom_ref = ref });
3786 }3528 }
37873529
3788 mem.sort(Entry, entries.items, self, Entry.lessThan);3530 mem.sort(Entry, entries.items, self, Entry.lessThan);
37893531
3790 atom_list.clearRetainingCapacity();3532 atom_list.clearRetainingCapacity();
3791 for (entries.items) |entry| {3533 for (entries.items) |entry| {
3792 atom_list.appendAssumeCapacity(entry.atom_index);3534 atom_list.appendAssumeCapacity(entry.atom_ref);
3793 }3535 }
3794 }3536 }
3795}3537}
...@@ -4155,26 +3897,11 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {...@@ -4155,26 +3897,11 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
4155 }3897 }
4156 }3898 }
41573899
4158 if (self.zigObjectPtr()) |zig_object| {3900 if (self.zigObjectPtr()) |zo| {
4159 for (zig_object.atoms.items) |atom_index| {3901 for (zo.atoms_indexes.items) |atom_index| {
4160 const atom_ptr = self.atom(atom_index) orelse continue;3902 const atom_ptr = zo.atom(atom_index) orelse continue;
4161 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];3903 atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
4162 }3904 }
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 }
4178 }3905 }
41793906
4180 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {3907 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {
...@@ -4194,9 +3921,9 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4194,9 +3921,9 @@ fn updateSectionSizes(self: *Elf) !void {
4194 const shdr = &self.shdrs.items[shndx];3921 const shdr = &self.shdrs.items[shndx];
4195 if (atom_list.items.len == 0) continue;3922 if (atom_list.items.len == 0) continue;
4196 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;3923 if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
4197 for (atom_list.items) |atom_index| {3924 for (atom_list.items) |ref| {
4198 const atom_ptr = self.atom(atom_index) orelse continue;3925 const atom_ptr = self.atom(ref) orelse continue;
4199 if (!atom_ptr.flags.alive) continue;3926 if (!atom_ptr.alive) continue;
4200 const offset = atom_ptr.alignment.forward(shdr.sh_size);3927 const offset = atom_ptr.alignment.forward(shdr.sh_size);
4201 const padding = offset - shdr.sh_size;3928 const padding = offset - shdr.sh_size;
4202 atom_ptr.value = @intCast(offset);3929 atom_ptr.value = @intCast(offset);
...@@ -4630,7 +4357,7 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -4630,7 +4357,7 @@ fn allocateSpecialPhdrs(self: *Elf) void {
4630fn writeAtoms(self: *Elf) !void {4357fn writeAtoms(self: *Elf) !void {
4631 const gpa = self.base.comp.gpa;4358 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);
4634 defer {4361 defer {
4635 var it = undefs.iterator();4362 var it = undefs.iterator();
4636 while (it.next()) |entry| {4363 while (it.next()) |entry| {
...@@ -4678,21 +4405,21 @@ fn writeAtoms(self: *Elf) !void {...@@ -4678,21 +4405,21 @@ fn writeAtoms(self: *Elf) !void {
4678 0;4405 0;
4679 @memset(buffer, padding_byte);4406 @memset(buffer, padding_byte);
46804407
4681 for (atom_list.items) |atom_index| {4408 for (atom_list.items) |ref| {
4682 const atom_ptr = self.atom(atom_index).?;4409 const atom_ptr = self.atom(ref).?;
4683 assert(atom_ptr.flags.alive);4410 assert(atom_ptr.alive);
46844411
4685 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse4412 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse
4686 return error.Overflow;4413 return error.Overflow;
4687 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;4414 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
4691 // TODO decompress directly into provided buffer4418 // TODO decompress directly into provided buffer
4692 const out_code = buffer[offset..][0..size];4419 const out_code = buffer[offset..][0..size];
4693 const in_code = switch (atom_ptr.file(self).?) {4420 const in_code = switch (atom_ptr.file(self).?) {
4694 .object => |x| try x.codeDecompressAlloc(self, atom_index),4421 .object => |x| try x.codeDecompressAlloc(self, ref.index),
4695 .zig_object => |x| try x.codeAlloc(self, atom_index),4422 .zig_object => |x| try x.codeAlloc(self, ref.index),
4696 else => unreachable,4423 else => unreachable,
4697 };4424 };
4698 defer gpa.free(in_code);4425 defer gpa.free(in_code);
...@@ -5015,9 +4742,8 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -5015,9 +4742,8 @@ pub fn writeSymtab(self: *Elf) !void {
5015 file_ptr.writeSymtab(self);4742 file_ptr.writeSymtab(self);
5016 }4743 }
50174744
5018 if (self.linker_defined_index) |index| {4745 if (self.linkerDefinedPtr()) |obj| {
5019 const file_ptr = self.file(index).?;4746 obj.asFile().writeSymtab(self);
5020 file_ptr.writeSymtab(self);
5021 }4747 }
50224748
5023 if (self.zig_got_section_index) |_| {4749 if (self.zig_got_section_index) |_| {
...@@ -5479,7 +5205,7 @@ fn addPhdr(self: *Elf, opts: struct {...@@ -5479,7 +5205,7 @@ fn addPhdr(self: *Elf, opts: struct {
5479 return index;5205 return index;
5480}5206}
54815207
5482pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u32) !u32 {5208pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 {
5483 const entsize: u64 = switch (self.ptr_width) {5209 const entsize: u64 = switch (self.ptr_width) {
5484 .p32 => @sizeOf(elf.Elf32_Rela),5210 .p32 => @sizeOf(elf.Elf32_Rela),
5485 .p64 => @sizeOf(elf.Elf64_Rela),5211 .p64 => @sizeOf(elf.Elf64_Rela),
...@@ -5500,7 +5226,7 @@ pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u32) !u32 {...@@ -5500,7 +5226,7 @@ pub fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u32) !u32 {
5500}5226}
55015227
5502pub const AddSectionOpts = struct {5228pub const AddSectionOpts = struct {
5503 name: [:0]const u8,5229 name: u32 = 0,
5504 type: u32 = elf.SHT_NULL,5230 type: u32 = elf.SHT_NULL,
5505 flags: u64 = 0,5231 flags: u64 = 0,
5506 link: u32 = 0,5232 link: u32 = 0,
...@@ -5515,7 +5241,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {...@@ -5515,7 +5241,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
5515 const index = @as(u32, @intCast(self.shdrs.items.len));5241 const index = @as(u32, @intCast(self.shdrs.items.len));
5516 const shdr = try self.shdrs.addOne(gpa);5242 const shdr = try self.shdrs.addOne(gpa);
5517 shdr.* = .{5243 shdr.* = .{
5518 .sh_name = try self.insertShString(opts.name),5244 .sh_name = opts.name,
5519 .sh_type = opts.type,5245 .sh_type = opts.type,
5520 .sh_flags = opts.flags,5246 .sh_flags = opts.flags,
5521 .sh_addr = 0,5247 .sh_addr = 0,
...@@ -5580,7 +5306,7 @@ fn sortRelaDyn(self: *Elf) void {...@@ -5580,7 +5306,7 @@ fn sortRelaDyn(self: *Elf) void {
5580 mem.sort(elf.Elf64_Rela, self.rela_dyn.items, self, Sort.lessThan);5306 mem.sort(elf.Elf64_Rela, self.rela_dyn.items, self, Sort.lessThan);
5581}5307}
55825308
5583fn calcNumIRelativeRelocs(self: *Elf) usize {5309pub fn calcNumIRelativeRelocs(self: *Elf) usize {
5584 var count: usize = self.num_ifunc_dynrelocs;5310 var count: usize = self.num_ifunc_dynrelocs;
55855311
5586 for (self.got.entries.items) |entry| {5312 for (self.got.entries.items) |entry| {
...@@ -5602,7 +5328,7 @@ pub fn isCIdentifier(name: []const u8) bool {...@@ -5602,7 +5328,7 @@ pub fn isCIdentifier(name: []const u8) bool {
5602 return true;5328 return true;
5603}5329}
56045330
5605fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {5331pub fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
5606 const name = self.getShString(shdr.sh_name);5332 const name = self.getShString(shdr.sh_name);
5607 if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {5333 if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
5608 if (isCIdentifier(name)) return name;5334 if (isCIdentifier(name)) return name;
...@@ -5610,64 +5336,6 @@ fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {...@@ -5610,64 +5336,6 @@ fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
5610 return null;5336 return null;
5611}5337}
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
5671pub fn addThunk(self: *Elf) !Thunk.Index {5339pub fn addThunk(self: *Elf) !Thunk.Index {
5672 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));5340 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
5673 const th = try self.thunks.addOne(self.base.comp.gpa);5341 const th = try self.thunks.addOne(self.base.comp.gpa);
...@@ -5704,6 +5372,15 @@ pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {...@@ -5704,6 +5372,15 @@ pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
5704 return self.file_handles.items[index];5372 return self.file_handles.items[index];
5705}5373}
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
5707/// Returns pointer-to-symbol described at sym_index.5384/// Returns pointer-to-symbol described at sym_index.
5708pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {5385pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
5709 return &self.symbols.items[sym_index];5386 return &self.symbols.items[sym_index];
...@@ -5795,11 +5472,6 @@ pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {...@@ -5795,11 +5472,6 @@ pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
5795 };5472 };
5796}5473}
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
5803pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {5475pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
5804 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);5476 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
5805}5477}
...@@ -5809,69 +5481,12 @@ pub fn zigObjectPtr(self: *Elf) ?*ZigObject {...@@ -5809,69 +5481,12 @@ pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
5809 return self.file(index).?.zig_object;5481 return self.file(index).?.zig_object;
5810}5482}
58115483
5812const GetOrCreateComdatGroupOwnerResult = struct {5484pub fn linkerDefinedPtr(self: *Elf) ?*LinkerDefined {
5813 found_existing: bool,5485 const index = self.linker_defined_index orelse return null;
5814 index: ComdatGroupOwner.Index,5486 return self.file(index).?.linker_defined;
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];
5848}5487}
58495488
5850pub fn addInputMergeSection(self: *Elf) !InputMergeSection.Index {5489pub fn getOrCreateMergeSection(self: *Elf, name: [:0]const u8, flags: u64, @"type": u32) !MergeSection.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 {
5875 const gpa = self.base.comp.gpa;5490 const gpa = self.base.comp.gpa;
5876 const out_name = name: {5491 const out_name = name: {
5877 if (self.base.isRelocatable()) break :name name;5492 if (self.base.isRelocatable()) break :name name;
...@@ -5879,11 +5494,11 @@ pub fn getOrCreateMergeSection(self: *Elf, name: []const u8, flags: u64, @"type"...@@ -5879,11 +5494,11 @@ pub fn getOrCreateMergeSection(self: *Elf, name: []const u8, flags: u64, @"type"
5879 break :name if (flags & elf.SHF_STRINGS != 0) ".rodata.str" else ".rodata.cst";5494 break :name if (flags & elf.SHF_STRINGS != 0) ".rodata.str" else ".rodata.cst";
5880 break :name name;5495 break :name name;
5881 };5496 };
5882 const out_off = try self.strings.insert(gpa, out_name);
5883 const out_flags = flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP);
5884 for (self.merge_sections.items, 0..) |msec, index| {5497 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);
5886 }5499 }
5500 const out_off = try self.insertShString(out_name);
5501 const out_flags = flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP);
5887 const index = @as(MergeSection.Index, @intCast(self.merge_sections.items.len));5502 const index = @as(MergeSection.Index, @intCast(self.merge_sections.items.len));
5888 const msec = try self.merge_sections.addOne(gpa);5503 const msec = try self.merge_sections.addOne(gpa);
5889 msec.* = .{5504 msec.* = .{
...@@ -5974,9 +5589,9 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {...@@ -5974,9 +5589,9 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
5974 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);5589 var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
5975 try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});5590 try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
59765591
5977 for (atoms[0..natoms]) |atom_index| {5592 for (atoms[0..natoms]) |ref| {
5978 const atom_ptr = self.atom(atom_index).?;5593 const atom_ptr = self.atom(ref).?;
5979 const file_ptr = self.file(atom_ptr.file_index).?;5594 const file_ptr = self.file(ref.file).?;
5980 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });5595 try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
5981 }5596 }
59825597
...@@ -6253,7 +5868,7 @@ fn fmtDumpState(...@@ -6253,7 +5868,7 @@ fn fmtDumpState(
62535868
6254 try writer.writeAll("Output COMDAT groups\n");5869 try writer.writeAll("Output COMDAT groups\n");
6255 for (self.comdat_group_sections.items) |cg| {5870 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 });
6257 }5872 }
62585873
6259 try writer.writeAll("\nOutput merge sections\n");5874 try writer.writeAll("\nOutput merge sections\n");
...@@ -6340,21 +5955,24 @@ const default_entry_addr = 0x8000000;...@@ -6340,21 +5955,24 @@ const default_entry_addr = 0x8000000;
63405955
6341pub const base_tag: link.File.Tag = .elf;5956pub const base_tag: link.File.Tag = .elf;
63425957
6343const ComdatGroupOwner = struct {
6344 file: File.Index = 0,
6345
6346 const Index = u32;
6347};
6348
6349pub const ComdatGroup = struct {5958pub const ComdatGroup = struct {
6350 owner: ComdatGroupOwner.Index,5959 signature_off: u32,
6351 file: File.Index,5960 file_index: File.Index,
6352 shndx: u32,5961 shndx: u32,
6353 members_start: u32,5962 members_start: u32,
6354 members_len: u32,5963 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
6356 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {5974 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;
6358 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];5976 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];
6359 }5977 }
63605978
...@@ -6396,6 +6014,22 @@ pub const SystemLib = struct {...@@ -6396,6 +6014,22 @@ pub const SystemLib = struct {
6396 path: []const u8,6014 path: []const u8,
6397};6015};
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
6399const LastAtomAndFreeList = struct {6033const LastAtomAndFreeList = struct {
6400 /// Index of the last allocated atom in this section.6034 /// Index of the last allocated atom in this section.
6401 last_atom_index: Atom.Index = 0,6035 last_atom_index: Atom.Index = 0,
...@@ -6421,7 +6055,7 @@ const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndF...@@ -6421,7 +6055,7 @@ const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndF
64216055
6422const RelaSection = struct {6056const RelaSection = struct {
6423 shndx: u32,6057 shndx: u32,
6424 atom_list: std.ArrayListUnmanaged(Atom.Index) = .{},6058 atom_list: std.ArrayListUnmanaged(Ref) = .{},
6425};6059};
6426const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);6060const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
64276061
src/link/Elf/Atom.zig+54-68
...@@ -30,14 +30,17 @@ atom_index: Index = 0,...@@ -30,14 +30,17 @@ atom_index: Index = 0,
30prev_index: Index = 0,30prev_index: Index = 0,
31next_index: Index = 0,31next_index: Index = 0,
3232
33/// Flags we use for state tracking.33/// Specifies whether this atom is alive or has been garbage collected.
34flags: Flags = .{},34alive: bool = true,
35
36/// Specifies if the atom has been visited during garbage collection.
37visited: bool = false,
3538
36extra_index: u32 = 0,39extra_index: u32 = 0,
3740
38pub const Alignment = @import("../../InternPool.zig").Alignment;41pub 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 {
41 const file_ptr = self.file(elf_file).?;44 const file_ptr = self.file(elf_file).?;
42 return switch (file_ptr) {45 return switch (file_ptr) {
43 inline else => |x| x.getString(self.name_offset),46 inline else => |x| x.getString(self.name_offset),
...@@ -45,8 +48,7 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {...@@ -45,8 +48,7 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
45}48}
4649
47pub fn address(self: Atom, elf_file: *Elf) i64 {50pub fn address(self: Atom, elf_file: *Elf) i64 {
48 const shndx = self.outputShndx() orelse return self.value;51 const shdr = elf_file.shdrs.items[self.output_section_index];
49 const shdr = elf_file.shdrs.items[shndx];
50 return @as(i64, @intCast(shdr.sh_addr)) + self.value;52 return @as(i64, @intCast(shdr.sh_addr)) + self.value;
51}53}
5254
...@@ -55,7 +57,7 @@ pub fn debugTombstoneValue(self: Atom, target: Symbol, elf_file: *Elf) ?u64 {...@@ -55,7 +57,7 @@ pub fn debugTombstoneValue(self: Atom, target: Symbol, elf_file: *Elf) ?u64 {
55 if (msub.alive) return null;57 if (msub.alive) return null;
56 }58 }
57 if (target.atom(elf_file)) |atom_ptr| {59 if (target.atom(elf_file)) |atom_ptr| {
58 if (atom_ptr.flags.alive) return null;60 if (atom_ptr.alive) return null;
59 }61 }
60 const atom_name = self.name(elf_file);62 const atom_name = self.name(elf_file);
61 if (!mem.startsWith(u8, atom_name, ".debug")) return null;63 if (!mem.startsWith(u8, atom_name, ".debug")) return null;
...@@ -67,8 +69,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {...@@ -67,8 +69,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
67}69}
6870
69pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {71pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {
70 assert(self.flags.thunk);72 const extras = self.extra(elf_file);
71 const extras = self.extra(elf_file).?;
72 return elf_file.thunk(extras.thunk);73 return elf_file.thunk(extras.thunk);
73}74}
7475
...@@ -85,11 +86,6 @@ pub fn relocsShndx(self: Atom) ?u32 {...@@ -85,11 +86,6 @@ pub fn relocsShndx(self: Atom) ?u32 {
85 return self.relocs_section_index;86 return self.relocs_section_index;
86}87}
8788
88pub fn outputShndx(self: Atom) ?u32 {
89 if (self.output_section_index == 0) return null;
90 return self.output_section_index;
91}
92
93pub fn priority(self: Atom, elf_file: *Elf) u64 {89pub fn priority(self: Atom, elf_file: *Elf) u64 {
94 const index = self.file(elf_file).?.index();90 const index = self.file(elf_file).?.index();
95 return (@as(u64, @intCast(index)) << 32) | @as(u64, @intCast(self.input_section_index));91 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 {...@@ -99,7 +95,8 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
99/// File offset relocation happens transparently, so it is not included in95/// File offset relocation happens transparently, so it is not included in
100/// this calculation.96/// this calculation.
101pub fn capacity(self: Atom, elf_file: *Elf) u64 {97pub 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|
103 next.address(elf_file)100 next.address(elf_file)
104 else101 else
105 std.math.maxInt(u32);102 std.math.maxInt(u32);
...@@ -107,8 +104,9 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {...@@ -107,8 +104,9 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
107}104}
108105
109pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {106pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
107 const zo = elf_file.zigObjectPtr().?;
110 // No need to keep a free list node for the last block.108 // 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;
112 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));110 const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
113 const ideal_cap = Elf.padToIdeal(self.size);111 const ideal_cap = Elf.padToIdeal(self.size);
114 if (cap <= ideal_cap) return false;112 if (cap <= ideal_cap) return false;
...@@ -117,8 +115,9 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -117,8 +115,9 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
117}115}
118116
119pub fn allocate(self: *Atom, elf_file: *Elf) !void {117pub fn allocate(self: *Atom, elf_file: *Elf) !void {
120 const shdr = &elf_file.shdrs.items[self.outputShndx().?];118 const zo = elf_file.zigObjectPtr().?;
121 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;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).?;
122 const free_list = &meta.free_list;121 const free_list = &meta.free_list;
123 const last_atom_index = &meta.last_atom_index;122 const last_atom_index = &meta.last_atom_index;
124 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);123 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
...@@ -137,7 +136,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -137,7 +136,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
137 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;136 var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
138 while (i < free_list.items.len) {137 while (i < free_list.items.len) {
139 const big_atom_index = free_list.items[i];138 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).?;
141 // We now have a pointer to a live atom that has too much capacity.140 // We now have a pointer to a live atom that has too much capacity.
142 // Is it enough that we could fit this new atom?141 // Is it enough that we could fit this new atom?
143 const cap = big_atom.capacity(elf_file);142 const cap = big_atom.capacity(elf_file);
...@@ -169,7 +168,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -169,7 +168,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
169 free_list_removal = i;168 free_list_removal = i;
170 }169 }
171 break :blk @intCast(new_start_vaddr);170 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| {
173 const ideal_capacity = Elf.padToIdeal(last.size);172 const ideal_capacity = Elf.padToIdeal(last.size);
174 const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;173 const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;
175 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);174 const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
...@@ -189,12 +188,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -189,12 +188,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
189 });188 });
190189
191 const expand_section = if (atom_placement) |placement_index|190 const expand_section = if (atom_placement) |placement_index|
192 elf_file.atom(placement_index).?.next_index == 0191 zo.atom(placement_index).?.next_index == 0
193 else192 else
194 true;193 true;
195 if (expand_section) {194 if (expand_section) {
196 const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size)));195 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);
198 last_atom_index.* = self.atom_index;197 last_atom_index.* = self.atom_index;
199198
200 const zig_object = elf_file.zigObjectPtr().?;199 const zig_object = elf_file.zigObjectPtr().?;
...@@ -214,15 +213,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -214,15 +213,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
214 // This function can also reallocate an atom.213 // This function can also reallocate an atom.
215 // In this case we need to "unplug" it from its previous location before214 // In this case we need to "unplug" it from its previous location before
216 // plugging it in to its new location.215 // plugging it in to its new location.
217 if (elf_file.atom(self.prev_index)) |prev| {216 if (zo.atom(self.prev_index)) |prev| {
218 prev.next_index = self.next_index;217 prev.next_index = self.next_index;
219 }218 }
220 if (elf_file.atom(self.next_index)) |next| {219 if (zo.atom(self.next_index)) |next| {
221 next.prev_index = self.prev_index;220 next.prev_index = self.prev_index;
222 }221 }
223222
224 if (atom_placement) |big_atom_index| {223 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).?;
226 self.prev_index = big_atom_index;225 self.prev_index = big_atom_index;
227 self.next_index = big_atom.next_index;226 self.next_index = big_atom.next_index;
228 big_atom.next_index = self.atom_index;227 big_atom.next_index = self.atom_index;
...@@ -234,7 +233,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -234,7 +233,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
234 _ = free_list.swapRemove(i);233 _ = free_list.swapRemove(i);
235 }234 }
236235
237 self.flags.alive = true;236 self.alive = true;
238}237}
239238
240pub fn shrink(self: *Atom, elf_file: *Elf) void {239pub fn shrink(self: *Atom, elf_file: *Elf) void {
...@@ -250,9 +249,10 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {...@@ -250,9 +249,10 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {
250pub fn free(self: *Atom, elf_file: *Elf) void {249pub fn free(self: *Atom, elf_file: *Elf) void {
251 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });250 log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
252251
252 const zo = elf_file.zigObjectPtr().?;
253 const comp = elf_file.base.comp;253 const comp = elf_file.base.comp;
254 const gpa = comp.gpa;254 const gpa = comp.gpa;
255 const shndx = self.outputShndx().?;255 const shndx = self.output_section_index;
256 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;256 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
257 const free_list = &meta.free_list;257 const free_list = &meta.free_list;
258 const last_atom_index = &meta.last_atom_index;258 const last_atom_index = &meta.last_atom_index;
...@@ -272,9 +272,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -272,9 +272,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
272 }272 }
273 }273 }
274274
275 if (elf_file.atom(last_atom_index.*)) |last_atom| {275 if (zo.atom(last_atom_index.*)) |last_atom| {
276 if (last_atom.atom_index == self.atom_index) {276 if (last_atom.atom_index == self.atom_index) {
277 if (elf_file.atom(self.prev_index)) |_| {277 if (zo.atom(self.prev_index)) |_| {
278 // TODO shrink the section size here278 // TODO shrink the section size here
279 last_atom_index.* = self.prev_index;279 last_atom_index.* = self.prev_index;
280 } else {280 } else {
...@@ -283,7 +283,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -283,7 +283,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
283 }283 }
284 }284 }
285285
286 if (elf_file.atom(self.prev_index)) |prev| {286 if (zo.atom(self.prev_index)) |prev| {
287 prev.next_index = self.next_index;287 prev.next_index = self.next_index;
288 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {288 if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
289 // The free list is heuristics, it doesn't have to be perfect, so we can289 // 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 {...@@ -294,7 +294,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
294 self.prev_index = 0;294 self.prev_index = 0;
295 }295 }
296296
297 if (elf_file.atom(self.next_index)) |next| {297 if (zo.atom(self.next_index)) |next| {
298 next.prev_index = self.prev_index;298 next.prev_index = self.prev_index;
299 } else {299 } else {
300 self.next_index = 0;300 self.next_index = 0;
...@@ -313,7 +313,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {...@@ -313,7 +313,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
313 switch (self.file(elf_file).?) {313 switch (self.file(elf_file).?) {
314 .zig_object => |x| return x.relocs.items[shndx].items,314 .zig_object => |x| return x.relocs.items[shndx].items,
315 .object => |x| {315 .object => |x| {
316 const extras = self.extra(elf_file).?;316 const extras = self.extra(elf_file);
317 return x.relocs.items[extras.rel_index..][0..extras.rel_count];317 return x.relocs.items[extras.rel_index..][0..extras.rel_count];
318 },318 },
319 else => unreachable,319 else => unreachable,
...@@ -337,12 +337,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El...@@ -337,12 +337,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
337 var r_addend = rel.r_addend;337 var r_addend = rel.r_addend;
338 var r_sym: u32 = 0;338 var r_sym: u32 = 0;
339 switch (target.type(elf_file)) {339 switch (target.type(elf_file)) {
340 elf.STT_SECTION => if (target.mergeSubsection(elf_file)) |msub| {340 elf.STT_SECTION => {
341 r_addend += @intCast(target.address(.{}, elf_file));
342 r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);
343 } else {
344 r_addend += @intCast(target.address(.{}, elf_file));341 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;
346 },346 },
347 else => {347 else => {
348 r_sym = target.outputSymtabIndex(elf_file) orelse 0;348 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...@@ -366,10 +366,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
366}366}
367367
368pub fn fdes(self: Atom, elf_file: *Elf) []Fde {368pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
369 if (!self.flags.fde) return &[0]Fde{};369 const extras = self.extra(elf_file);
370 const extras = self.extra(elf_file).?;370 return switch (self.file(elf_file).?) {
371 const object = self.file(elf_file).?.object;371 .shared_object => unreachable,
372 return object.fdes.items[extras.fde_start..][0..extras.fde_count];372 .linker_defined, .zig_object => &[0]Fde{},
373 .object => |x| x.fdes.items[extras.fde_start..][0..extras.fde_count],
374 };
373}375}
374376
375pub fn markFdesDead(self: Atom, elf_file: *Elf) void {377pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
...@@ -712,9 +714,9 @@ fn reportUndefined(...@@ -712,9 +714,9 @@ fn reportUndefined(
712 {714 {
713 const gop = try undefs.getOrPut(sym_index);715 const gop = try undefs.getOrPut(sym_index);
714 if (!gop.found_existing) {716 if (!gop.found_existing) {
715 gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);717 gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
716 }718 }
717 try gop.value_ptr.append(self.atom_index);719 try gop.value_ptr.append(.{ .index = self.atom_index, .file = self.file_index });
718 return true;720 return true;
719 }721 }
720722
...@@ -1001,25 +1003,23 @@ const AddExtraOpts = struct {...@@ -1001,25 +1003,23 @@ const AddExtraOpts = struct {
1001 rel_count: ?u32 = null,1003 rel_count: ?u32 = null,
1002};1004};
10031005
1004pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void {1006pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) void {
1005 if (atom.extra(elf_file) == null) {1007 const file_ptr = atom.file(elf_file).?;
1006 atom.extra_index = try elf_file.addAtomExtra(.{});1008 var extras = file_ptr.atomExtra(atom.extra_index);
1007 }
1008 var extras = atom.extra(elf_file).?;
1009 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {1009 inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
1010 if (@field(opts, field.name)) |x| {1010 if (@field(opts, field.name)) |x| {
1011 @field(extras, field.name) = x;1011 @field(extras, field.name) = x;
1012 }1012 }
1013 }1013 }
1014 atom.setExtra(extras, elf_file);1014 file_ptr.setAtomExtra(atom.extra_index, extras);
1015}1015}
10161016
1017pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {1017pub inline fn extra(atom: Atom, elf_file: *Elf) Extra {
1018 return elf_file.atomExtra(atom.extra_index);1018 return atom.file(elf_file).?.atomExtra(atom.extra_index);
1019}1019}
10201020
1021pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {1021pub 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);
1023}1023}
10241024
1025pub fn format(1025pub fn format(
...@@ -1061,9 +1061,9 @@ fn format2(...@@ -1061,9 +1061,9 @@ fn format2(
1061 atom.atom_index, atom.name(elf_file), atom.address(elf_file),1061 atom.atom_index, atom.name(elf_file), atom.address(elf_file),
1062 atom.output_section_index, atom.alignment, atom.size,1062 atom.output_section_index, atom.alignment, atom.size,
1063 });1063 });
1064 if (atom.flags.fde) {1064 if (atom.fdes(elf_file).len > 0) {
1065 try writer.writeAll(" : fdes{ ");1065 try writer.writeAll(" : fdes{ ");
1066 const extras = atom.extra(elf_file).?;1066 const extras = atom.extra(elf_file);
1067 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {1067 for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
1068 try writer.print("{d}", .{i});1068 try writer.print("{d}", .{i});
1069 if (!fde.alive) try writer.writeAll("([*])");1069 if (!fde.alive) try writer.writeAll("([*])");
...@@ -1071,27 +1071,13 @@ fn format2(...@@ -1071,27 +1071,13 @@ fn format2(
1071 }1071 }
1072 try writer.writeAll(" }");1072 try writer.writeAll(" }");
1073 }1073 }
1074 if (!atom.flags.alive) {1074 if (!atom.alive) {
1075 try writer.writeAll(" : [*]");1075 try writer.writeAll(" : [*]");
1076 }1076 }
1077}1077}
10781078
1079pub const Index = u32;1079pub 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
1095const x86_64 = struct {1081const x86_64 = struct {
1096 fn scanReloc(1082 fn scanReloc(
1097 atom: Atom,1083 atom: Atom,
src/link/Elf/LinkerDefined.zig+223-2
...@@ -1,17 +1,89 @@...@@ -1,17 +1,89 @@
1index: File.Index,1index: File.Index,
2
2symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},3symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
3strtab: std.ArrayListUnmanaged(u8) = .{},4strtab: std.ArrayListUnmanaged(u8) = .{},
4symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},5symbols: 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
6output_symtab_ctx: Elf.SymtabCtx = .{},26output_symtab_ctx: Elf.SymtabCtx = .{},
727
8pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {28pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
9 self.symtab.deinit(allocator);29 self.symtab.deinit(allocator);
10 self.strtab.deinit(allocator);30 self.strtab.deinit(allocator);
11 self.symbols.deinit(allocator);31 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);
12}38}
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 {
15 const comp = elf_file.base.comp;87 const comp = elf_file.base.comp;
16 const gpa = comp.gpa;88 const gpa = comp.gpa;
17 try self.symtab.ensureUnusedCapacity(gpa, 1);89 try self.symtab.ensureUnusedCapacity(gpa, 1);
...@@ -41,7 +113,7 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -41,7 +113,7 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
41 const global = elf_file.symbol(index);113 const global = elf_file.symbol(index);
42 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {114 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
43 global.value = 0;115 global.value = 0;
44 global.atom_index = 0;116 global.ref = .{ .index = 0, .file = 0 };
45 global.file_index = self.index;117 global.file_index = self.index;
46 global.esym_index = sym_idx;118 global.esym_index = sym_idx;
47 global.version_index = elf_file.default_sym_version;119 global.version_index = elf_file.default_sym_version;
...@@ -49,6 +121,154 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {...@@ -49,6 +121,154 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
49 }121 }
50}122}
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
52pub fn globals(self: LinkerDefined) []const Symbol.Index {272pub fn globals(self: LinkerDefined) []const Symbol.Index {
53 return self.symbols.items;273 return self.symbols.items;
54}274}
...@@ -127,6 +347,7 @@ const mem = std.mem;...@@ -127,6 +347,7 @@ const mem = std.mem;
127const std = @import("std");347const std = @import("std");
128348
129const Allocator = mem.Allocator;349const Allocator = mem.Allocator;
350const Atom = @import("Atom.zig");
130const Elf = @import("../Elf.zig");351const Elf = @import("../Elf.zig");
131const File = @import("file.zig").File;352const File = @import("file.zig").File;
132const LinkerDefined = @This();353const LinkerDefined = @This();
src/link/Elf/Object.zig+333-200
...@@ -10,12 +10,17 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},...@@ -10,12 +10,17 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
10strtab: std.ArrayListUnmanaged(u8) = .{},10strtab: std.ArrayListUnmanaged(u8) = .{},
11first_global: ?Symbol.Index = null,11first_global: ?Symbol.Index = null,
12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
14comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
15comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
16relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},13relocs: 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
20fdes: std.ArrayListUnmanaged(Fde) = .{},25fdes: std.ArrayListUnmanaged(Fde) = .{},
21cies: std.ArrayListUnmanaged(Cie) = .{},26cies: std.ArrayListUnmanaged(Cie) = .{},
...@@ -47,13 +52,19 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -47,13 +52,19 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
47 self.strtab.deinit(allocator);52 self.strtab.deinit(allocator);
48 self.symbols.deinit(allocator);53 self.symbols.deinit(allocator);
49 self.atoms.deinit(allocator);54 self.atoms.deinit(allocator);
55 self.atoms_indexes.deinit(allocator);
56 self.atoms_extra.deinit(allocator);
50 self.comdat_groups.deinit(allocator);57 self.comdat_groups.deinit(allocator);
51 self.comdat_group_data.deinit(allocator);58 self.comdat_group_data.deinit(allocator);
52 self.relocs.deinit(allocator);59 self.relocs.deinit(allocator);
53 self.fdes.deinit(allocator);60 self.fdes.deinit(allocator);
54 self.cies.deinit(allocator);61 self.cies.deinit(allocator);
55 self.eh_frame_data.deinit(allocator);62 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);
57}68}
5869
59pub fn parse(self: *Object, elf_file: *Elf) !void {70pub fn parse(self: *Object, elf_file: *Elf) !void {
...@@ -62,14 +73,20 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -62,14 +73,20 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
62 const handle = elf_file.fileHandle(self.file_handle);73 const handle = elf_file.fileHandle(self.file_handle);
6374
64 try self.parseCommon(gpa, handle, elf_file);75 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
65 try self.initAtoms(gpa, handle, elf_file);82 try self.initAtoms(gpa, handle, elf_file);
66 try self.initSymtab(gpa, elf_file);83 try self.initSymtab(gpa, elf_file);
6784
68 for (self.shdrs.items, 0..) |shdr, i| {85 for (self.shdrs.items, 0..) |shdr, i| {
69 const atom = elf_file.atom(self.atoms.items[i]) orelse continue;86 const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
70 if (!atom.flags.alive) continue;87 if (!atom_ptr.alive) continue;
71 if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or88 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"))
73 {90 {
74 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);91 try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
75 }92 }
...@@ -169,8 +186,11 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil...@@ -169,8 +186,11 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
169186
170fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {187fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
171 const shdrs = self.shdrs.items;188 const shdrs = self.shdrs.items;
172 try self.atoms.resize(allocator, shdrs.len);189 try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len);
173 @memset(self.atoms.items, 0);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
175 for (shdrs, 0..) |shdr, i| {195 for (shdrs, 0..) |shdr, i| {
176 if (shdr.sh_flags & elf.SHF_EXCLUDE != 0 and196 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:...@@ -188,37 +208,53 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
188 const group_signature = blk: {208 const group_signature = blk: {
189 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {209 if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
190 const sym_shdr = shdrs[group_info_sym.st_shndx];210 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;
192 }212 }
193 break :blk self.getString(group_info_sym.st_name);213 break :blk group_info_sym.st_name;
194 };214 };
195215
196 const shndx = @as(u32, @intCast(i));216 const shndx = @as(u32, @intCast(i));
197 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);217 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
198 defer allocator.free(group_raw_data);218 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 }
200 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];235 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
201236
202 if (group_members[0] != elf.GRP_COMDAT) {237 if (group_members[0] != elf.GRP_COMDAT) {
203 // TODO convert into an error238 try elf_file.reportParseError2(
204 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});239 self.index,
205 continue;240 "corrupt section group: unknown SHT_GROUP format",
241 .{},
242 );
243 return error.MalformedObject;
206 }244 }
207245
208 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));246 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));
209 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);247 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
210248
211 const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);249 const comdat_group_index = try self.addComdatGroup(allocator);
212 const comdat_group_index = try elf_file.addComdatGroup();250 const comdat_group = self.comdatGroup(comdat_group_index);
213 const comdat_group = elf_file.comdatGroup(comdat_group_index);
214 comdat_group.* = .{251 comdat_group.* = .{
215 .owner = gop.index,252 .signature_off = group_signature,
216 .file = self.index,253 .file_index = self.index,
217 .shndx = shndx,254 .shndx = shndx,
218 .members_start = group_start,255 .members_start = group_start,
219 .members_len = @intCast(group_nmembers - 1),256 .members_len = @intCast(group_nmembers - 1),
220 };257 };
221 try self.comdat_groups.append(allocator, comdat_group_index);
222 },258 },
223259
224 elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),260 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:...@@ -233,7 +269,19 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
233 else => {269 else => {
234 const shndx = @as(u32, @intCast(i));270 const shndx = @as(u32, @intCast(i));
235 if (self.skipShdr(shndx, elf_file)) continue;271 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;
237 },285 },
238 }286 }
239 }287 }
...@@ -241,14 +289,14 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:...@@ -241,14 +289,14 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
241 // Parse relocs sections if any.289 // Parse relocs sections if any.
242 for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) {290 for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) {
243 elf.SHT_REL, elf.SHT_RELA => {291 elf.SHT_REL, elf.SHT_RELA => {
244 const atom_index = self.atoms.items[shdr.sh_info];292 const atom_index = self.atoms_indexes.items[shdr.sh_info];
245 if (elf_file.atom(atom_index)) |atom| {293 if (self.atom(atom_index)) |atom_ptr| {
246 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));294 const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
247 defer allocator.free(relocs);295 defer allocator.free(relocs);
248 atom.relocs_section_index = @intCast(i);296 atom_ptr.relocs_section_index = @intCast(i);
249 const rel_index: u32 = @intCast(self.relocs.items.len);297 const rel_index: u32 = @intCast(self.relocs.items.len);
250 const rel_count: u32 = @intCast(relocs.len);298 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);
252 try self.relocs.appendUnalignedSlice(allocator, relocs);300 try self.relocs.appendUnalignedSlice(allocator, relocs);
253 if (elf_file.getTarget().cpu.arch == .riscv64) {301 if (elf_file.getTarget().cpu.arch == .riscv64) {
254 sortRelocs(self.relocs.items[rel_index..][0..rel_count]);302 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:...@@ -259,27 +307,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
259 };307 };
260}308}
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
283fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {310fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
284 const name = blk: {311 const name = blk: {
285 const name = self.getString(shdr.sh_name);312 const name = self.getString(shdr.sh_name);
...@@ -327,7 +354,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O...@@ -327,7 +354,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O
327 const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{354 const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
328 .type = @"type",355 .type = @"type",
329 .flags = flags,356 .flags = flags,
330 .name = name,357 .name = try elf_file.insertShString(name),
331 });358 });
332 return out_shndx;359 return out_shndx;
333}360}
...@@ -359,8 +386,10 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {...@@ -359,8 +386,10 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
359 sym_ptr.value = @intCast(sym.st_value);386 sym_ptr.value = @intCast(sym.st_value);
360 sym_ptr.name_offset = sym.st_name;387 sym_ptr.name_offset = sym.st_name;
361 sym_ptr.esym_index = @as(u32, @intCast(i));388 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];
363 sym_ptr.file_index = self.index;389 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 }
364 }393 }
365394
366 for (self.symtab.items[first_global..]) |sym| {395 for (self.symtab.items[first_global..]) |sym| {
...@@ -447,15 +476,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:...@@ -447,15 +476,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
447 var i: u32 = @as(u32, @intCast(fdes_start));476 var i: u32 = @as(u32, @intCast(fdes_start));
448 while (i < self.fdes.items.len) {477 while (i < self.fdes.items.len) {
449 const fde = self.fdes.items[i];478 const fde = self.fdes.items[i];
450 const atom = fde.atom(elf_file);479 const atom_ptr = fde.atom(elf_file);
451 const start = i;480 const start = i;
452 i += 1;481 i += 1;
453 while (i < self.fdes.items.len) : (i += 1) {482 while (i < self.fdes.items.len) : (i += 1) {
454 const next_fde = self.fdes.items[i];483 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;
456 }485 }
457 try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);486 atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
458 atom.flags.fde = true;
459 }487 }
460}488}
461489
...@@ -498,19 +526,19 @@ fn filterRelocs(...@@ -498,19 +526,19 @@ fn filterRelocs(
498pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {526pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
499 const comp = elf_file.base.comp;527 const comp = elf_file.base.comp;
500 const gpa = comp.gpa;528 const gpa = comp.gpa;
501 for (self.atoms.items) |atom_index| {529 for (self.atoms_indexes.items) |atom_index| {
502 const atom = elf_file.atom(atom_index) orelse continue;530 const atom_ptr = self.atom(atom_index) orelse continue;
503 if (!atom.flags.alive) continue;531 if (!atom_ptr.alive) continue;
504 const shdr = atom.inputShdr(elf_file);532 const shdr = atom_ptr.inputShdr(elf_file);
505 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;533 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
506 if (shdr.sh_type == elf.SHT_NOBITS) continue;534 if (shdr.sh_type == elf.SHT_NOBITS) continue;
507 if (atom.scanRelocsRequiresCode(elf_file)) {535 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
508 // TODO ideally, we don't have to decompress at this stage (should already be done)536 // TODO ideally, we don't have to decompress at this stage (should already be done)
509 // and we just fetch the code slice.537 // and we just fetch the code slice.
510 const code = try self.codeDecompressAlloc(elf_file, atom_index);538 const code = try self.codeDecompressAlloc(elf_file, atom_index);
511 defer gpa.free(code);539 defer gpa.free(code);
512 try atom.scanRelocs(elf_file, code, undefs);540 try atom_ptr.scanRelocs(elf_file, code, undefs);
513 } else try atom.scanRelocs(elf_file, null, undefs);541 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
514 }542 }
515543
516 for (self.cies.items) |cie| {544 for (self.cies.items) |cie| {
...@@ -538,19 +566,21 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {...@@ -538,19 +566,21 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
538 if (esym.st_shndx == elf.SHN_UNDEF) continue;566 if (esym.st_shndx == elf.SHN_UNDEF) continue;
539567
540 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {568 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
541 const atom_index = self.atoms.items[esym.st_shndx];569 const atom_index = self.atoms_indexes.items[esym.st_shndx];
542 const atom = elf_file.atom(atom_index) orelse continue;570 const atom_ptr = self.atom(atom_index) orelse continue;
543 if (!atom.flags.alive) continue;571 if (!atom_ptr.alive) continue;
544 }572 }
545573
546 const global = elf_file.symbol(index);574 const global = elf_file.symbol(index);
547 if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {575 if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {
548 const atom_index = switch (esym.st_shndx) {576 switch (esym.st_shndx) {
549 elf.SHN_ABS, elf.SHN_COMMON => 0,577 elf.SHN_ABS, elf.SHN_COMMON => {},
550 else => self.atoms.items[esym.st_shndx],578 else => global.ref = .{
551 };579 .index = self.atoms_indexes.items[esym.st_shndx],
580 .file = self.index,
581 },
582 }
552 global.value = @intCast(esym.st_value);583 global.value = @intCast(esym.st_value);
553 global.atom_index = atom_index;
554 global.esym_index = esym_index;584 global.esym_index = esym_index;
555 global.file_index = self.index;585 global.file_index = self.index;
556 global.version_index = elf_file.default_sym_version;586 global.version_index = elf_file.default_sym_version;
...@@ -579,7 +609,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -579,7 +609,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
579 };609 };
580610
581 global.value = 0;611 global.value = 0;
582 global.atom_index = 0;612 global.ref = .{ .index = 0, .file = 0 };
583 global.esym_index = esym_index;613 global.esym_index = esym_index;
584 global.file_index = self.index;614 global.file_index = self.index;
585 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;615 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 {...@@ -600,7 +630,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
600 }630 }
601631
602 global.value = 0;632 global.value = 0;
603 global.atom_index = 0;633 global.ref = .{ .index = 0, .file = 0 };
604 global.esym_index = esym_index;634 global.esym_index = esym_index;
605 global.file_index = self.index;635 global.file_index = self.index;
606 }636 }
...@@ -624,13 +654,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {...@@ -624,13 +654,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {
624 }654 }
625}655}
626656
627pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {657pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
628 const cpu_arch = elf_file.getTarget().cpu.arch;658 const cpu_arch = elf_file.getTarget().cpu.arch;
629 for (self.atoms.items) |atom_index| {659 for (self.atoms_indexes.items) |atom_index| {
630 const atom = elf_file.atom(atom_index) orelse continue;660 const atom_ptr = self.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) or661 const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
632 mem.eql(u8, atom.name(elf_file), ".eh_frame");662 mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame");
633 if (atom.flags.alive and is_eh_frame) atom.flags.alive = false;663 if (atom_ptr.alive and is_eh_frame) atom_ptr.alive = false;
634 }664 }
635}665}
636666
...@@ -648,9 +678,9 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO...@@ -648,9 +678,9 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
648 sym.st_shndx == elf.SHN_COMMON) continue;678 sym.st_shndx == elf.SHN_COMMON) continue;
649679
650 if (sym.st_shndx != elf.SHN_ABS) {680 if (sym.st_shndx != elf.SHN_ABS) {
651 const atom_index = self.atoms.items[sym.st_shndx];681 const atom_index = self.atoms_indexes.items[sym.st_shndx];
652 const atom = elf_file.atom(atom_index) orelse continue;682 const atom_ptr = self.atom(atom_index) orelse continue;
653 if (!atom.flags.alive) continue;683 if (!atom_ptr.alive) continue;
654 }684 }
655685
656 const gop = try dupes.getOrPut(index);686 const gop = try dupes.getOrPut(index);
...@@ -661,25 +691,24 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO...@@ -661,25 +691,24 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
661 }691 }
662}692}
663693
664pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {694pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
665 const gpa = elf_file.base.comp.gpa;695 const gpa = elf_file.base.comp.gpa;
666696
667 try self.merge_sections.resize(gpa, self.shdrs.items.len);697 try self.input_merge_sections.ensureUnusedCapacity(gpa, self.shdrs.items.len);
668 @memset(self.merge_sections.items, 0);698 try self.input_merge_sections_indexes.resize(gpa, self.shdrs.items.len);
699 @memset(self.input_merge_sections_indexes.items, 0);
669700
670 for (self.shdrs.items, 0..) |shdr, shndx| {701 for (self.shdrs.items, 0..) |shdr, shndx| {
671 if (shdr.sh_flags & elf.SHF_MERGE == 0) continue;702 if (shdr.sh_flags & elf.SHF_MERGE == 0) continue;
672703
673 const atom_index = self.atoms.items[shndx];704 const atom_index = self.atoms_indexes.items[shndx];
674 const atom_ptr = elf_file.atom(atom_index) orelse continue;705 const atom_ptr = self.atom(atom_index) orelse continue;
675 if (!atom_ptr.flags.alive) continue;706 if (!atom_ptr.alive) continue;
676 if (atom_ptr.relocs(elf_file).len > 0) continue;707 if (atom_ptr.relocs(elf_file).len > 0) continue;
677708
678 const imsec_idx = try elf_file.addInputMergeSection();709 const imsec_idx = try self.addInputMergeSection(gpa);
679 const imsec = elf_file.inputMergeSection(imsec_idx).?;710 const imsec = self.inputMergeSection(imsec_idx).?;
680 self.merge_sections.items[shndx] = imsec_idx;711 self.input_merge_sections_indexes.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);
683 imsec.atom_index = atom_index;712 imsec.atom_index = atom_index;
684713
685 const data = try self.codeDecompressAlloc(elf_file, atom_index);714 const data = try self.codeDecompressAlloc(elf_file, atom_index);
...@@ -734,18 +763,31 @@ pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -734,18 +763,31 @@ pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
734 }763 }
735 }764 }
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 );
738 }780 }
739}781}
740782
741pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {783pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
742 const gpa = elf_file.base.comp.gpa;784 const gpa = elf_file.base.comp.gpa;
743785
744 for (self.merge_sections.items) |index| {786 for (self.input_merge_sections_indexes.items) |index| {
745 const imsec = elf_file.inputMergeSection(index) orelse continue;787 const imsec = self.inputMergeSection(index) orelse continue;
746 if (imsec.offsets.items.len == 0) continue;788 if (imsec.offsets.items.len == 0) continue;
747 const msec = elf_file.mergeSection(imsec.merge_section_index);789 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).?;
749 const isec = atom_ptr.inputShdr(elf_file);791 const isec = atom_ptr.inputShdr(elf_file);
750792
751 try imsec.subsections.resize(gpa, imsec.strings.items.len);793 try imsec.subsections.resize(gpa, imsec.strings.items.len);
...@@ -754,8 +796,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -754,8 +796,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
754 const string = imsec.bytes.items[str.pos..][0..str.len];796 const string = imsec.bytes.items[str.pos..][0..str.len];
755 const res = try msec.insert(gpa, string);797 const res = try msec.insert(gpa, string);
756 if (!res.found_existing) {798 if (!res.found_existing) {
757 const msub_index = try elf_file.addMergeSubsection();799 const msub_index = try msec.addMergeSubsection(gpa);
758 const msub = elf_file.mergeSubsection(msub_index);800 const msub = msec.mergeSubsection(msub_index);
759 msub.merge_section_index = imsec.merge_section_index;801 msub.merge_section_index = imsec.merge_section_index;
760 msub.string_index = res.key.pos;802 msub.string_index = res.key.pos;
761 msub.alignment = atom_ptr.alignment;803 msub.alignment = atom_ptr.alignment;
...@@ -776,10 +818,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -776,10 +818,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
776818
777 if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;819 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];821 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
780 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;822 const imsec = self.inputMergeSection(imsec_index) orelse continue;
781 if (imsec.offsets.items.len == 0) continue;823 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 {
783 var err = try elf_file.base.addErrorWithNotes(2);825 var err = try elf_file.base.addErrorWithNotes(2);
784 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});826 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
785 try err.addNote("for symbol {s}", .{sym.name(elf_file)});827 try err.addNote("for symbol {s}", .{sym.name(elf_file)});
...@@ -787,45 +829,44 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -787,45 +829,44 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
787 return error.MalformedObject;829 return error.MalformedObject;
788 };830 };
789831
790 try sym.addExtra(.{ .subsection = msub_index }, elf_file);832 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
791 sym.flags.merge_subsection = true;833 sym.flags.merge_subsection = true;
792 sym.value = offset;834 sym.value = res.offset;
793 }835 }
794836
795 for (self.atoms.items) |atom_index| {837 for (self.atoms_indexes.items) |atom_index| {
796 const atom_ptr = elf_file.atom(atom_index) orelse continue;838 const atom_ptr = self.atom(atom_index) orelse continue;
797 if (!atom_ptr.flags.alive) continue;839 if (!atom_ptr.alive) continue;
798 const extras = atom_ptr.extra(elf_file) orelse continue;840 const extras = atom_ptr.extra(elf_file);
799 const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];841 const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];
800 for (relocs) |*rel| {842 for (relocs) |*rel| {
801 const esym = self.symtab.items[rel.r_sym()];843 const esym = self.symtab.items[rel.r_sym()];
802 if (esym.st_type() != elf.STT_SECTION) continue;844 if (esym.st_type() != elf.STT_SECTION) continue;
803845
804 const imsec_index = self.merge_sections.items[esym.st_shndx];846 const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
805 const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;847 const imsec = self.inputMergeSection(imsec_index) orelse continue;
806 if (imsec.offsets.items.len == 0) continue;848 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 {
808 var err = try elf_file.base.addErrorWithNotes(1);851 var err = try elf_file.base.addErrorWithNotes(1);
809 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});852 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
810 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });853 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
811 return error.MalformedObject;854 return error.MalformedObject;
812 };855 };
813 const msub = elf_file.mergeSubsection(msub_index);
814 const msec = msub.mergeSection(elf_file);
815856
816 const out_sym_idx: u64 = @intCast(self.symbols.items.len);857 const out_sym_idx: u64 = @intCast(self.symbols.items.len);
817 try self.symbols.ensureUnusedCapacity(gpa, 1);858 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 });
819 defer gpa.free(name);860 defer gpa.free(name);
820 const sym_index = try elf_file.addSymbol();861 const sym_index = try elf_file.addSymbol();
821 const sym = elf_file.symbol(sym_index);862 const sym = elf_file.symbol(sym_index);
822 sym.* = .{863 sym.* = .{
823 .value = @bitCast(@as(i64, @intCast(offset)) - rel.r_addend),864 .value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
824 .name_offset = try self.addString(gpa, name),865 .name_offset = try self.addString(gpa, name),
825 .esym_index = rel.r_sym(),866 .esym_index = rel.r_sym(),
826 .file_index = self.index,867 .file_index = self.index,
827 };868 };
828 try sym.addExtra(.{ .subsection = msub_index }, elf_file);869 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
829 sym.flags.merge_subsection = true;870 sym.flags.merge_subsection = true;
830 self.symbols.addOneAssumeCapacity().* = sym_index;871 self.symbols.addOneAssumeCapacity().* = sym_index;
831 rel.r_info = (out_sym_idx << 32) | rel.r_type();872 rel.r_info = (out_sym_idx << 32) | rel.r_type();
...@@ -857,21 +898,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -857,21 +898,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
857 const comp = elf_file.base.comp;898 const comp = elf_file.base.comp;
858 const gpa = comp.gpa;899 const gpa = comp.gpa;
859900
860 const atom_index = try elf_file.addAtom();
861 try self.atoms.append(gpa, atom_index);
862
863 const is_tls = global.type(elf_file) == elf.STT_TLS;901 const is_tls = global.type(elf_file) == elf.STT_TLS;
864 const name = if (is_tls) ".tls_common" else ".common";902 const name = if (is_tls) ".tls_common" else ".common";
865
866 const atom = elf_file.atom(atom_index).?;
867 const name_offset = @as(u32, @intCast(self.strtab.items.len));903 const name_offset = @as(u32, @intCast(self.strtab.items.len));
868 try self.strtab.writer(gpa).print("{s}\x00", .{name});904 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
876 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;906 var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
877 if (is_tls) sh_flags |= elf.SHF_TLS;907 if (is_tls) sh_flags |= elf.SHF_TLS;
...@@ -887,78 +917,84 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -887,78 +917,84 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
887 .sh_size = sh_size,917 .sh_size = sh_size,
888 .sh_link = 0,918 .sh_link = 0,
889 .sh_info = 0,919 .sh_info = 0,
890 .sh_addralign = alignment,920 .sh_addralign = this_sym.st_value,
891 .sh_entsize = 0,921 .sh_entsize = 0,
892 };922 };
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
895 global.value = 0;932 global.value = 0;
896 global.atom_index = atom_index;933 global.ref = .{ .index = atom_index, .file = self.index };
897 global.flags.weak = false;934 global.flags.weak = false;
898 }935 }
899}936}
900937
901pub fn initOutputSections(self: Object, elf_file: *Elf) !void {938pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
902 for (self.atoms.items) |atom_index| {939 for (self.comdat_groups.items, 0..) |*cg, cgi| {
903 const atom = elf_file.atom(atom_index) orelse continue;940 const signature = cg.signature(elf_file);
904 if (!atom.flags.alive) continue;941 const gop = try table.getOrPut(signature);
905 const shdr = atom.inputShdr(elf_file);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);
906 _ = try self.initOutputSection(elf_file, shdr);974 _ = try self.initOutputSection(elf_file, shdr);
907 }975 }
908}976}
909977
910pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {978pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
911 for (self.atoms.items) |atom_index| {979 for (self.atoms_indexes.items) |atom_index| {
912 const atom = elf_file.atom(atom_index) orelse continue;980 const atom_ptr = self.atom(atom_index) orelse continue;
913 if (!atom.flags.alive) continue;981 if (!atom_ptr.alive) continue;
914 const shdr = atom.inputShdr(elf_file);982 const shdr = atom_ptr.inputShdr(elf_file);
915 atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;983 atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
916984
917 const comp = elf_file.base.comp;985 const comp = elf_file.base.comp;
918 const gpa = comp.gpa;986 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);
920 if (!gop.found_existing) gop.value_ptr.* = .{};988 if (!gop.found_existing) gop.value_ptr.* = .{};
921 try gop.value_ptr.append(gpa, atom_index);989 try gop.value_ptr.append(gpa, .{ .index = atom_index, .file = self.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;
954 }990 }
955}991}
956992
957pub fn initRelaSections(self: Object, elf_file: *Elf) !void {993pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
958 for (self.atoms.items) |atom_index| {994 for (self.atoms_indexes.items) |atom_index| {
959 const atom = elf_file.atom(atom_index) orelse continue;995 const atom_ptr = self.atom(atom_index) orelse continue;
960 if (!atom.flags.alive) continue;996 if (!atom_ptr.alive) continue;
961 const shndx = atom.relocsShndx() orelse continue;997 const shndx = atom_ptr.relocsShndx() orelse continue;
962 const shdr = self.shdrs.items[shndx];998 const shdr = self.shdrs.items[shndx];
963 const out_shndx = try self.initOutputSection(elf_file, shdr);999 const out_shndx = try self.initOutputSection(elf_file, shdr);
964 const out_shdr = &elf_file.shdrs.items[out_shndx];1000 const out_shdr = &elf_file.shdrs.items[out_shndx];
...@@ -968,24 +1004,24 @@ pub fn initRelaSections(self: Object, elf_file: *Elf) !void {...@@ -968,24 +1004,24 @@ pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
968 }1004 }
969}1005}
9701006
971pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {1007pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
972 for (self.atoms.items) |atom_index| {1008 for (self.atoms_indexes.items) |atom_index| {
973 const atom = elf_file.atom(atom_index) orelse continue;1009 const atom_ptr = self.atom(atom_index) orelse continue;
974 if (!atom.flags.alive) continue;1010 if (!atom_ptr.alive) continue;
975 const shndx = blk: {1011 const shndx = blk: {
976 const shndx = atom.relocsShndx() orelse continue;1012 const shndx = atom_ptr.relocsShndx() orelse continue;
977 const shdr = self.shdrs.items[shndx];1013 const shdr = self.shdrs.items[shndx];
978 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;1014 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
979 };1015 };
980 const shdr = &elf_file.shdrs.items[shndx];1016 const shdr = &elf_file.shdrs.items[shndx];
981 shdr.sh_info = atom.outputShndx().?;1017 shdr.sh_info = atom_ptr.output_section_index;
982 shdr.sh_link = elf_file.symtab_section_index.?;1018 shdr.sh_link = elf_file.symtab_section_index.?;
9831019
984 const comp = elf_file.base.comp;1020 const comp = elf_file.base.comp;
985 const gpa = comp.gpa;1021 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);
987 if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };1023 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 });
989 }1025 }
990}1026}
9911027
...@@ -1041,7 +1077,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {...@@ -1041,7 +1077,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
1041 const isAlive = struct {1077 const isAlive = struct {
1042 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {1078 fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
1043 if (sym.mergeSubsection(ctx)) |msub| return msub.alive;1079 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;
1045 return true;1081 return true;
1046 }1082 }
1047 }.isAlive;1083 }.isAlive;
...@@ -1119,11 +1155,10 @@ pub fn globals(self: Object) []const Symbol.Index {...@@ -1119,11 +1155,10 @@ pub fn globals(self: Object) []const Symbol.Index {
11191155
1120/// Returns atom's code and optionally uncompresses data if required (for compressed sections).1156/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
1121/// Caller owns the memory.1157/// 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 {
1123 const comp = elf_file.base.comp;1159 const comp = elf_file.base.comp;
1124 const gpa = comp.gpa;1160 const gpa = comp.gpa;
1125 const atom_ptr = elf_file.atom(atom_index).?;1161 const atom_ptr = self.atom(atom_index).?;
1126 assert(atom_ptr.file_index == self.index);
1127 const shdr = atom_ptr.inputShdr(elf_file);1162 const shdr = atom_ptr.inputShdr(elf_file);
1128 const handle = elf_file.fileHandle(self.file_handle);1163 const handle = elf_file.fileHandle(self.file_handle);
1129 const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index);1164 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...@@ -1184,6 +1219,105 @@ fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shn
1184 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];1219 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
1185}1220}
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
1187pub fn format(1321pub fn format(
1188 self: *Object,1322 self: *Object,
1189 comptime unused_fmt_string: []const u8,1323 comptime unused_fmt_string: []const u8,
...@@ -1247,9 +1381,9 @@ fn formatAtoms(...@@ -1247,9 +1381,9 @@ fn formatAtoms(
1247 _ = options;1381 _ = options;
1248 const object = ctx.object;1382 const object = ctx.object;
1249 try writer.writeAll(" atoms\n");1383 try writer.writeAll(" atoms\n");
1250 for (object.atoms.items) |atom_index| {1384 for (object.atoms_indexes.items) |atom_index| {
1251 const atom = ctx.elf_file.atom(atom_index) orelse continue;1385 const atom_ptr = object.atom(atom_index) orelse continue;
1252 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});1386 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
1253 }1387 }
1254}1388}
12551389
...@@ -1315,16 +1449,15 @@ fn formatComdatGroups(...@@ -1315,16 +1449,15 @@ fn formatComdatGroups(
1315 const object = ctx.object;1449 const object = ctx.object;
1316 const elf_file = ctx.elf_file;1450 const elf_file = ctx.elf_file;
1317 try writer.writeAll(" COMDAT groups\n");1451 try writer.writeAll(" COMDAT groups\n");
1318 for (object.comdat_groups.items) |cg_index| {1452 for (object.comdat_groups.items, 0..) |cg, cg_index| {
1319 const cg = elf_file.comdatGroup(cg_index);1453 try writer.print(" COMDAT({d})", .{cg_index});
1320 const cg_owner = elf_file.comdatGroupOwner(cg.owner);1454 if (!cg.alive) try writer.writeAll(" : [*]");
1321 if (cg_owner.file != object.index) continue;1455 try writer.writeByte('\n');
1322 try writer.print(" COMDAT({d})\n", .{cg_index});
1323 const cg_members = cg.comdatGroupMembers(elf_file);1456 const cg_members = cg.comdatGroupMembers(elf_file);
1324 for (cg_members) |shndx| {1457 for (cg_members) |shndx| {
1325 const atom_index = object.atoms.items[shndx];1458 const atom_index = object.atoms_indexes.items[shndx];
1326 const atom = elf_file.atom(atom_index) orelse continue;1459 const atom_ptr = object.atom(atom_index) orelse continue;
1327 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });1460 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
1328 }1461 }
1329 }1462 }
1330}1463}
src/link/Elf/SharedObject.zig+1-1
...@@ -232,7 +232,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {...@@ -232,7 +232,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
232 const global = elf_file.symbol(index);232 const global = elf_file.symbol(index);
233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {233 if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
234 global.value = @intCast(this_sym.st_value);234 global.value = @intCast(this_sym.st_value);
235 global.atom_index = 0;235 global.ref = .{ .index = 0, .file = 0 };
236 global.esym_index = esym_index;236 global.esym_index = esym_index;
237 global.version_index = self.versyms.items[esym_index];237 global.version_index = self.versyms.items[esym_index];
238 global.file_index = self.index;238 global.file_index = self.index;
src/link/Elf/Symbol.zig+25-20
...@@ -9,10 +9,9 @@ name_offset: u32 = 0,...@@ -9,10 +9,9 @@ name_offset: u32 = 0,
9/// Index of file where this symbol is defined.9/// Index of file where this symbol is defined.
10file_index: File.Index = 0,10file_index: File.Index = 0,
1111
12/// Index of atom containing this symbol.12/// Reference to Atom or merge subsection containing this symbol if any.
13/// Index of 0 means there is no associated atom with this symbol.13/// Use `atom` or `mergeSubsection` to get the pointer to the atom.
14/// Use `atom` to get the pointer to the atom.14ref: Elf.Ref = .{ .index = 0, .file = 0 },
15atom_index: Atom.Index = 0,
1615
17/// Assigned output section index for this symbol.16/// Assigned output section index for this symbol.
18output_section_index: u32 = 0,17output_section_index: u32 = 0,
...@@ -34,11 +33,15 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {...@@ -34,11 +33,15 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
34 const file_ptr = symbol.file(elf_file).?;33 const file_ptr = symbol.file(elf_file).?;
35 if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;34 if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;
36 return !symbol.flags.import and symbol.atom(elf_file) == null and35 return !symbol.flags.import and symbol.atom(elf_file) == null and
37 symbol.mergeSubsection(elf_file) == null and symbol.outputShndx() == null and36 symbol.mergeSubsection(elf_file) == null and symbol.outputShndx(elf_file) == null and
38 file_ptr != .linker_defined;37 file_ptr != .linker_defined;
39}38}
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;
42 if (symbol.output_section_index == 0) return null;45 if (symbol.output_section_index == 0) return null;
43 return symbol.output_section_index;46 return symbol.output_section_index;
44}47}
...@@ -68,13 +71,15 @@ pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {...@@ -68,13 +71,15 @@ pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
68}71}
6972
70pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {73pub 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);
72}77}
7378
74pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {79pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {
75 if (!symbol.flags.merge_subsection) return null;80 if (!symbol.flags.merge_subsection) return null;
76 const extras = symbol.extra(elf_file).?;81 const msec = elf_file.mergeSection(symbol.ref.file);
77 return elf_file.mergeSubsection(extras.subsection);82 return msec.mergeSubsection(symbol.ref.index);
78}83}
7984
80pub fn file(symbol: Symbol, elf_file: *Elf) ?File {85pub 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...@@ -116,7 +121,7 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
116 return symbol.pltAddress(elf_file);121 return symbol.pltAddress(elf_file);
117 }122 }
118 if (symbol.atom(elf_file)) |atom_ptr| {123 if (symbol.atom(elf_file)) |atom_ptr| {
119 if (!atom_ptr.flags.alive) {124 if (!atom_ptr.alive) {
120 if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {125 if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {
121 const sym_name = symbol.name(elf_file);126 const sym_name = symbol.name(elf_file);
122 const sh_addr, const sh_size = blk: {127 const sh_addr, const sh_size = blk: {
...@@ -258,7 +263,6 @@ const AddExtraOpts = struct {...@@ -258,7 +263,6 @@ const AddExtraOpts = struct {
258 gottp: ?u32 = null,263 gottp: ?u32 = null,
259 tlsdesc: ?u32 = null,264 tlsdesc: ?u32 = null,
260 zig_got: ?u32 = null,265 zig_got: ?u32 = null,
261 subsection: ?u32 = null,
262};266};
263267
264pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {268pub 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 {...@@ -298,7 +302,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
298 if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;302 if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
299 if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index);303 if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index);
300 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;304 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);
302 };306 };
303 const st_value = blk: {307 const st_value = blk: {
304 if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);308 if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);
...@@ -382,22 +386,23 @@ fn format2(...@@ -382,22 +386,23 @@ fn format2(
382 _ = options;386 _ = options;
383 _ = unused_fmt_string;387 _ = unused_fmt_string;
384 const symbol = ctx.symbol;388 const symbol = ctx.symbol;
389 const elf_file = ctx.elf_file;
385 try writer.print("%{d} : {s} : @{x}", .{390 try writer.print("%{d} : {s} : @{x}", .{
386 symbol.esym_index,391 symbol.esym_index,
387 symbol.fmtName(ctx.elf_file),392 symbol.fmtName(elf_file),
388 symbol.address(.{}, ctx.elf_file),393 symbol.address(.{}, elf_file),
389 });394 });
390 if (symbol.file(ctx.elf_file)) |file_ptr| {395 if (symbol.file(elf_file)) |file_ptr| {
391 if (symbol.isAbs(ctx.elf_file)) {396 if (symbol.isAbs(elf_file)) {
392 if (symbol.elfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {397 if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) {
393 try writer.writeAll(" : undef");398 try writer.writeAll(" : undef");
394 } else {399 } else {
395 try writer.writeAll(" : absolute");400 try writer.writeAll(" : absolute");
396 }401 }
397 } else if (symbol.outputShndx()) |shndx| {402 } else if (symbol.outputShndx(elf_file)) |shndx| {
398 try writer.print(" : shdr({d})", .{shndx});403 try writer.print(" : shdr({d})", .{shndx});
399 }404 }
400 if (symbol.atom(ctx.elf_file)) |atom_ptr| {405 if (symbol.atom(elf_file)) |atom_ptr| {
401 try writer.print(" : atom({d})", .{atom_ptr.atom_index});406 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
402 }407 }
403 var buf: [2]u8 = .{'_'} ** 2;408 var buf: [2]u8 = .{'_'} ** 2;
...@@ -483,7 +488,7 @@ pub const Extra = struct {...@@ -483,7 +488,7 @@ pub const Extra = struct {
483 gottp: u32 = 0,488 gottp: u32 = 0,
484 tlsdesc: u32 = 0,489 tlsdesc: u32 = 0,
485 zig_got: u32 = 0,490 zig_got: u32 = 0,
486 subsection: u32 = 0,491 merge_section: u32 = 0,
487};492};
488493
489pub const Index = u32;494pub const Index = u32;
src/link/Elf/ZigObject.zig+138-82
...@@ -15,7 +15,9 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},...@@ -15,7 +15,9 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
15global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},15global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
16globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},16globals_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) = .{},
19relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},21relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
2022
21num_dynrelocs: u32 = 0,23num_dynrelocs: u32 = 0,
...@@ -80,7 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -80,7 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
80 const comp = elf_file.base.comp;82 const comp = elf_file.base.comp;
81 const gpa = comp.gpa;83 const gpa = comp.gpa;
8284
83 try self.atoms.append(gpa, 0); // null input section85 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
84 try self.relocs.append(gpa, .{}); // null relocs section86 try self.relocs.append(gpa, .{}); // null relocs section
85 try self.strtab.buffer.append(gpa, 0);87 try self.strtab.buffer.append(gpa, 0);
8688
...@@ -117,6 +119,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -117,6 +119,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
117 self.global_symbols.deinit(allocator);119 self.global_symbols.deinit(allocator);
118 self.globals_lookup.deinit(allocator);120 self.globals_lookup.deinit(allocator);
119 self.atoms.deinit(allocator);121 self.atoms.deinit(allocator);
122 self.atoms_indexes.deinit(allocator);
123 self.atoms_extra.deinit(allocator);
120 for (self.relocs.items) |*list| {124 for (self.relocs.items) |*list| {
121 list.deinit(allocator);125 list.deinit(allocator);
122 }126 }
...@@ -276,24 +280,20 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {...@@ -276,24 +280,20 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
276 return index | global_symbol_bit;280 return index | global_symbol_bit;
277}281}
278282
279pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {283pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
280 const gpa = elf_file.base.comp.gpa;284 const gpa = elf_file.base.comp.gpa;
281 const atom_index = try elf_file.addAtom();285 const atom_index = try self.addAtom(gpa);
282 const symbol_index = try elf_file.addSymbol();286 const symbol_index = try elf_file.addSymbol();
283 const esym_index = try self.addLocalEsym(gpa);287 const esym_index = try self.addLocalEsym(gpa);
284288
285 const shndx = @as(u32, @intCast(self.atoms.items.len));289 try self.atoms_indexes.append(gpa, atom_index);
286 try self.atoms.append(gpa, atom_index);
287 try self.local_symbols.append(gpa, symbol_index);290 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
292 const symbol_ptr = elf_file.symbol(symbol_index);292 const symbol_ptr = elf_file.symbol(symbol_index);
293 symbol_ptr.file_index = self.index;293 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;
297 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;297 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
298 symbol_ptr.esym_index = esym_index;298 symbol_ptr.esym_index = esym_index;
299299
...@@ -301,21 +301,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {...@@ -301,21 +301,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
301 const relocs_index = @as(u32, @intCast(self.relocs.items.len));301 const relocs_index = @as(u32, @intCast(self.relocs.items.len));
302 const relocs = try self.relocs.addOne(gpa);302 const relocs = try self.relocs.addOne(gpa);
303 relocs.* = .{};303 relocs.* = .{};
304
305 const atom_ptr = self.atom(atom_index).?;
304 atom_ptr.relocs_section_index = relocs_index;306 atom_ptr.relocs_section_index = relocs_index;
305307
306 return symbol_index;308 return symbol_index;
307}309}
308310
309/// TODO actually create fake input shdrs and return that instead.311/// 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 {312pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
311 _ = self;313 const atom_ptr = self.atom(atom_index) orelse return Elf.null_shdr;
312 const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr;314 const shndx = atom_ptr.output_section_index;
313 const shndx = atom.outputShndx() orelse return Elf.null_shdr;
314 var shdr = elf_file.shdrs.items[shndx];315 var shdr = elf_file.shdrs.items[shndx];
315 shdr.sh_addr = 0;316 shdr.sh_addr = 0;
316 shdr.sh_offset = 0;317 shdr.sh_offset = 0;
317 shdr.sh_size = atom.size;318 shdr.sh_size = atom_ptr.size;
318 shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;319 shdr.sh_addralign = atom_ptr.alignment.toByteUnits() orelse 1;
319 return shdr;320 return shdr;
320}321}
321322
...@@ -329,27 +330,21 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {...@@ -329,27 +330,21 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
329330
330 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {331 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
331 assert(esym.st_shndx == SHN_ATOM);332 assert(esym.st_shndx == SHN_ATOM);
332 const atom_index = self.atoms.items[shndx];333 const atom_ptr = self.atom(shndx) orelse continue;
333 const atom = elf_file.atom(atom_index) orelse continue;334 if (!atom_ptr.alive) continue;
334 if (!atom.flags.alive) continue;
335 }335 }
336336
337 const global = elf_file.symbol(index);337 const global = elf_file.symbol(index);
338 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {338 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
339 const atom_index = switch (esym.st_shndx) {339 const atom_index = switch (esym.st_shndx) {
340 elf.SHN_ABS, elf.SHN_COMMON => 0,340 elf.SHN_ABS, elf.SHN_COMMON => 0,
341 SHN_ATOM => self.atoms.items[shndx],341 SHN_ATOM => shndx,
342 else => unreachable,342 else => unreachable,
343 };343 };
344 const output_section_index = if (elf_file.atom(atom_index)) |atom|
345 atom.outputShndx().?
346 else
347 elf.SHN_UNDEF;
348 global.value = @intCast(esym.st_value);344 global.value = @intCast(esym.st_value);
349 global.atom_index = atom_index;345 global.ref = .{ .index = atom_index, .file = self.index };
350 global.esym_index = esym_index;346 global.esym_index = esym_index;
351 global.file_index = self.index;347 global.file_index = self.index;
352 global.output_section_index = output_section_index;
353 global.version_index = elf_file.default_sym_version;348 global.version_index = elf_file.default_sym_version;
354 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;349 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
355 }350 }
...@@ -376,7 +371,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {...@@ -376,7 +371,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
376 };371 };
377372
378 global.value = 0;373 global.value = 0;
379 global.atom_index = 0;374 global.ref = .{ .index = 0, .file = 0 };
380 global.esym_index = esym_index;375 global.esym_index = esym_index;
381 global.file_index = self.index;376 global.file_index = self.index;
382 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;377 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 {...@@ -397,7 +392,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
397 }392 }
398393
399 global.value = 0;394 global.value = 0;
400 global.atom_index = 0;395 global.ref = .{ .index = 0, .file = 0 };
401 global.esym_index = esym_index;396 global.esym_index = esym_index;
402 global.file_index = self.index;397 global.file_index = self.index;
403 }398 }
...@@ -405,19 +400,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {...@@ -405,19 +400,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
405400
406pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {401pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
407 const gpa = elf_file.base.comp.gpa;402 const gpa = elf_file.base.comp.gpa;
408 for (self.atoms.items) |atom_index| {403 for (self.atoms_indexes.items) |atom_index| {
409 const atom = elf_file.atom(atom_index) orelse continue;404 const atom_ptr = self.atom(atom_index) orelse continue;
410 if (!atom.flags.alive) continue;405 if (!atom_ptr.alive) continue;
411 const shdr = atom.inputShdr(elf_file);406 const shdr = atom_ptr.inputShdr(elf_file);
412 if (shdr.sh_type == elf.SHT_NOBITS) continue;407 if (shdr.sh_type == elf.SHT_NOBITS) continue;
413 if (atom.scanRelocsRequiresCode(elf_file)) {408 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
414 // TODO ideally we don't have to fetch the code here.409 // TODO ideally we don't have to fetch the code here.
415 // Perhaps it would make sense to save the code until flushModule where we410 // Perhaps it would make sense to save the code until flushModule where we
416 // would free all of generated code?411 // would free all of generated code?
417 const code = try self.codeAlloc(elf_file, atom_index);412 const code = try self.codeAlloc(elf_file, atom_index);
418 defer gpa.free(code);413 defer gpa.free(code);
419 try atom.scanRelocs(elf_file, code, undefs);414 try atom_ptr.scanRelocs(elf_file, code, undefs);
420 } else try atom.scanRelocs(elf_file, null, undefs);415 } else try atom_ptr.scanRelocs(elf_file, null, undefs);
421 }416 }
422}417}
423418
...@@ -450,9 +445,8 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O...@@ -450,9 +445,8 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
450 esym.st_shndx == elf.SHN_COMMON) continue;445 esym.st_shndx == elf.SHN_COMMON) continue;
451446
452 if (esym.st_shndx == SHN_ATOM) {447 if (esym.st_shndx == SHN_ATOM) {
453 const atom_index = self.atoms.items[shndx];448 const atom_ptr = self.atom(shndx) orelse continue;
454 const atom = elf_file.atom(atom_index) orelse continue;449 if (!atom_ptr.alive) continue;
455 if (!atom.flags.alive) continue;
456 }450 }
457451
458 const gop = try dupes.getOrPut(index);452 const gop = try dupes.getOrPut(index);
...@@ -493,7 +487,7 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *...@@ -493,7 +487,7 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *
493 const global = elf_file.symbol(global_index);487 const global = elf_file.symbol(global_index);
494 const file_ptr = global.file(elf_file).?;488 const file_ptr = global.file(elf_file).?;
495 assert(file_ptr.index() == self.index);489 assert(file_ptr.index() == self.index);
496 if (global.outputShndx() == null) continue;490 if (global.outputShndx(elf_file) == null) continue;
497491
498 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));492 const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
499 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });493 ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
...@@ -517,20 +511,20 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {...@@ -517,20 +511,20 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
517 try writer.writeAll(self.data.items);511 try writer.writeAll(self.data.items);
518}512}
519513
520pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {514pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
521 for (self.atoms.items) |atom_index| {515 for (self.atoms_indexes.items) |atom_index| {
522 const atom = elf_file.atom(atom_index) orelse continue;516 const atom_ptr = self.atom(atom_index) orelse continue;
523 if (!atom.flags.alive) continue;517 if (!atom_ptr.alive) continue;
524 const rela_shndx = atom.relocsShndx() orelse continue;518 const rela_shndx = atom_ptr.relocsShndx() orelse continue;
525 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level519 // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
526 if (self.relocs.items[rela_shndx].items.len == 0) continue;520 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;
528 const out_shdr = elf_file.shdrs.items[out_shndx];522 const out_shdr = elf_file.shdrs.items[out_shndx];
529 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;523 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
530524
531 const gpa = elf_file.base.comp.gpa;525 const gpa = elf_file.base.comp.gpa;
532 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;526 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 });
534 }528 }
535}529}
536530
...@@ -561,7 +555,7 @@ pub fn globals(self: ZigObject) []const Symbol.Index {...@@ -561,7 +555,7 @@ pub fn globals(self: ZigObject) []const Symbol.Index {
561pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {555pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
562 for (self.locals()) |local_index| {556 for (self.locals()) |local_index| {
563 const local = elf_file.symbol(local_index);557 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;
565 const esym = local.elfSym(elf_file);559 const esym = local.elfSym(elf_file);
566 switch (esym.st_type()) {560 switch (esym.st_type()) {
567 elf.STT_SECTION, elf.STT_NOTYPE => continue,561 elf.STT_SECTION, elf.STT_NOTYPE => continue,
...@@ -577,7 +571,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {...@@ -577,7 +571,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
577 const global = elf_file.symbol(global_index);571 const global = elf_file.symbol(global_index);
578 const file_ptr = global.file(elf_file) orelse continue;572 const file_ptr = global.file(elf_file) orelse continue;
579 if (file_ptr.index() != self.index) continue;573 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;
581 global.flags.output_symtab = true;575 global.flags.output_symtab = true;
582 if (global.isLocal(elf_file)) {576 if (global.isLocal(elf_file)) {
583 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);577 try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
...@@ -621,11 +615,10 @@ pub fn asFile(self: *ZigObject) File {...@@ -621,11 +615,10 @@ pub fn asFile(self: *ZigObject) File {
621615
622/// Returns atom's code.616/// Returns atom's code.
623/// Caller owns the memory.617/// 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 {
625 const gpa = elf_file.base.comp.gpa;619 const gpa = elf_file.base.comp.gpa;
626 const atom = elf_file.atom(atom_index).?;620 const atom_ptr = self.atom(atom_index).?;
627 assert(atom.file_index == self.index);621 const shdr = &elf_file.shdrs.items[atom_ptr.output_section_index];
628 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
629622
630 if (shdr.sh_flags & elf.SHF_TLS != 0) {623 if (shdr.sh_flags & elf.SHF_TLS != 0) {
631 const tlv = self.tls_variables.get(atom_index).?;624 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...@@ -633,13 +626,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
633 return code;626 return code;
634 }627 }
635628
636 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value));629 const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
637 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;630 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
638 const code = try gpa.alloc(u8, size);631 const code = try gpa.alloc(u8, size);
639 errdefer gpa.free(code);632 errdefer gpa.free(code);
640 const amt = try elf_file.base.file.?.preadAll(code, file_offset);633 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
641 if (amt != code.len) {634 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)});
643 return error.InputOutput;636 return error.InputOutput;
644 }637 }
645 return code;638 return code;
...@@ -760,7 +753,7 @@ pub fn getOrCreateMetadataForLazySymbol(...@@ -760,7 +753,7 @@ pub fn getOrCreateMetadataForLazySymbol(
760 };753 };
761 switch (metadata.state.*) {754 switch (metadata.state.*) {
762 .unused => {755 .unused => {
763 const symbol_index = try self.addAtom(elf_file);756 const symbol_index = try self.newAtom(elf_file);
764 const sym = elf_file.symbol(symbol_index);757 const sym = elf_file.symbol(symbol_index);
765 sym.flags.needs_zig_got = true;758 sym.flags.needs_zig_got = true;
766 metadata.symbol_index.* = symbol_index;759 metadata.symbol_index.* = symbol_index;
...@@ -824,7 +817,7 @@ pub fn getOrCreateMetadataForDecl(...@@ -824,7 +817,7 @@ pub fn getOrCreateMetadataForDecl(
824 const gop = try self.decls.getOrPut(gpa, decl_index);817 const gop = try self.decls.getOrPut(gpa, decl_index);
825 if (!gop.found_existing) {818 if (!gop.found_existing) {
826 const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;819 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);
828 const mod = elf_file.base.comp.module.?;821 const mod = elf_file.base.comp.module.?;
829 const decl = mod.declPtr(decl_index);822 const decl = mod.declPtr(decl_index);
830 const sym = elf_file.symbol(symbol_index);823 const sym = elf_file.symbol(symbol_index);
...@@ -861,14 +854,14 @@ fn getDeclShdrIndex(...@@ -861,14 +854,14 @@ fn getDeclShdrIndex(
861 if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{854 if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
862 .type = elf.SHT_NOBITS,855 .type = elf.SHT_NOBITS,
863 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,856 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
864 .name = ".tbss",857 .name = try elf_file.insertShString(".tbss"),
865 .offset = std.math.maxInt(u64),858 .offset = std.math.maxInt(u64),
866 });859 });
867860
868 break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{861 break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
869 .type = elf.SHT_PROGBITS,862 .type = elf.SHT_PROGBITS,
870 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,863 .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
871 .name = ".tdata",864 .name = try elf_file.insertShString(".tdata"),
872 .offset = std.math.maxInt(u64),865 .offset = std.math.maxInt(u64),
873 });866 });
874 }867 }
...@@ -919,14 +912,13 @@ fn updateDeclCode(...@@ -919,14 +912,13 @@ fn updateDeclCode(
919 const sym = elf_file.symbol(sym_index);912 const sym = elf_file.symbol(sym_index);
920 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];913 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
921 const atom_ptr = sym.atom(elf_file).?;914 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;
924 atom_ptr.output_section_index = shdr_index;919 atom_ptr.output_section_index = shdr_index;
925920 sym.name_offset = name_offset;
926 sym.name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));921 esym.st_name = name_offset;
927 atom_ptr.flags.alive = true;
928 atom_ptr.name_offset = sym.name_offset;
929 esym.st_name = sym.name_offset;
930 esym.st_info |= stt_bits;922 esym.st_info |= stt_bits;
931 esym.st_size = code.len;923 esym.st_size = code.len;
932924
...@@ -1018,16 +1010,17 @@ fn updateTlv(...@@ -1018,16 +1010,17 @@ fn updateTlv(
1018 const sym = elf_file.symbol(sym_index);1010 const sym = elf_file.symbol(sym_index);
1019 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];1011 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
1020 const atom_ptr = sym.atom(elf_file).?;1012 const atom_ptr = sym.atom(elf_file).?;
1013 const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
10211014
1022 sym.value = 0;1015 sym.value = 0;
1023 sym.output_section_index = shndx;1016 sym.name_offset = name_offset;
1017
1024 atom_ptr.output_section_index = shndx;1018 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;
1029 esym.st_value = 0;1022 esym.st_value = 0;
1030 esym.st_name = sym.name_offset;1023 esym.st_name = name_offset;
1031 esym.st_info = elf.STT_TLS;1024 esym.st_info = elf.STT_TLS;
1032 esym.st_size = code.len;1025 esym.st_size = code.len;
10331026
...@@ -1048,7 +1041,7 @@ fn updateTlv(...@@ -1048,7 +1041,7 @@ fn updateTlv(
1048 {1041 {
1049 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);1042 const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
1050 if (!gop.found_existing) gop.value_ptr.* = .{};1043 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 });
1052 }1045 }
1053}1046}
10541047
...@@ -1242,13 +1235,12 @@ fn updateLazySymbol(...@@ -1242,13 +1235,12 @@ fn updateLazySymbol(
1242 };1235 };
1243 const local_sym = elf_file.symbol(symbol_index);1236 const local_sym = elf_file.symbol(symbol_index);
1244 local_sym.name_offset = name_str_index;1237 local_sym.name_offset = name_str_index;
1245 local_sym.output_section_index = output_section_index;
1246 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1238 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1247 local_esym.st_name = name_str_index;1239 local_esym.st_name = name_str_index;
1248 local_esym.st_info |= elf.STT_OBJECT;1240 local_esym.st_info |= elf.STT_OBJECT;
1249 local_esym.st_size = code.len;1241 local_esym.st_size = code.len;
1250 const atom_ptr = local_sym.atom(elf_file).?;1242 const atom_ptr = local_sym.atom(elf_file).?;
1251 atom_ptr.flags.alive = true;1243 atom_ptr.alive = true;
1252 atom_ptr.name_offset = name_str_index;1244 atom_ptr.name_offset = name_str_index;
1253 atom_ptr.alignment = required_alignment;1245 atom_ptr.alignment = required_alignment;
1254 atom_ptr.size = code.len;1246 atom_ptr.size = code.len;
...@@ -1307,8 +1299,7 @@ pub fn lowerUnnamedConst(...@@ -1307,8 +1299,7 @@ pub fn lowerUnnamedConst(
1307 return error.CodegenFail;1299 return error.CodegenFail;
1308 },1300 },
1309 };1301 };
1310 const sym = elf_file.symbol(sym_index);1302 try unnamed_consts.append(gpa, sym_index);
1311 try unnamed_consts.append(gpa, sym.atom_index);
1312 return sym_index;1303 return sym_index;
1313}1304}
13141305
...@@ -1332,7 +1323,7 @@ fn lowerConst(...@@ -1332,7 +1323,7 @@ fn lowerConst(
1332 var code_buffer = std.ArrayList(u8).init(gpa);1323 var code_buffer = std.ArrayList(u8).init(gpa);
1333 defer code_buffer.deinit();1324 defer code_buffer.deinit();
13341325
1335 const sym_index = try self.addAtom(elf_file);1326 const sym_index = try self.newAtom(elf_file);
13361327
1337 const res = try codegen.generateSymbol(1328 const res = try codegen.generateSymbol(
1338 &elf_file.base,1329 &elf_file.base,
...@@ -1351,13 +1342,12 @@ fn lowerConst(...@@ -1351,13 +1342,12 @@ fn lowerConst(
1351 const local_sym = elf_file.symbol(sym_index);1342 const local_sym = elf_file.symbol(sym_index);
1352 const name_str_index = try self.strtab.insert(gpa, name);1343 const name_str_index = try self.strtab.insert(gpa, name);
1353 local_sym.name_offset = name_str_index;1344 local_sym.name_offset = name_str_index;
1354 local_sym.output_section_index = output_section_index;
1355 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];1345 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1356 local_esym.st_name = name_str_index;1346 local_esym.st_name = name_str_index;
1357 local_esym.st_info |= elf.STT_OBJECT;1347 local_esym.st_info |= elf.STT_OBJECT;
1358 local_esym.st_size = code.len;1348 local_esym.st_size = code.len;
1359 const atom_ptr = local_sym.atom(elf_file).?;1349 const atom_ptr = local_sym.atom(elf_file).?;
1360 atom_ptr.flags.alive = true;1350 atom_ptr.alive = true;
1361 atom_ptr.name_offset = name_str_index;1351 atom_ptr.name_offset = name_str_index;
1362 atom_ptr.alignment = required_alignment;1352 atom_ptr.alignment = required_alignment;
1363 atom_ptr.size = code.len;1353 atom_ptr.size = code.len;
...@@ -1530,6 +1520,72 @@ pub fn getString(self: ZigObject, off: u32) [:0]const u8 {...@@ -1530,6 +1520,72 @@ pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
1530 return self.strtab.getAssumeExists(off);1520 return self.strtab.getAssumeExists(off);
1531}1521}
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
1533pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {1589pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1534 return .{ .data = .{1590 return .{ .data = .{
1535 .self = self,1591 .self = self,
...@@ -1578,9 +1634,9 @@ fn formatAtoms(...@@ -1578,9 +1634,9 @@ fn formatAtoms(
1578 _ = unused_fmt_string;1634 _ = unused_fmt_string;
1579 _ = options;1635 _ = options;
1580 try writer.writeAll(" atoms\n");1636 try writer.writeAll(" atoms\n");
1581 for (ctx.self.atoms.items) |atom_index| {1637 for (ctx.self.atoms_indexes.items) |atom_index| {
1582 const atom = ctx.elf_file.atom(atom_index) orelse continue;1638 const atom_ptr = ctx.self.atom(atom_index) orelse continue;
1583 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});1639 try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
1584 }1640 }
1585}1641}
15861642
src/link/Elf/eh_frame.zig+3-3
...@@ -42,8 +42,8 @@ pub const Fde = struct {...@@ -42,8 +42,8 @@ pub const Fde = struct {
42 const object = elf_file.file(fde.file_index).?.object;42 const object = elf_file.file(fde.file_index).?.object;
43 const rel = fde.relocs(elf_file)[0];43 const rel = fde.relocs(elf_file)[0];
44 const sym = object.symtab.items[rel.r_sym()];44 const sym = object.symtab.items[rel.r_sym()];
45 const atom_index = object.atoms.items[sym.st_shndx];45 const atom_index = object.atoms_indexes.items[sym.st_shndx];
46 return elf_file.atom(atom_index).?;46 return object.atom(atom_index).?;
47 }47 }
4848
49 pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {49 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...@@ -421,7 +421,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re
421 switch (sym.type(elf_file)) {421 switch (sym.type(elf_file)) {
422 elf.STT_SECTION => {422 elf.STT_SECTION => {
423 r_addend += @intCast(sym.address(.{}, elf_file));423 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).?);
425 },425 },
426 else => {426 else => {
427 r_sym = sym.outputSymtabIndex(elf_file) orelse 0;427 r_sym = sym.outputSymtabIndex(elf_file) orelse 0;
src/link/Elf/file.zig+39-3
...@@ -98,11 +98,34 @@ pub const File = union(enum) {...@@ -98,11 +98,34 @@ pub const File = union(enum) {
98 }98 }
99 }99 }
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
101 pub fn atoms(file: File) []const Atom.Index {109 pub fn atoms(file: File) []const Atom.Index {
102 return switch (file) {110 return switch (file) {
103 .linker_defined, .shared_object => &[0]Atom.Index{},111 .shared_object => unreachable,
104 .zig_object => |x| x.atoms.items,112 .linker_defined => &[0]Atom.Index{},
105 .object => |x| x.atoms.items,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),
106 };129 };
107 }130 }
108131
...@@ -114,6 +137,13 @@ pub const File = union(enum) {...@@ -114,6 +137,13 @@ pub const File = union(enum) {
114 };137 };
115 }138 }
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
117 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {147 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
118 return switch (file) {148 return switch (file) {
119 .zig_object => |x| x.symbol(ind),149 .zig_object => |x| x.symbol(ind),
...@@ -134,6 +164,12 @@ pub const File = union(enum) {...@@ -134,6 +164,12 @@ pub const File = union(enum) {
134 };164 };
135 }165 }
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
137 pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {173 pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
138 return switch (file) {174 return switch (file) {
139 inline else => |x| x.updateSymtabSize(elf_file),175 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 {...@@ -16,9 +16,11 @@ pub fn gcAtoms(elf_file: *Elf) !void {
16}16}
1717
18fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {18fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {
19 if (elf_file.entry_index) |index| {19 if (elf_file.linkerDefinedPtr()) |obj| {
20 const global = elf_file.symbol(index);20 if (obj.entry_index) |index| {
21 try markSymbol(global, roots, elf_file);21 const global = elf_file.symbol(index);
22 try markSymbol(global, roots, elf_file);
23 }
22 }24 }
2325
24 for (files) |index| {26 for (files) |index| {
...@@ -35,8 +37,8 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil...@@ -35,8 +37,8 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
35 const file = elf_file.file(index).?;37 const file = elf_file.file(index).?;
3638
37 for (file.atoms()) |atom_index| {39 for (file.atoms()) |atom_index| {
38 const atom = elf_file.atom(atom_index) orelse continue;40 const atom = file.atom(atom_index) orelse continue;
39 if (!atom.flags.alive) continue;41 if (!atom.alive) continue;
4042
41 const shdr = atom.inputShdr(elf_file);43 const shdr = atom.inputShdr(elf_file);
42 const name = atom.name(elf_file);44 const name = atom.name(elf_file);
...@@ -54,7 +56,7 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil...@@ -54,7 +56,7 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
54 break :blk false;56 break :blk false;
55 };57 };
56 if (is_gc_root and markAtom(atom)) try roots.append(atom);58 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;
58 }60 }
5961
60 // Mark every atom referenced by CIE as alive.62 // Mark every atom referenced by CIE as alive.
...@@ -77,22 +79,22 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void...@@ -77,22 +79,22 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void
77}79}
7880
79fn markAtom(atom: *Atom) bool {81fn markAtom(atom: *Atom) bool {
80 const already_visited = atom.flags.visited;82 const already_visited = atom.visited;
81 atom.flags.visited = true;83 atom.visited = true;
82 return atom.flags.alive and !already_visited;84 return atom.alive and !already_visited;
83}85}
8486
85fn markLive(atom: *Atom, elf_file: *Elf) void {87fn markLive(atom: *Atom, elf_file: *Elf) void {
86 if (@import("build_options").enable_logging) track_live_level.incr();88 if (@import("build_options").enable_logging) track_live_level.incr();
8789
88 assert(atom.flags.visited);90 assert(atom.visited);
89 const file = atom.file(elf_file).?;91 const file = atom.file(elf_file).?;
9092
91 for (atom.fdes(elf_file)) |fde| {93 for (atom.fdes(elf_file)) |fde| {
92 for (fde.relocs(elf_file)[1..]) |rel| {94 for (fde.relocs(elf_file)[1..]) |rel| {
93 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));95 const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
94 const target_atom = target_sym.atom(elf_file) orelse continue;96 const target_atom = target_sym.atom(elf_file) orelse continue;
95 target_atom.flags.alive = true;97 target_atom.alive = true;
96 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });98 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
97 if (markAtom(target_atom)) markLive(target_atom, elf_file);99 if (markAtom(target_atom)) markLive(target_atom, elf_file);
98 }100 }
...@@ -105,7 +107,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {...@@ -105,7 +107,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
105 continue;107 continue;
106 }108 }
107 const target_atom = target_sym.atom(elf_file) orelse continue;109 const target_atom = target_sym.atom(elf_file) orelse continue;
108 target_atom.flags.alive = true;110 target_atom.alive = true;
109 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });111 gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
110 if (markAtom(target_atom)) markLive(target_atom, elf_file);112 if (markAtom(target_atom)) markLive(target_atom, elf_file);
111 }113 }
...@@ -120,10 +122,11 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {...@@ -120,10 +122,11 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
120122
121fn prune(files: []const File.Index, elf_file: *Elf) void {123fn prune(files: []const File.Index, elf_file: *Elf) void {
122 for (files) |index| {124 for (files) |index| {
123 for (elf_file.file(index).?.atoms()) |atom_index| {125 const file = elf_file.file(index).?;
124 const atom = elf_file.atom(atom_index) orelse continue;126 for (file.atoms()) |atom_index| {
125 if (atom.flags.alive and !atom.flags.visited) {127 const atom = file.atom(atom_index) orelse continue;
126 atom.flags.alive = false;128 if (atom.alive and !atom.visited) {
129 atom.alive = false;
127 atom.markFdesDead(elf_file);130 atom.markFdesDead(elf_file);
128 }131 }
129 }132 }
...@@ -133,9 +136,10 @@ fn prune(files: []const File.Index, elf_file: *Elf) void {...@@ -133,9 +136,10 @@ fn prune(files: []const File.Index, elf_file: *Elf) void {
133pub fn dumpPrunedAtoms(elf_file: *Elf) !void {136pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
134 const stderr = std.io.getStdErr().writer();137 const stderr = std.io.getStdErr().writer();
135 for (elf_file.objects.items) |index| {138 for (elf_file.objects.items) |index| {
136 for (elf_file.file(index).?.object.atoms.items) |atom_index| {139 const file = elf_file.file(index).?;
137 const atom = elf_file.atom(atom_index) orelse continue;140 for (file.atoms()) |atom_index| {
138 if (!atom.flags.alive)141 const atom = file.atom(atom_index) orelse continue;
142 if (!atom.alive)
139 // TODO should we simply print to stderr?143 // TODO should we simply print to stderr?
140 try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{144 try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{
141 atom.name(elf_file),145 atom.name(elf_file),
src/link/Elf/merge_section.zig+40-17
...@@ -10,16 +10,18 @@ pub const MergeSection = struct {...@@ -10,16 +10,18 @@ pub const MergeSection = struct {
10 IndexContext,10 IndexContext,
11 std.hash_map.default_max_load_percentage,11 std.hash_map.default_max_load_percentage,
12 ) = .{},12 ) = .{},
13 subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},13 subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
14 finalized_subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},
1415
15 pub fn deinit(msec: *MergeSection, allocator: Allocator) void {16 pub fn deinit(msec: *MergeSection, allocator: Allocator) void {
16 msec.bytes.deinit(allocator);17 msec.bytes.deinit(allocator);
17 msec.table.deinit(allocator);18 msec.table.deinit(allocator);
18 msec.subsections.deinit(allocator);19 msec.subsections.deinit(allocator);
20 msec.finalized_subsections.deinit(allocator);
19 }21 }
2022
21 pub fn name(msec: MergeSection, elf_file: *Elf) [:0]const u8 {23 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);
23 }25 }
2426
25 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {27 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
...@@ -58,25 +60,26 @@ pub const MergeSection = struct {...@@ -58,25 +60,26 @@ pub const MergeSection = struct {
5860
59 /// Finalizes the merge section and clears hash table.61 /// Finalizes the merge section and clears hash table.
60 /// Sorts all owned subsections.62 /// Sorts all owned subsections.
61 pub fn finalize(msec: *MergeSection, elf_file: *Elf) !void {63 pub fn finalize(msec: *MergeSection, allocator: Allocator) !void {
62 const gpa = elf_file.base.comp.gpa;64 try msec.finalized_subsections.ensureTotalCapacityPrecise(allocator, msec.subsections.items.len);
63 try msec.subsections.ensureTotalCapacityPrecise(gpa, msec.table.count());
6465
65 var it = msec.table.iterator();66 var it = msec.table.iterator();
66 while (it.next()) |entry| {67 while (it.next()) |entry| {
67 const msub = elf_file.mergeSubsection(entry.value_ptr.*);68 const msub = msec.mergeSubsection(entry.value_ptr.*);
68 if (!msub.alive) continue;69 if (!msub.alive) continue;
69 msec.subsections.appendAssumeCapacity(entry.value_ptr.*);70 msec.finalized_subsections.appendAssumeCapacity(entry.value_ptr.*);
70 }71 }
71 msec.table.clearAndFree(gpa);72 msec.table.clearAndFree(allocator);
7273
73 const sortFn = struct {74 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 {
75 const lhs_msub = ctx.mergeSubsection(lhs);76 const lhs_msub = ctx.mergeSubsection(lhs);
76 const rhs_msub = ctx.mergeSubsection(rhs);77 const rhs_msub = ctx.mergeSubsection(rhs);
77 if (lhs_msub.alignment.compareStrict(.eq, rhs_msub.alignment)) {78 if (lhs_msub.alignment.compareStrict(.eq, rhs_msub.alignment)) {
78 if (lhs_msub.size == rhs_msub.size) {79 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;
80 }83 }
81 return lhs_msub.size < rhs_msub.size;84 return lhs_msub.size < rhs_msub.size;
82 }85 }
...@@ -84,7 +87,19 @@ pub const MergeSection = struct {...@@ -84,7 +87,19 @@ pub const MergeSection = struct {
84 }87 }
85 }.sortFn;88 }.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];
88 }103 }
89104
90 pub const IndexContext = struct {105 pub const IndexContext = struct {
...@@ -154,8 +169,8 @@ pub const MergeSection = struct {...@@ -154,8 +169,8 @@ pub const MergeSection = struct {
154 msec.type,169 msec.type,
155 msec.flags,170 msec.flags,
156 });171 });
157 for (msec.subsections.items) |index| {172 for (msec.subsections.items) |msub| {
158 try writer.print(" {}\n", .{elf_file.mergeSubsection(index).fmt(elf_file)});173 try writer.print(" {}\n", .{msub.fmt(elf_file)});
159 }174 }
160 }175 }
161176
...@@ -250,18 +265,26 @@ pub const InputMergeSection = struct {...@@ -250,18 +265,26 @@ pub const InputMergeSection = struct {
250 // TODO: imsec.strings.clearAndFree(allocator);265 // TODO: imsec.strings.clearAndFree(allocator);
251 }266 }
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 {
254 // TODO: binary search274 // TODO: binary search
255 for (imsec.offsets.items, 0..) |off, index| {275 for (imsec.offsets.items, 0..) |off, index| {
256 if (offset < off) return .{276 if (offset < off) return .{
257 imsec.subsections.items[index - 1],277 .msub_index = imsec.subsections.items[index - 1],
258 offset - imsec.offsets.items[index - 1],278 .offset = offset - imsec.offsets.items[index - 1],
259 };279 };
260 }280 }
261 const last = imsec.offsets.items.len - 1;281 const last = imsec.offsets.items.len - 1;
262 const last_off = imsec.offsets.items[last];282 const last_off = imsec.offsets.items[last];
263 const last_len = imsec.strings.items[last].len;283 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 };
265 return null;288 return null;
266 }289 }
267290
src/link/Elf/relocatable.zig+27-28
...@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
190 // Now, we are ready to resolve the symbols across all input files.190 // Now, we are ready to resolve the symbols across all input files.
191 // We will first resolve the files in the ZigObject, next in the parsed191 // We will first resolve the files in the ZigObject, next in the parsed
192 // input Object files.192 // input Object files.
193 elf_file.resolveSymbols();193 try elf_file.resolveSymbols();
194 elf_file.markEhFrameAtomsDead();194 elf_file.markEhFrameAtomsDead();
195 try elf_file.resolveMergeSections();195 try elf_file.resolveMergeSections();
196 try elf_file.addCommentString();196 try elf_file.addCommentString();
...@@ -299,13 +299,16 @@ fn initSections(elf_file: *Elf) !void {...@@ -299,13 +299,16 @@ fn initSections(elf_file: *Elf) !void {
299 } else false;299 } else false;
300 if (needs_eh_frame) {300 if (needs_eh_frame) {
301 elf_file.eh_frame_section_index = try elf_file.addSection(.{301 elf_file.eh_frame_section_index = try elf_file.addSection(.{
302 .name = ".eh_frame",302 .name = try elf_file.insertShString(".eh_frame"),
303 .type = elf.SHT_PROGBITS,303 .type = elf.SHT_PROGBITS,
304 .flags = elf.SHF_ALLOC,304 .flags = elf.SHF_ALLOC,
305 .addralign = ptr_size,305 .addralign = ptr_size,
306 .offset = std.math.maxInt(u64),306 .offset = std.math.maxInt(u64),
307 });307 });
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 );
309 }312 }
310313
311 try initComdatGroups(elf_file);314 try initComdatGroups(elf_file);
...@@ -318,22 +321,18 @@ fn initComdatGroups(elf_file: *Elf) !void {...@@ -318,22 +321,18 @@ fn initComdatGroups(elf_file: *Elf) !void {
318321
319 for (elf_file.objects.items) |index| {322 for (elf_file.objects.items) |index| {
320 const object = elf_file.file(index).?.object;323 const object = elf_file.file(index).?.object;
321324 for (object.comdat_groups.items, 0..) |cg, cg_index| {
322 for (object.comdat_groups.items) |cg_index| {325 if (!cg.alive) continue;
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
327 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);326 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);
328 cg_sec.* = .{327 cg_sec.* = .{
329 .shndx = try elf_file.addSection(.{328 .shndx = try elf_file.addSection(.{
330 .name = ".group",329 .name = try elf_file.insertShString(".group"),
331 .type = elf.SHT_GROUP,330 .type = elf.SHT_GROUP,
332 .entsize = @sizeOf(u32),331 .entsize = @sizeOf(u32),
333 .addralign = @alignOf(u32),332 .addralign = @alignOf(u32),
334 .offset = std.math.maxInt(u64),333 .offset = std.math.maxInt(u64),
335 }),334 }),
336 .cg_index = cg_index,335 .cg_ref = .{ .index = @intCast(cg_index), .file = index },
337 };336 };
338 }337 }
339 }338 }
...@@ -342,9 +341,9 @@ fn initComdatGroups(elf_file: *Elf) !void {...@@ -342,9 +341,9 @@ fn initComdatGroups(elf_file: *Elf) !void {
342fn updateSectionSizes(elf_file: *Elf) !void {341fn updateSectionSizes(elf_file: *Elf) !void {
343 for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| {342 for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| {
344 const shdr = &elf_file.shdrs.items[shndx];343 const shdr = &elf_file.shdrs.items[shndx];
345 for (atom_list.items) |atom_index| {344 for (atom_list.items) |ref| {
346 const atom_ptr = elf_file.atom(atom_index) orelse continue;345 const atom_ptr = elf_file.atom(ref) orelse continue;
347 if (!atom_ptr.flags.alive) continue;346 if (!atom_ptr.alive) continue;
348 const offset = atom_ptr.alignment.forward(shdr.sh_size);347 const offset = atom_ptr.alignment.forward(shdr.sh_size);
349 const padding = offset - shdr.sh_size;348 const padding = offset - shdr.sh_size;
350 atom_ptr.value = @intCast(offset);349 atom_ptr.value = @intCast(offset);
...@@ -355,9 +354,9 @@ fn updateSectionSizes(elf_file: *Elf) !void {...@@ -355,9 +354,9 @@ fn updateSectionSizes(elf_file: *Elf) !void {
355354
356 for (elf_file.output_rela_sections.values()) |sec| {355 for (elf_file.output_rela_sections.values()) |sec| {
357 const shdr = &elf_file.shdrs.items[sec.shndx];356 const shdr = &elf_file.shdrs.items[sec.shndx];
358 for (sec.atom_list.items) |atom_index| {357 for (sec.atom_list.items) |ref| {
359 const atom_ptr = elf_file.atom(atom_index) orelse continue;358 const atom_ptr = elf_file.atom(ref) orelse continue;
360 if (!atom_ptr.flags.alive) continue;359 if (!atom_ptr.alive) continue;
361 const relocs = atom_ptr.relocs(elf_file);360 const relocs = atom_ptr.relocs(elf_file);
362 shdr.sh_size += shdr.sh_entsize * relocs.len;361 shdr.sh_size += shdr.sh_entsize * relocs.len;
363 }362 }
...@@ -386,7 +385,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {...@@ -386,7 +385,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
386385
387 const sym = elf_file.symbol(cg.symbol(elf_file));386 const sym = elf_file.symbol(cg.symbol(elf_file));
388 shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse387 shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse
389 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);388 elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
390 }389 }
391}390}
392391
...@@ -449,16 +448,16 @@ fn writeAtoms(elf_file: *Elf) !void {...@@ -449,16 +448,16 @@ fn writeAtoms(elf_file: *Elf) !void {
449 0;448 0;
450 @memset(buffer, padding_byte);449 @memset(buffer, padding_byte);
451450
452 for (atom_list.items) |atom_index| {451 for (atom_list.items) |ref| {
453 const atom_ptr = elf_file.atom(atom_index).?;452 const atom_ptr = elf_file.atom(ref).?;
454 assert(atom_ptr.flags.alive);453 assert(atom_ptr.alive);
455454
456 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse455 const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
457 return error.Overflow;456 return error.Overflow;
458 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;457 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}", .{459 log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
461 atom_index,460 ref,
462 sh_offset + offset,461 sh_offset + offset,
463 sh_offset + offset + size,462 sh_offset + offset + size,
464 });463 });
...@@ -466,8 +465,8 @@ fn writeAtoms(elf_file: *Elf) !void {...@@ -466,8 +465,8 @@ fn writeAtoms(elf_file: *Elf) !void {
466 // TODO decompress directly into provided buffer465 // TODO decompress directly into provided buffer
467 const out_code = buffer[offset..][0..size];466 const out_code = buffer[offset..][0..size];
468 const in_code = switch (atom_ptr.file(elf_file).?) {467 const in_code = switch (atom_ptr.file(elf_file).?) {
469 .object => |x| try x.codeDecompressAlloc(elf_file, atom_index),468 .object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
470 .zig_object => |x| try x.codeAlloc(elf_file, atom_index),469 .zig_object => |x| try x.codeAlloc(elf_file, ref.index),
471 else => unreachable,470 else => unreachable,
472 };471 };
473 defer gpa.free(in_code);472 defer gpa.free(in_code);
...@@ -491,9 +490,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void {...@@ -491,9 +490,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
491 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);490 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
492 defer relocs.deinit();491 defer relocs.deinit();
493492
494 for (sec.atom_list.items) |atom_index| {493 for (sec.atom_list.items) |ref| {
495 const atom_ptr = elf_file.atom(atom_index) orelse continue;494 const atom_ptr = elf_file.atom(ref) orelse continue;
496 if (!atom_ptr.flags.alive) continue;495 if (!atom_ptr.alive) continue;
497 try atom_ptr.writeRelocs(elf_file, &relocs);496 try atom_ptr.writeRelocs(elf_file, &relocs);
498 }497 }
499 assert(relocs.items.len == num_relocs);498 assert(relocs.items.len == num_relocs);
src/link/Elf/synthetic_sections.zig+16-17
...@@ -1075,7 +1075,7 @@ pub const GotPltSection = struct {...@@ -1075,7 +1075,7 @@ pub const GotPltSection = struct {
1075 _ = got_plt;1075 _ = got_plt;
1076 {1076 {
1077 // [0]: _DYNAMIC1077 // [0]: _DYNAMIC
1078 const symbol = elf_file.symbol(elf_file.dynamic_index.?);1078 const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?);
1079 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);1079 try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
1080 }1080 }
1081 // [1]: 0x01081 // [1]: 0x0
...@@ -1670,45 +1670,44 @@ pub const VerneedSection = struct {...@@ -1670,45 +1670,44 @@ pub const VerneedSection = struct {
16701670
1671pub const ComdatGroupSection = struct {1671pub const ComdatGroupSection = struct {
1672 shndx: u32,1672 shndx: u32,
1673 cg_index: u32,1673 cg_ref: Elf.Ref,
16741674
1675 fn file(cgs: ComdatGroupSection, elf_file: *Elf) ?File {1675 fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {
1676 const cg = elf_file.comdatGroup(cgs.cg_index);1676 const cg_file = elf_file.file(cgs.cg_ref.file).?;
1677 const cg_owner = elf_file.comdatGroupOwner(cg.owner);1677 return cg_file.object.comdatGroup(cgs.cg_ref.index);
1678 return elf_file.file(cg_owner.file);
1679 }1678 }
16801679
1681 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {1680 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
1682 const cg = elf_file.comdatGroup(cgs.cg_index);1681 const cg = cgs.comdatGroup(elf_file);
1683 const object = cgs.file(elf_file).?.object;1682 const object = cg.file(elf_file).object;
1684 const shdr = object.shdrs.items[cg.shndx];1683 const shdr = object.shdrs.items[cg.shndx];
1685 return object.symbols.items[shdr.sh_info];1684 return object.symbols.items[shdr.sh_info];
1686 }1685 }
16871686
1688 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {1687 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);
1690 const members = cg.comdatGroupMembers(elf_file);1689 const members = cg.comdatGroupMembers(elf_file);
1691 return (members.len + 1) * @sizeOf(u32);1690 return (members.len + 1) * @sizeOf(u32);
1692 }1691 }
16931692
1694 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {1693 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
1695 const cg = elf_file.comdatGroup(cgs.cg_index);1694 const cg = cgs.comdatGroup(elf_file);
1696 const object = cgs.file(elf_file).?.object;1695 const object = cg.file(elf_file).object;
1697 const members = cg.comdatGroupMembers(elf_file);1696 const members = cg.comdatGroupMembers(elf_file);
1698 try writer.writeInt(u32, elf.GRP_COMDAT, .little);1697 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
1699 for (members) |shndx| {1698 for (members) |shndx| {
1700 const shdr = object.shdrs.items[shndx];1699 const shdr = object.shdrs.items[shndx];
1701 switch (shdr.sh_type) {1700 switch (shdr.sh_type) {
1702 elf.SHT_RELA => {1701 elf.SHT_RELA => {
1703 const atom_index = object.atoms.items[shdr.sh_info];1702 const atom_index = object.atoms_indexes.items[shdr.sh_info];
1704 const atom = elf_file.atom(atom_index).?;1703 const atom = object.atom(atom_index).?;
1705 const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;1704 const rela = elf_file.output_rela_sections.get(atom.output_section_index).?;
1706 try writer.writeInt(u32, rela.shndx, .little);1705 try writer.writeInt(u32, rela.shndx, .little);
1707 },1706 },
1708 else => {1707 else => {
1709 const atom_index = object.atoms.items[shndx];1708 const atom_index = object.atoms_indexes.items[shndx];
1710 const atom = elf_file.atom(atom_index).?;1709 const atom = object.atom(atom_index).?;
1711 try writer.writeInt(u32, atom.outputShndx().?, .little);1710 try writer.writeInt(u32, atom.output_section_index, .little);
1712 },1711 },
1713 }1712 }
1714 }1713 }
src/link/Elf/thunks.zig+9-11
...@@ -6,22 +6,21 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -6,22 +6,21 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
6 const atoms = elf_file.output_sections.get(shndx).?.items;6 const atoms = elf_file.output_sections.get(shndx).?.items;
7 assert(atoms.len > 0);7 assert(atoms.len > 0);
88
9 for (atoms) |atom_index| {9 for (atoms) |ref| {
10 elf_file.atom(atom_index).?.value = -1;10 elf_file.atom(ref).?.value = -1;
11 }11 }
1212
13 var i: usize = 0;13 var i: usize = 0;
14 while (i < atoms.len) {14 while (i < atoms.len) {
15 const start = i;15 const start = i;
16 const start_atom = elf_file.atom(atoms[start]).?;16 const start_atom = elf_file.atom(atoms[start]).?;
17 assert(start_atom.flags.alive);17 assert(start_atom.alive);
18 start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment);18 start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment);
19 i += 1;19 i += 1;
2020
21 while (i < atoms.len) : (i += 1) {21 while (i < atoms.len) : (i += 1) {
22 const atom_index = atoms[i];22 const atom = elf_file.atom(atoms[i]).?;
23 const atom = elf_file.atom(atom_index).?;23 assert(atom.alive);
24 assert(atom.flags.alive);
25 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)24 if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
26 break;25 break;
27 atom.value = try advance(shdr, atom.size, atom.alignment);26 atom.value = try advance(shdr, atom.size, atom.alignment);
...@@ -33,10 +32,10 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -33,10 +32,10 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
33 thunk.output_section_index = shndx;32 thunk.output_section_index = shndx;
3433
35 // Scan relocs in the group and create trampolines for any unreachable callsite34 // Scan relocs in the group and create trampolines for any unreachable callsite
36 for (atoms[start..i]) |atom_index| {35 for (atoms[start..i]) |ref| {
37 const atom = elf_file.atom(atom_index).?;36 const atom = elf_file.atom(ref).?;
38 const file = atom.file(elf_file).?;37 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) });
40 for (atom.relocs(elf_file)) |rel| {39 for (atom.relocs(elf_file)) |rel| {
41 const is_reachable = switch (cpu_arch) {40 const is_reachable = switch (cpu_arch) {
42 .aarch64 => aarch64.isReachable(atom, rel, elf_file),41 .aarch64 => aarch64.isReachable(atom, rel, elf_file),
...@@ -51,8 +50,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {...@@ -51,8 +50,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
51 };50 };
52 try thunk.symbols.put(gpa, target, {});51 try thunk.symbols.put(gpa, target, {});
53 }52 }
54 try atom.addExtra(.{ .thunk = thunk_index }, elf_file);53 atom.addExtra(.{ .thunk = thunk_index }, elf_file);
55 atom.flags.thunk = true;
56 }54 }
5755
58 thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));56 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 {...@@ -45,8 +45,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
4545
46pub fn init(self: *InternalObject, allocator: Allocator) !void {46pub fn init(self: *InternalObject, allocator: Allocator) !void {
47 // Atom at index 0 is reserved as null atom.47 // Atom at index 0 is reserved as null atom.
48 try self.atoms.append(allocator, .{});48 try self.atoms.append(allocator, .{ .extra = try self.addAtomExtra(allocator, .{}) });
49 try self.atoms_extra.append(allocator, 0);
50 // Null byte in strtab49 // Null byte in strtab
51 try self.strtab.append(allocator, 0);50 try self.strtab.append(allocator, 0);
52}51}
src/link/MachO/ZigObject.zig+1-1
...@@ -1634,7 +1634,7 @@ fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {...@@ -1634,7 +1634,7 @@ fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {
16341634
1635fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {1635fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
1636 try self.atoms.ensureUnusedCapacity(allocator, 1);1636 try self.atoms.ensureUnusedCapacity(allocator, 1);
1637 try self.atoms_extra.ensureUnusedCapacity(allocator, 1);1637 try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
1638 return self.addAtomAssumeCapacity();1638 return self.addAtomAssumeCapacity();
1639}1639}
16401640
test/link/elf.zig+104
...@@ -59,6 +59,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {...@@ -59,6 +59,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
59 // Exercise linker with LLVM backend59 // Exercise linker with LLVM backend
60 // musl tests60 // musl tests
61 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));61 elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));
62 elf_step.dependOn(testComdatElimination(b, .{ .target = musl_target }));
62 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));63 elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));
63 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));64 elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));
64 elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));65 elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));
...@@ -368,6 +369,109 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {...@@ -368,6 +369,109 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
368 return test_step;369 return test_step;
369}370}
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
371fn testCommentString(b: *Build, opts: Options) *Step {475fn testCommentString(b: *Build, opts: Options) *Step {
372 const test_step = addTestStep(b, "comment-string", opts);476 const test_step = addTestStep(b, "comment-string", opts);
373477