authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-10 07:57:52+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-11-10 07:57:52+01:00
logc550eb3e8ab7ae77e5533313c219b2015e633081
tree88da11231c79c95ce8523792db99fd8db1854c50
parent3f10b3ee1eaca13d8edbdebeae8cd50d40c095c0
parent73fd4ed54b639bfd4d8a142102b54762d290763e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17933 from ziglang/elf-r-mode

elf: the dreaded `-r` mode

12 files changed, 1458 insertions(+), 672 deletions(-)

lib/std/elf.zig+2
...@@ -1664,6 +1664,8 @@ pub const EM = enum(u16) {...@@ -1664,6 +1664,8 @@ pub const EM = enum(u16) {
1664 }1664 }
1665};1665};
16661666
1667pub const GRP_COMDAT = 1;
1668
1667/// Section data should be writable during execution.1669/// Section data should be writable during execution.
1668pub const SHF_WRITE = 0x1;1670pub const SHF_WRITE = 0x1;
16691671
src/link/Elf.zig+966-501
...@@ -18,12 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{},...@@ -18,12 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
18/// Same order as in the file.18/// Same order as in the file.
19shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},19shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
20/// Given index to a section, pulls index of containing phdr if any.20/// Given index to a section, pulls index of containing phdr if any.
21phdr_to_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},21phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
22/// File offset into the shdr table.22/// File offset into the shdr table.
23shdr_table_offset: ?u64 = null,23shdr_table_offset: ?u64 = null,
24/// Table of lists of atoms per output section.24/// Table of lists of atoms per output section.
25/// This table is not used to track incrementally generated atoms.25/// This table is not used to track incrementally generated atoms.
26output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},26output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Atom.Index)) = .{},
27output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{},
2728
28/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.29/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
29/// Same order as in the file.30/// Same order as in the file.
...@@ -101,15 +102,15 @@ copy_rel: CopyRelSection = .{},...@@ -101,15 +102,15 @@ copy_rel: CopyRelSection = .{},
101rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},102rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
102/// .got.zig section103/// .got.zig section
103zig_got: ZigGotSection = .{},104zig_got: ZigGotSection = .{},
105/// SHT_GROUP sections
106/// Applies only to a relocatable.
107comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
104108
105/// Tracked section headers with incremental updates to Zig object.109/// Tracked section headers with incremental updates to Zig object.
106/// .rela.* sections are only used when emitting a relocatable object file.110/// .rela.* sections are only used when emitting a relocatable object file.
107zig_text_section_index: ?u16 = null,111zig_text_section_index: ?u16 = null,
108zig_text_rela_section_index: ?u16 = null,
109zig_data_rel_ro_section_index: ?u16 = null,112zig_data_rel_ro_section_index: ?u16 = null,
110zig_data_rel_ro_rela_section_index: ?u16 = null,
111zig_data_section_index: ?u16 = null,113zig_data_section_index: ?u16 = null,
112zig_data_rela_section_index: ?u16 = null,
113zig_bss_section_index: ?u16 = null,114zig_bss_section_index: ?u16 = null,
114zig_got_section_index: ?u16 = null,115zig_got_section_index: ?u16 = null,
115116
...@@ -124,6 +125,7 @@ dynamic_section_index: ?u16 = null,...@@ -124,6 +125,7 @@ dynamic_section_index: ?u16 = null,
124dynstrtab_section_index: ?u16 = null,125dynstrtab_section_index: ?u16 = null,
125dynsymtab_section_index: ?u16 = null,126dynsymtab_section_index: ?u16 = null,
126eh_frame_section_index: ?u16 = null,127eh_frame_section_index: ?u16 = null,
128eh_frame_rela_section_index: ?u16 = null,
127eh_frame_hdr_section_index: ?u16 = null,129eh_frame_hdr_section_index: ?u16 = null,
128hash_section_index: ?u16 = null,130hash_section_index: ?u16 = null,
129gnu_hash_section_index: ?u16 = null,131gnu_hash_section_index: ?u16 = null,
...@@ -216,10 +218,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -216,10 +218,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
216 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),218 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
217 });219 });
218 }220 }
219 if (is_obj) {
220 // TODO until we implement -r option, we don't want to open a file at this stage.
221 return self;
222 }
223 }221 }
224 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);222 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
225223
...@@ -361,6 +359,10 @@ pub fn deinit(self: *Elf) void {...@@ -361,6 +359,10 @@ pub fn deinit(self: *Elf) void {
361 list.deinit(gpa);359 list.deinit(gpa);
362 }360 }
363 self.output_sections.deinit(gpa);361 self.output_sections.deinit(gpa);
362 for (self.output_rela_sections.values()) |*sec| {
363 sec.atom_list.deinit(gpa);
364 }
365 self.output_rela_sections.deinit(gpa);
364 self.shstrtab.deinit(gpa);366 self.shstrtab.deinit(gpa);
365 self.symtab.deinit(gpa);367 self.symtab.deinit(gpa);
366 self.strtab.deinit(gpa);368 self.strtab.deinit(gpa);
...@@ -395,6 +397,7 @@ pub fn deinit(self: *Elf) void {...@@ -395,6 +397,7 @@ pub fn deinit(self: *Elf) void {
395 self.rela_dyn.deinit(gpa);397 self.rela_dyn.deinit(gpa);
396 self.rela_plt.deinit(gpa);398 self.rela_plt.deinit(gpa);
397 self.zig_got.deinit(gpa);399 self.zig_got.deinit(gpa);
400 self.comdat_group_sections.deinit(gpa);
398}401}
399402
400pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {403pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
...@@ -601,11 +604,10 @@ pub fn initMetadata(self: *Elf) !void {...@@ -601,11 +604,10 @@ pub fn initMetadata(self: *Elf) !void {
601 const shdr = &self.shdrs.items[self.zig_text_section_index.?];604 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
602 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);605 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
603 if (self.isRelocatable()) {606 if (self.isRelocatable()) {
604 try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);607 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
605 self.zig_text_rela_section_index = try self.addRelaShdr(608 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
606 ".rela.text.zig",609 .shndx = rela_shndx,
607 self.zig_text_section_index.?,610 });
608 );
609 } else {611 } else {
610 try self.phdr_to_shdr_table.putNoClobber(612 try self.phdr_to_shdr_table.putNoClobber(
611 gpa,613 gpa,
...@@ -613,6 +615,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -613,6 +615,7 @@ pub fn initMetadata(self: *Elf) !void {
613 self.phdr_zig_load_re_index.?,615 self.phdr_zig_load_re_index.?,
614 );616 );
615 }617 }
618 try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{});
616 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});619 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
617 }620 }
618621
...@@ -642,17 +645,19 @@ pub fn initMetadata(self: *Elf) !void {...@@ -642,17 +645,19 @@ pub fn initMetadata(self: *Elf) !void {
642 .name = ".data.rel.ro.zig",645 .name = ".data.rel.ro.zig",
643 .type = elf.SHT_PROGBITS,646 .type = elf.SHT_PROGBITS,
644 .addralign = 1,647 .addralign = 1,
645 .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro648 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
646 .offset = std.math.maxInt(u64),649 .offset = std.math.maxInt(u64),
647 });650 });
648 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];651 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
649 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);652 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
650 if (self.isRelocatable()) {653 if (self.isRelocatable()) {
651 try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);654 const rela_shndx = try self.addRelaShdr(
652 self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
653 ".rela.data.rel.ro.zig",655 ".rela.data.rel.ro.zig",
654 self.zig_data_rel_ro_section_index.?,656 self.zig_data_rel_ro_section_index.?,
655 );657 );
658 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{
659 .shndx = rela_shndx,
660 });
656 } else {661 } else {
657 try self.phdr_to_shdr_table.putNoClobber(662 try self.phdr_to_shdr_table.putNoClobber(
658 gpa,663 gpa,
...@@ -660,6 +665,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -660,6 +665,7 @@ pub fn initMetadata(self: *Elf) !void {
660 self.phdr_zig_load_ro_index.?,665 self.phdr_zig_load_ro_index.?,
661 );666 );
662 }667 }
668 try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
663 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});669 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
664 }670 }
665671
...@@ -674,11 +680,13 @@ pub fn initMetadata(self: *Elf) !void {...@@ -674,11 +680,13 @@ pub fn initMetadata(self: *Elf) !void {
674 const shdr = &self.shdrs.items[self.zig_data_section_index.?];680 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
675 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);681 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
676 if (self.isRelocatable()) {682 if (self.isRelocatable()) {
677 try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);683 const rela_shndx = try self.addRelaShdr(
678 self.zig_data_rela_section_index = try self.addRelaShdr(
679 ".rela.data.zig",684 ".rela.data.zig",
680 self.zig_data_section_index.?,685 self.zig_data_section_index.?,
681 );686 );
687 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{
688 .shndx = rela_shndx,
689 });
682 } else {690 } else {
683 try self.phdr_to_shdr_table.putNoClobber(691 try self.phdr_to_shdr_table.putNoClobber(
684 gpa,692 gpa,
...@@ -686,6 +694,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -686,6 +694,7 @@ pub fn initMetadata(self: *Elf) !void {
686 self.phdr_zig_load_rw_index.?,694 self.phdr_zig_load_rw_index.?,
687 );695 );
688 }696 }
697 try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{});
689 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});698 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
690 }699 }
691700
...@@ -704,9 +713,9 @@ pub fn initMetadata(self: *Elf) !void {...@@ -704,9 +713,9 @@ pub fn initMetadata(self: *Elf) !void {
704 shdr.sh_size = phdr.p_memsz;713 shdr.sh_size = phdr.p_memsz;
705 try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);714 try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
706 } else {715 } else {
707 try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
708 shdr.sh_size = 1024;716 shdr.sh_size = 1024;
709 }717 }
718 try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
710 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});719 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
711 }720 }
712721
...@@ -728,6 +737,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -728,6 +737,7 @@ pub fn initMetadata(self: *Elf) !void {
728 shdr.sh_offset = off;737 shdr.sh_offset = off;
729 shdr.sh_size = size;738 shdr.sh_size = size;
730 zig_object.debug_strtab_dirty = true;739 zig_object.debug_strtab_dirty = true;
740 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
731 }741 }
732742
733 if (self.debug_info_section_index == null) {743 if (self.debug_info_section_index == null) {
...@@ -743,6 +753,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -743,6 +753,7 @@ pub fn initMetadata(self: *Elf) !void {
743 shdr.sh_offset = off;753 shdr.sh_offset = off;
744 shdr.sh_size = size;754 shdr.sh_size = size;
745 zig_object.debug_info_header_dirty = true;755 zig_object.debug_info_header_dirty = true;
756 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
746 }757 }
747758
748 if (self.debug_abbrev_section_index == null) {759 if (self.debug_abbrev_section_index == null) {
...@@ -758,6 +769,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -758,6 +769,7 @@ pub fn initMetadata(self: *Elf) !void {
758 shdr.sh_offset = off;769 shdr.sh_offset = off;
759 shdr.sh_size = size;770 shdr.sh_size = size;
760 zig_object.debug_abbrev_section_dirty = true;771 zig_object.debug_abbrev_section_dirty = true;
772 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
761 }773 }
762774
763 if (self.debug_aranges_section_index == null) {775 if (self.debug_aranges_section_index == null) {
...@@ -773,6 +785,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -773,6 +785,7 @@ pub fn initMetadata(self: *Elf) !void {
773 shdr.sh_offset = off;785 shdr.sh_offset = off;
774 shdr.sh_size = size;786 shdr.sh_size = size;
775 zig_object.debug_aranges_section_dirty = true;787 zig_object.debug_aranges_section_dirty = true;
788 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
776 }789 }
777790
778 if (self.debug_line_section_index == null) {791 if (self.debug_line_section_index == null) {
...@@ -788,8 +801,17 @@ pub fn initMetadata(self: *Elf) !void {...@@ -788,8 +801,17 @@ pub fn initMetadata(self: *Elf) !void {
788 shdr.sh_offset = off;801 shdr.sh_offset = off;
789 shdr.sh_size = size;802 shdr.sh_size = size;
790 zig_object.debug_line_header_dirty = true;803 zig_object.debug_line_header_dirty = true;
804 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
791 }805 }
792 }806 }
807
808 // We need to find current max assumed file offset, and actually write to file to make it a reality.
809 var end_pos: u64 = 0;
810 for (self.shdrs.items) |shdr| {
811 if (shdr.sh_offset == std.math.maxInt(u64)) continue;
812 end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
813 }
814 try self.base.file.?.pwriteAll(&[1]u8{0}, end_pos);
793}815}
794816
795pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {817pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
...@@ -942,30 +964,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -942,30 +964,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
942 } else null;964 } else null;
943 const gc_sections = self.base.options.gc_sections orelse false;965 const gc_sections = self.base.options.gc_sections orelse false;
944966
945 if (self.isObject() and self.zig_object_index == null) {967 // --verbose-link
946 // TODO this will become -r route I guess. For now, just copy the object file.968 if (self.base.options.verbose_link) try self.dumpArgv(comp);
947 const the_object_path = blk: {
948 if (self.base.options.objects.len != 0) {
949 break :blk self.base.options.objects[0].path;
950 }
951
952 if (comp.c_object_table.count() != 0)
953 break :blk comp.c_object_table.keys()[0].status.success.object_path;
954
955 if (module_obj_path) |p|
956 break :blk p;
957
958 // TODO I think this is unreachable. Audit this situation when solving the above TODO
959 // regarding eliding redundant object -> object transformations.
960 return error.NoObjectsToLink;
961 };
962 // This can happen when using --enable-cache and using the stage1 backend. In this case
963 // we can skip the file copy.
964 if (!mem.eql(u8, the_object_path, full_out_path)) {
965 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
966 }
967 return;
968 }
969969
970 var csu = try CsuObjects.init(arena, self.base.options, comp);970 var csu = try CsuObjects.init(arena, self.base.options, comp);
971 const compiler_rt_path: ?[]const u8 = blk: {971 const compiler_rt_path: ?[]const u8 = blk: {
...@@ -974,247 +974,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -974,247 +974,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
974 break :blk null;974 break :blk null;
975 };975 };
976976
977 // --verbose-link
978 if (self.base.options.verbose_link) {
979 var argv = std.ArrayList([]const u8).init(arena);
980
981 try argv.append("zig");
982 try argv.append("ld");
983
984 try argv.append("-o");
985 try argv.append(full_out_path);
986
987 if (self.base.options.entry) |entry| {
988 try argv.append("--entry");
989 try argv.append(entry);
990 }
991
992 if (self.base.options.dynamic_linker) |path| {
993 try argv.append("-dynamic-linker");
994 try argv.append(path);
995 }
996
997 if (self.base.options.soname) |name| {
998 try argv.append("-soname");
999 try argv.append(name);
1000 }
1001
1002 for (self.base.options.rpath_list) |rpath| {
1003 try argv.append("-rpath");
1004 try argv.append(rpath);
1005 }
1006
1007 if (self.base.options.each_lib_rpath) {
1008 for (self.base.options.lib_dirs) |lib_dir_path| {
1009 try argv.append("-rpath");
1010 try argv.append(lib_dir_path);
1011 }
1012 for (self.base.options.objects) |obj| {
1013 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
1014 const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
1015 if (obj.loption) continue;
1016
1017 try argv.append("-rpath");
1018 try argv.append(lib_dir_path);
1019 }
1020 }
1021 }
1022
1023 if (self.base.options.stack_size_override) |ss| {
1024 try argv.append("-z");
1025 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
1026 }
1027
1028 if (self.base.options.image_base_override) |image_base| {
1029 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1030 }
1031
1032 if (gc_sections) {
1033 try argv.append("--gc-sections");
1034 }
1035
1036 if (self.base.options.print_gc_sections) {
1037 try argv.append("--print-gc-sections");
1038 }
1039
1040 if (self.base.options.eh_frame_hdr) {
1041 try argv.append("--eh-frame-hdr");
1042 }
1043
1044 if (self.base.options.rdynamic) {
1045 try argv.append("--export-dynamic");
1046 }
1047
1048 if (self.base.options.strip) {
1049 try argv.append("-s");
1050 }
1051
1052 if (self.base.options.z_notext) {
1053 try argv.append("-z");
1054 try argv.append("notext");
1055 }
1056
1057 if (self.base.options.z_nocopyreloc) {
1058 try argv.append("-z");
1059 try argv.append("nocopyreloc");
1060 }
1061
1062 if (self.base.options.z_now) {
1063 try argv.append("-z");
1064 try argv.append("now");
1065 }
1066
1067 if (self.isStatic()) {
1068 try argv.append("-static");
1069 } else if (self.isDynLib()) {
1070 try argv.append("-shared");
1071 }
1072
1073 if (self.base.options.pie and self.isExe()) {
1074 try argv.append("-pie");
1075 }
1076
1077 // csu prelude
1078 if (csu.crt0) |v| try argv.append(v);
1079 if (csu.crti) |v| try argv.append(v);
1080 if (csu.crtbegin) |v| try argv.append(v);
1081
1082 for (self.base.options.lib_dirs) |lib_dir| {
1083 try argv.append("-L");
1084 try argv.append(lib_dir);
1085 }
1086
1087 if (self.base.options.link_libc) {
1088 if (self.base.options.libc_installation) |libc_installation| {
1089 try argv.append("-L");
1090 try argv.append(libc_installation.crt_dir.?);
1091 }
1092 }
1093
1094 var whole_archive = false;
1095 for (self.base.options.objects) |obj| {
1096 if (obj.must_link and !whole_archive) {
1097 try argv.append("-whole-archive");
1098 whole_archive = true;
1099 } else if (!obj.must_link and whole_archive) {
1100 try argv.append("-no-whole-archive");
1101 whole_archive = false;
1102 }
1103
1104 if (obj.loption) {
1105 assert(obj.path[0] == ':');
1106 try argv.append("-l");
1107 }
1108 try argv.append(obj.path);
1109 }
1110 if (whole_archive) {
1111 try argv.append("-no-whole-archive");
1112 whole_archive = false;
1113 }
1114
1115 for (comp.c_object_table.keys()) |key| {
1116 try argv.append(key.status.success.object_path);
1117 }
1118
1119 if (module_obj_path) |p| {
1120 try argv.append(p);
1121 }
1122
1123 // TSAN
1124 if (self.base.options.tsan) {
1125 try argv.append(comp.tsan_static_lib.?.full_object_path);
1126 }
1127
1128 // libc
1129 if (!self.base.options.skip_linker_dependencies and
1130 !self.base.options.link_libc)
1131 {
1132 if (comp.libc_static_lib) |lib| {
1133 try argv.append(lib.full_object_path);
1134 }
1135 }
1136
1137 // stack-protector.
1138 // Related: https://github.com/ziglang/zig/issues/7265
1139 if (comp.libssp_static_lib) |ssp| {
1140 try argv.append(ssp.full_object_path);
1141 }
1142
1143 // Shared libraries.
1144 // Worst-case, we need an --as-needed argument for every lib, as well
1145 // as one before and one after.
1146 try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
1147 argv.appendAssumeCapacity("--as-needed");
1148 var as_needed = true;
1149
1150 for (self.base.options.system_libs.values()) |lib_info| {
1151 const lib_as_needed = !lib_info.needed;
1152 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1153 0b00, 0b11 => {},
1154 0b01 => {
1155 argv.appendAssumeCapacity("--no-as-needed");
1156 as_needed = false;
1157 },
1158 0b10 => {
1159 argv.appendAssumeCapacity("--as-needed");
1160 as_needed = true;
1161 },
1162 }
1163 argv.appendAssumeCapacity(lib_info.path.?);
1164 }
1165
1166 if (!as_needed) {
1167 argv.appendAssumeCapacity("--as-needed");
1168 as_needed = true;
1169 }
1170
1171 // libc++ dep
1172 if (self.base.options.link_libcpp) {
1173 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1174 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1175 }
1176
1177 // libunwind dep
1178 if (self.base.options.link_libunwind) {
1179 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1180 }
1181
1182 // libc dep
1183 if (self.base.options.link_libc) {
1184 if (self.base.options.libc_installation != null) {
1185 const needs_grouping = self.base.options.link_mode == .Static;
1186 if (needs_grouping) try argv.append("--start-group");
1187 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1188 if (needs_grouping) try argv.append("--end-group");
1189 } else if (target.isGnuLibC()) {
1190 for (glibc.libs) |lib| {
1191 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1192 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1193 });
1194 try argv.append(lib_path);
1195 }
1196 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1197 } else if (target.isMusl()) {
1198 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1199 .Static => "libc.a",
1200 .Dynamic => "libc.so",
1201 }));
1202 }
1203 }
1204
1205 // compiler-rt
1206 if (compiler_rt_path) |p| {
1207 try argv.append(p);
1208 }
1209
1210 // crt postlude
1211 if (csu.crtend) |v| try argv.append(v);
1212 if (csu.crtn) |v| try argv.append(v);
1213
1214 Compilation.dump_argv(argv.items);
1215 }
1216
1217 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);977 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
978 if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
979 if (self.isObject()) return self.flushObject(comp, module_obj_path);
1218980
1219 // Here we will parse input positional and library files (if referenced).981 // Here we will parse input positional and library files (if referenced).
1220 // This will roughly match in any linker backend we support.982 // This will roughly match in any linker backend we support.
...@@ -1240,6 +1002,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1240,6 +1002,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1240 // rpaths1002 // rpaths
1241 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);1003 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);
1242 defer rpath_table.deinit();1004 defer rpath_table.deinit();
1005
1243 for (self.base.options.rpath_list) |rpath| {1006 for (self.base.options.rpath_list) |rpath| {
1244 _ = try rpath_table.put(rpath, {});1007 _ = try rpath_table.put(rpath, {});
1245 }1008 }
...@@ -1388,8 +1151,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1388,8 +1151,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1388 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1151 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1389 }1152 }
13901153
1391 if (self.isStaticLib()) return self.flushStaticLib(comp);
1392
1393 // Init all objects1154 // Init all objects
1394 for (self.objects.items) |index| {1155 for (self.objects.items) |index| {
1395 try self.file(index).?.object.init(self);1156 try self.file(index).?.object.init(self);
...@@ -1418,7 +1179,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1418,7 +1179,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14181179
1419 // If we haven't already, create a linker-generated input file comprising of1180 // If we haven't already, create a linker-generated input file comprising of
1420 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.1181 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
1421 if (self.linker_defined_index == null and !self.isRelocatable()) {1182 if (self.linker_defined_index == null) {
1422 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1183 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1423 self.files.set(index, .{ .linker_defined = .{ .index = index } });1184 self.files.set(index, .{ .linker_defined = .{ .index = index } });
1424 self.linker_defined_index = index;1185 self.linker_defined_index = index;
...@@ -1432,8 +1193,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1432,8 +1193,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1432 self.resolveSymbols();1193 self.resolveSymbols();
1433 self.markEhFrameAtomsDead();1194 self.markEhFrameAtomsDead();
14341195
1435 if (self.isObject()) return self.flushObject(comp);
1436
1437 try self.convertCommonSymbols();1196 try self.convertCommonSymbols();
1438 self.markImportsExports();1197 self.markImportsExports();
14391198
...@@ -1527,10 +1286,30 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1527,10 +1286,30 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1527 }1286 }
1528}1287}
15291288
1530pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {1289pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1531 _ = comp;
1532 const gpa = self.base.allocator;1290 const gpa = self.base.allocator;
15331291
1292 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
1293 defer positionals.deinit();
1294
1295 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
1296 positionals.appendSliceAssumeCapacity(self.base.options.objects);
1297
1298 // This is a set of object files emitted by clang in a single `build-exe` invocation.
1299 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
1300 // in this set.
1301 for (comp.c_object_table.keys()) |key| {
1302 try positionals.append(.{ .path = key.status.success.object_path });
1303 }
1304
1305 if (module_obj_path) |path| try positionals.append(.{ .path = path });
1306
1307 for (positionals.items) |obj| {
1308 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1309 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
1310 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1311 }
1312
1534 // First, we flush relocatable object file generated with our backends.1313 // First, we flush relocatable object file generated with our backends.
1535 if (self.zigObjectPtr()) |zig_object| {1314 if (self.zigObjectPtr()) |zig_object| {
1536 zig_object.resolveSymbols(self);1315 zig_object.resolveSymbols(self);
...@@ -1539,16 +1318,17 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void...@@ -1539,16 +1318,17 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
1539 try self.initSymtab();1318 try self.initSymtab();
1540 try self.initShStrtab();1319 try self.initShStrtab();
1541 try self.sortShdrs();1320 try self.sortShdrs();
1542 zig_object.updateRelaSectionSizes(self);1321 try zig_object.addAtomsToRelaSections(self);
1543 self.updateSymtabSizeObject(zig_object);1322 try self.updateSectionSizesObject();
1544 self.updateShStrtabSize();
15451323
1546 try self.allocateNonAllocSections();1324 try self.allocateNonAllocSections();
15471325
1326 if (build_options.enable_logging) {
1327 state_log.debug("{}", .{self.dumpState()});
1328 }
1329
1330 try self.writeSyntheticSectionsObject();
1548 try self.writeShdrTable();1331 try self.writeShdrTable();
1549 try zig_object.writeRelaSections(self);
1550 try self.writeSymtabObject(zig_object);
1551 try self.writeShStrtab();
1552 try self.writeElfHeader();1332 try self.writeElfHeader();
1553 }1333 }
15541334
...@@ -1603,67 +1383,391 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void...@@ -1603,67 +1383,391 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
1603 pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);1383 pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
1604 }1384 }
16051385
1606 break :blk pos;1386 break :blk pos;
1607 };1387 };
1388
1389 if (build_options.enable_logging) {
1390 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1391 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
1392 }
1393
1394 var buffer = std.ArrayList(u8).init(gpa);
1395 defer buffer.deinit();
1396 try buffer.ensureTotalCapacityPrecise(total_size);
1397
1398 // Write magic
1399 try buffer.writer().writeAll(elf.ARMAG);
1400
1401 // Write symtab
1402 try ar_symtab.write(.p64, self, buffer.writer());
1403
1404 // Write strtab
1405 if (ar_strtab.size() > 0) {
1406 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1407 try ar_strtab.write(buffer.writer());
1408 }
1409
1410 // Write object files
1411 for (files.items) |index| {
1412 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1413 try self.file(index).?.writeAr(self, buffer.writer());
1414 }
1415
1416 assert(buffer.items.len == total_size);
1417
1418 try self.base.file.?.setEndPos(total_size);
1419 try self.base.file.?.pwriteAll(buffer.items, 0);
1420}
1421
1422pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1423 const gpa = self.base.allocator;
1424
1425 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
1426 defer positionals.deinit();
1427 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
1428 positionals.appendSliceAssumeCapacity(self.base.options.objects);
1429
1430 // This is a set of object files emitted by clang in a single `build-exe` invocation.
1431 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
1432 // in this set.
1433 for (comp.c_object_table.keys()) |key| {
1434 try positionals.append(.{ .path = key.status.success.object_path });
1435 }
1436
1437 if (module_obj_path) |path| try positionals.append(.{ .path = path });
1438
1439 for (positionals.items) |obj| {
1440 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1441 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
1442 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1443 }
1444
1445 // Init all objects
1446 for (self.objects.items) |index| {
1447 try self.file(index).?.object.init(self);
1448 }
1449
1450 // Now, we are ready to resolve the symbols across all input files.
1451 // We will first resolve the files in the ZigObject, next in the parsed
1452 // input Object files.
1453 self.resolveSymbols();
1454 self.markEhFrameAtomsDead();
1455 self.claimUnresolvedObject();
1456
1457 try self.initSectionsObject();
1458 try self.sortShdrs();
1459 if (self.zigObjectPtr()) |zig_object| {
1460 try zig_object.addAtomsToRelaSections(self);
1461 }
1462 for (self.objects.items) |index| {
1463 const object = self.file(index).?.object;
1464 try object.addAtomsToOutputSections(self);
1465 try object.addAtomsToRelaSections(self);
1466 }
1467 try self.updateSectionSizesObject();
1468
1469 try self.allocateAllocSectionsObject();
1470 try self.allocateNonAllocSections();
1471 self.allocateAtoms();
1472
1473 if (build_options.enable_logging) {
1474 state_log.debug("{}", .{self.dumpState()});
1475 }
1476
1477 try self.writeAtomsObject();
1478 try self.writeSyntheticSectionsObject();
1479 try self.writeShdrTable();
1480 try self.writeElfHeader();
1481}
1482
1483/// --verbose-link output
1484fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1485 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
1486 defer arena_allocator.deinit();
1487 const arena = arena_allocator.allocator();
1488
1489 const target = self.base.options.target;
1490 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
1491 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
1492 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
1493 if (fs.path.dirname(full_out_path)) |dirname| {
1494 break :blk try fs.path.join(arena, &.{ dirname, path });
1495 } else {
1496 break :blk path;
1497 }
1498 } else null;
1499 const gc_sections = self.base.options.gc_sections orelse false;
1500
1501 var csu = try CsuObjects.init(arena, self.base.options, comp);
1502 const compiler_rt_path: ?[]const u8 = blk: {
1503 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1504 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
1505 break :blk null;
1506 };
1507
1508 var argv = std.ArrayList([]const u8).init(arena);
1509
1510 try argv.append("zig");
1511
1512 if (self.isStaticLib()) {
1513 try argv.append("ar");
1514 } else {
1515 try argv.append("ld");
1516 }
1517
1518 if (self.isObject()) {
1519 try argv.append("-r");
1520 }
1521
1522 try argv.append("-o");
1523 try argv.append(full_out_path);
1524
1525 if (self.isRelocatable()) {
1526 for (self.base.options.objects) |obj| {
1527 try argv.append(obj.path);
1528 }
1529
1530 for (comp.c_object_table.keys()) |key| {
1531 try argv.append(key.status.success.object_path);
1532 }
1533
1534 if (module_obj_path) |p| {
1535 try argv.append(p);
1536 }
1537 } else {
1538 if (!self.isStatic()) {
1539 if (self.base.options.dynamic_linker) |path| {
1540 try argv.append("-dynamic-linker");
1541 try argv.append(path);
1542 }
1543 }
1544
1545 if (self.isDynLib()) {
1546 if (self.base.options.soname) |name| {
1547 try argv.append("-soname");
1548 try argv.append(name);
1549 }
1550 }
1551
1552 if (self.base.options.entry) |entry| {
1553 try argv.append("--entry");
1554 try argv.append(entry);
1555 }
1556
1557 for (self.base.options.rpath_list) |rpath| {
1558 try argv.append("-rpath");
1559 try argv.append(rpath);
1560 }
1561
1562 if (self.base.options.each_lib_rpath) {
1563 for (self.base.options.lib_dirs) |lib_dir_path| {
1564 try argv.append("-rpath");
1565 try argv.append(lib_dir_path);
1566 }
1567 for (self.base.options.objects) |obj| {
1568 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
1569 const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
1570 if (obj.loption) continue;
1571
1572 try argv.append("-rpath");
1573 try argv.append(lib_dir_path);
1574 }
1575 }
1576 }
1577
1578 if (self.base.options.stack_size_override) |ss| {
1579 try argv.append("-z");
1580 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
1581 }
1582
1583 if (self.base.options.image_base_override) |image_base| {
1584 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1585 }
1586
1587 if (gc_sections) {
1588 try argv.append("--gc-sections");
1589 }
1590
1591 if (self.base.options.print_gc_sections) {
1592 try argv.append("--print-gc-sections");
1593 }
1594
1595 if (self.base.options.eh_frame_hdr) {
1596 try argv.append("--eh-frame-hdr");
1597 }
1598
1599 if (self.base.options.rdynamic) {
1600 try argv.append("--export-dynamic");
1601 }
1602
1603 if (self.base.options.z_notext) {
1604 try argv.append("-z");
1605 try argv.append("notext");
1606 }
1607
1608 if (self.base.options.z_nocopyreloc) {
1609 try argv.append("-z");
1610 try argv.append("nocopyreloc");
1611 }
1612
1613 if (self.base.options.z_now) {
1614 try argv.append("-z");
1615 try argv.append("now");
1616 }
1617
1618 if (self.isStatic()) {
1619 try argv.append("-static");
1620 } else if (self.isDynLib()) {
1621 try argv.append("-shared");
1622 }
1623
1624 if (self.base.options.pie and self.isExe()) {
1625 try argv.append("-pie");
1626 }
1627
1628 if (self.base.options.strip) {
1629 try argv.append("-s");
1630 }
1631
1632 // csu prelude
1633 if (csu.crt0) |v| try argv.append(v);
1634 if (csu.crti) |v| try argv.append(v);
1635 if (csu.crtbegin) |v| try argv.append(v);
1636
1637 for (self.base.options.lib_dirs) |lib_dir| {
1638 try argv.append("-L");
1639 try argv.append(lib_dir);
1640 }
1641
1642 if (self.base.options.link_libc) {
1643 if (self.base.options.libc_installation) |libc_installation| {
1644 try argv.append("-L");
1645 try argv.append(libc_installation.crt_dir.?);
1646 }
1647 }
16081648
1609 if (build_options.enable_logging) {1649 var whole_archive = false;
1610 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});1650 for (self.base.options.objects) |obj| {
1611 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});1651 if (obj.must_link and !whole_archive) {
1612 }1652 try argv.append("-whole-archive");
1653 whole_archive = true;
1654 } else if (!obj.must_link and whole_archive) {
1655 try argv.append("-no-whole-archive");
1656 whole_archive = false;
1657 }
16131658
1614 var buffer = std.ArrayList(u8).init(gpa);1659 if (obj.loption) {
1615 defer buffer.deinit();1660 assert(obj.path[0] == ':');
1616 try buffer.ensureTotalCapacityPrecise(total_size);1661 try argv.append("-l");
1662 }
1663 try argv.append(obj.path);
1664 }
1665 if (whole_archive) {
1666 try argv.append("-no-whole-archive");
1667 whole_archive = false;
1668 }
16171669
1618 // Write magic1670 for (comp.c_object_table.keys()) |key| {
1619 try buffer.writer().writeAll(elf.ARMAG);1671 try argv.append(key.status.success.object_path);
1672 }
16201673
1621 // Write symtab1674 if (module_obj_path) |p| {
1622 try ar_symtab.write(.p64, self, buffer.writer());1675 try argv.append(p);
1676 }
16231677
1624 // Write strtab1678 // TSAN
1625 if (ar_strtab.size() > 0) {1679 if (self.base.options.tsan) {
1626 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);1680 try argv.append(comp.tsan_static_lib.?.full_object_path);
1627 try ar_strtab.write(buffer.writer());1681 }
1628 }
16291682
1630 // Write object files1683 // libc
1631 for (files.items) |index| {1684 if (!self.base.options.skip_linker_dependencies and
1632 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);1685 !self.base.options.link_libc)
1633 try self.file(index).?.writeAr(self, buffer.writer());1686 {
1634 }1687 if (comp.libc_static_lib) |lib| {
1688 try argv.append(lib.full_object_path);
1689 }
1690 }
16351691
1636 assert(buffer.items.len == total_size);1692 // stack-protector.
1693 // Related: https://github.com/ziglang/zig/issues/7265
1694 if (comp.libssp_static_lib) |ssp| {
1695 try argv.append(ssp.full_object_path);
1696 }
16371697
1638 try self.base.file.?.setEndPos(total_size);1698 // Shared libraries.
1639 try self.base.file.?.pwriteAll(buffer.items, 0);1699 // Worst-case, we need an --as-needed argument for every lib, as well
1640}1700 // as one before and one after.
1701 try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
1702 argv.appendAssumeCapacity("--as-needed");
1703 var as_needed = true;
16411704
1642pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {1705 for (self.base.options.system_libs.values()) |lib_info| {
1643 _ = comp;1706 const lib_as_needed = !lib_info.needed;
1707 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1708 0b00, 0b11 => {},
1709 0b01 => {
1710 argv.appendAssumeCapacity("--no-as-needed");
1711 as_needed = false;
1712 },
1713 0b10 => {
1714 argv.appendAssumeCapacity("--as-needed");
1715 as_needed = true;
1716 },
1717 }
1718 argv.appendAssumeCapacity(lib_info.path.?);
1719 }
16441720
1645 if (self.objects.items.len > 0) {1721 if (!as_needed) {
1646 var err = try self.addErrorWithNotes(1);1722 argv.appendAssumeCapacity("--as-needed");
1647 try err.addMsg(self, "fatal linker error: too many input positionals", .{});1723 as_needed = true;
1648 try err.addNote(self, "TODO implement '-r' option", .{});1724 }
1649 return;
1650 }
16511725
1652 self.claimUnresolvedObject();1726 // libc++ dep
1727 if (self.base.options.link_libcpp) {
1728 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1729 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1730 }
16531731
1654 try self.initSections();1732 // libunwind dep
1655 try self.sortShdrs();1733 if (self.base.options.link_libunwind) {
1656 try self.updateSectionSizes();1734 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1735 }
16571736
1658 try self.allocateNonAllocSections();1737 // libc dep
1738 if (self.base.options.link_libc) {
1739 if (self.base.options.libc_installation != null) {
1740 const needs_grouping = self.base.options.link_mode == .Static;
1741 if (needs_grouping) try argv.append("--start-group");
1742 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1743 if (needs_grouping) try argv.append("--end-group");
1744 } else if (target.isGnuLibC()) {
1745 for (glibc.libs) |lib| {
1746 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1747 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1748 });
1749 try argv.append(lib_path);
1750 }
1751 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1752 } else if (target.isMusl()) {
1753 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1754 .Static => "libc.a",
1755 .Dynamic => "libc.so",
1756 }));
1757 }
1758 }
16591759
1660 if (build_options.enable_logging) {1760 // compiler-rt
1661 state_log.debug("{}", .{self.dumpState()});1761 if (compiler_rt_path) |p| {
1762 try argv.append(p);
1763 }
1764
1765 // crt postlude
1766 if (csu.crtend) |v| try argv.append(v);
1767 if (csu.crtn) |v| try argv.append(v);
1662 }1768 }
16631769
1664 try self.writeShdrTable();1770 Compilation.dump_argv(argv.items);
1665 try self.writeSyntheticSections();
1666 try self.writeElfHeader();
1667}1771}
16681772
1669const ParseError = error{1773const ParseError = error{
...@@ -2047,8 +2151,7 @@ fn claimUnresolved(self: *Elf) void {...@@ -2047,8 +2151,7 @@ fn claimUnresolved(self: *Elf) void {
2047 zig_object.claimUnresolved(self);2151 zig_object.claimUnresolved(self);
2048 }2152 }
2049 for (self.objects.items) |index| {2153 for (self.objects.items) |index| {
2050 const object = self.file(index).?.object;2154 self.file(index).?.object.claimUnresolved(self);
2051 object.claimUnresolved(self);
2052 }2155 }
2053}2156}
20542157
...@@ -2056,6 +2159,9 @@ fn claimUnresolvedObject(self: *Elf) void {...@@ -2056,6 +2159,9 @@ fn claimUnresolvedObject(self: *Elf) void {
2056 if (self.zigObjectPtr()) |zig_object| {2159 if (self.zigObjectPtr()) |zig_object| {
2057 zig_object.claimUnresolvedObject(self);2160 zig_object.claimUnresolvedObject(self);
2058 }2161 }
2162 for (self.objects.items) |index| {
2163 self.file(index).?.object.claimUnresolvedObject(self);
2164 }
2059}2165}
20602166
2061/// In scanRelocs we will go over all live atoms and scan their relocs.2167/// In scanRelocs we will go over all live atoms and scan their relocs.
...@@ -3460,6 +3566,60 @@ fn initSections(self: *Elf) !void {...@@ -3460,6 +3566,60 @@ fn initSections(self: *Elf) !void {
3460 try self.initShStrtab();3566 try self.initShStrtab();
3461}3567}
34623568
3569fn initSectionsObject(self: *Elf) !void {
3570 const ptr_size = self.ptrWidthBytes();
3571
3572 for (self.objects.items) |index| {
3573 const object = self.file(index).?.object;
3574 try object.initOutputSections(self);
3575 try object.initRelaSections(self);
3576 }
3577
3578 const needs_eh_frame = for (self.objects.items) |index| {
3579 if (self.file(index).?.object.cies.items.len > 0) break true;
3580 } else false;
3581 if (needs_eh_frame) {
3582 self.eh_frame_section_index = try self.addSection(.{
3583 .name = ".eh_frame",
3584 .type = elf.SHT_PROGBITS,
3585 .flags = elf.SHF_ALLOC,
3586 .addralign = ptr_size,
3587 .offset = std.math.maxInt(u64),
3588 });
3589 self.eh_frame_rela_section_index = try self.addRelaShdr(".rela.eh_frame", self.eh_frame_section_index.?);
3590 }
3591
3592 try self.initComdatGroups();
3593 try self.initSymtab();
3594 try self.initShStrtab();
3595}
3596
3597fn initComdatGroups(self: *Elf) !void {
3598 const gpa = self.base.allocator;
3599
3600 for (self.objects.items) |index| {
3601 const object = self.file(index).?.object;
3602
3603 for (object.comdat_groups.items) |cg_index| {
3604 const cg = self.comdatGroup(cg_index);
3605 const cg_owner = self.comdatGroupOwner(cg.owner);
3606 if (cg_owner.file != index) continue;
3607
3608 const cg_sec = try self.comdat_group_sections.addOne(gpa);
3609 cg_sec.* = .{
3610 .shndx = try self.addSection(.{
3611 .name = ".group",
3612 .type = elf.SHT_GROUP,
3613 .entsize = @sizeOf(u32),
3614 .addralign = @alignOf(u32),
3615 .offset = std.math.maxInt(u64),
3616 }),
3617 .cg_index = cg_index,
3618 };
3619 }
3620 }
3621}
3622
3463fn initSymtab(self: *Elf) !void {3623fn initSymtab(self: *Elf) !void {
3464 const small_ptr = switch (self.ptr_width) {3624 const small_ptr = switch (self.ptr_width) {
3465 .p32 => true,3625 .p32 => true,
...@@ -3586,7 +3746,8 @@ fn sortInitFini(self: *Elf) !void {...@@ -3586,7 +3746,8 @@ fn sortInitFini(self: *Elf) !void {
35863746
3587 if (!is_init_fini and !is_ctor_dtor) continue;3747 if (!is_init_fini and !is_ctor_dtor) continue;
35883748
3589 const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue;3749 const atom_list = self.output_sections.getPtr(@intCast(shndx)).?;
3750 if (atom_list.items.len == 0) continue;
35903751
3591 var entries = std.ArrayList(Entry).init(gpa);3752 var entries = std.ArrayList(Entry).init(gpa);
3592 try entries.ensureTotalCapacityPrecise(atom_list.items.len);3753 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
...@@ -3627,8 +3788,10 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {...@@ -3627,8 +3788,10 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
3627 try self.dynamic.addNeeded(shared_object, self);3788 try self.dynamic.addNeeded(shared_object, self);
3628 }3789 }
36293790
3630 if (self.base.options.soname) |soname| {3791 if (self.isDynLib()) {
3631 try self.dynamic.setSoname(soname, self);3792 if (self.base.options.soname) |soname| {
3793 try self.dynamic.setSoname(soname, self);
3794 }
3632 }3795 }
36333796
3634 try self.dynamic.setRpath(rpaths, self);3797 try self.dynamic.setRpath(rpaths, self);
...@@ -3760,7 +3923,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 {...@@ -3760,7 +3923,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 {
37603923
3761 elf.SHT_DYNAMIC => return 0xf3,3924 elf.SHT_DYNAMIC => return 0xf3,
37623925
3763 elf.SHT_RELA => return 0xf,3926 elf.SHT_RELA, elf.SHT_GROUP => return 0xf,
37643927
3765 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {3928 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
3766 if (flags & elf.SHF_EXECINSTR != 0) {3929 if (flags & elf.SHF_EXECINSTR != 0) {
...@@ -3819,8 +3982,15 @@ fn sortShdrs(self: *Elf) !void {...@@ -3819,8 +3982,15 @@ fn sortShdrs(self: *Elf) !void {
3819 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);3982 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
3820 }3983 }
38213984
3985 try self.resetShdrIndexes(backlinks);
3986}
3987
3988fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void {
3989 const gpa = self.base.allocator;
3990
3822 for (&[_]*?u16{3991 for (&[_]*?u16{
3823 &self.eh_frame_section_index,3992 &self.eh_frame_section_index,
3993 &self.eh_frame_rela_section_index,
3824 &self.eh_frame_hdr_section_index,3994 &self.eh_frame_hdr_section_index,
3825 &self.got_section_index,3995 &self.got_section_index,
3826 &self.symtab_section_index,3996 &self.symtab_section_index,
...@@ -3841,12 +4011,9 @@ fn sortShdrs(self: *Elf) !void {...@@ -3841,12 +4011,9 @@ fn sortShdrs(self: *Elf) !void {
3841 &self.versym_section_index,4011 &self.versym_section_index,
3842 &self.verneed_section_index,4012 &self.verneed_section_index,
3843 &self.zig_text_section_index,4013 &self.zig_text_section_index,
3844 &self.zig_text_rela_section_index,
3845 &self.zig_got_section_index,4014 &self.zig_got_section_index,
3846 &self.zig_data_rel_ro_section_index,4015 &self.zig_data_rel_ro_section_index,
3847 &self.zig_data_rel_ro_rela_section_index,
3848 &self.zig_data_section_index,4016 &self.zig_data_section_index,
3849 &self.zig_data_rela_section_index,
3850 &self.zig_bss_section_index,4017 &self.zig_bss_section_index,
3851 &self.debug_str_section_index,4018 &self.debug_str_section_index,
3852 &self.debug_info_section_index,4019 &self.debug_info_section_index,
...@@ -3905,15 +4072,39 @@ fn sortShdrs(self: *Elf) !void {...@@ -3905,15 +4072,39 @@ fn sortShdrs(self: *Elf) !void {
3905 shdr.sh_info = self.plt_section_index.?;4072 shdr.sh_info = self.plt_section_index.?;
3906 }4073 }
39074074
3908 for (&[_]?u16{4075 if (self.eh_frame_rela_section_index) |index| {
3909 self.zig_text_rela_section_index,
3910 self.zig_data_rel_ro_rela_section_index,
3911 self.zig_data_rela_section_index,
3912 }) |maybe_index| {
3913 const index = maybe_index orelse continue;
3914 const shdr = &self.shdrs.items[index];4076 const shdr = &self.shdrs.items[index];
3915 shdr.sh_link = self.symtab_section_index.?;4077 shdr.sh_link = self.symtab_section_index.?;
3916 shdr.sh_info = backlinks[shdr.sh_info];4078 shdr.sh_info = self.eh_frame_section_index.?;
4079 }
4080
4081 {
4082 var output_sections = try self.output_sections.clone(gpa);
4083 defer output_sections.deinit(gpa);
4084
4085 self.output_sections.clearRetainingCapacity();
4086
4087 var it = output_sections.iterator();
4088 while (it.next()) |entry| {
4089 const shndx = entry.key_ptr.*;
4090 const meta = entry.value_ptr.*;
4091 self.output_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta);
4092 }
4093 }
4094
4095 {
4096 var output_rela_sections = try self.output_rela_sections.clone(gpa);
4097 defer output_rela_sections.deinit(gpa);
4098
4099 self.output_rela_sections.clearRetainingCapacity();
4100
4101 var it = output_rela_sections.iterator();
4102 while (it.next()) |entry| {
4103 const shndx = entry.key_ptr.*;
4104 var meta = entry.value_ptr.*;
4105 meta.shndx = backlinks[meta.shndx];
4106 self.output_rela_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta);
4107 }
3917 }4108 }
39184109
3919 {4110 {
...@@ -3965,11 +4156,20 @@ fn sortShdrs(self: *Elf) !void {...@@ -3965,11 +4156,20 @@ fn sortShdrs(self: *Elf) !void {
3965 global.output_section_index = backlinks[out_shndx];4156 global.output_section_index = backlinks[out_shndx];
3966 }4157 }
3967 }4158 }
4159
4160 for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| {
4161 const shdr = &self.shdrs.items[sec.shndx];
4162 shdr.sh_link = self.symtab_section_index.?;
4163 shdr.sh_info = shndx;
4164 }
4165
4166 for (self.comdat_group_sections.items) |*cg| {
4167 cg.shndx = backlinks[cg.shndx];
4168 }
3968}4169}
39694170
3970fn updateSectionSizes(self: *Elf) !void {4171fn updateSectionSizes(self: *Elf) !void {
3971 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {4172 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
3972 if (atom_list.items.len == 0) continue;
3973 const shdr = &self.shdrs.items[shndx];4173 const shdr = &self.shdrs.items[shndx];
3974 for (atom_list.items) |atom_index| {4174 for (atom_list.items) |atom_index| {
3975 const atom_ptr = self.atom(atom_index) orelse continue;4175 const atom_ptr = self.atom(atom_index) orelse continue;
...@@ -3982,10 +4182,6 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3982,10 +4182,6 @@ fn updateSectionSizes(self: *Elf) !void {
3982 }4182 }
3983 }4183 }
39844184
3985 if (self.zigObjectPtr()) |zig_object| {
3986 zig_object.updateRelaSectionSizes(self);
3987 }
3988
3989 if (self.eh_frame_section_index) |index| {4185 if (self.eh_frame_section_index) |index| {
3990 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);4186 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
3991 }4187 }
...@@ -4049,22 +4245,73 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4049,22 +4245,73 @@ fn updateSectionSizes(self: *Elf) !void {
4049 self.shdrs.items[index].sh_size = self.dynsym.size();4245 self.shdrs.items[index].sh_size = self.dynsym.size();
4050 }4246 }
40514247
4052 if (self.dynstrtab_section_index) |index| {4248 if (self.dynstrtab_section_index) |index| {
4053 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;4249 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
4054 }4250 }
4251
4252 if (self.versym_section_index) |index| {
4253 self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
4254 }
4255
4256 if (self.verneed_section_index) |index| {
4257 self.shdrs.items[index].sh_size = self.verneed.size();
4258 }
4259
4260 try self.updateSymtabSize();
4261 self.updateShStrtabSize();
4262}
4263
4264fn updateSectionSizesObject(self: *Elf) !void {
4265 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
4266 const shdr = &self.shdrs.items[shndx];
4267 for (atom_list.items) |atom_index| {
4268 const atom_ptr = self.atom(atom_index) orelse continue;
4269 if (!atom_ptr.flags.alive) continue;
4270 const offset = atom_ptr.alignment.forward(shdr.sh_size);
4271 const padding = offset - shdr.sh_size;
4272 atom_ptr.value = offset;
4273 shdr.sh_size += padding + atom_ptr.size;
4274 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
4275 }
4276 }
4277
4278 for (self.output_rela_sections.values()) |sec| {
4279 const shdr = &self.shdrs.items[sec.shndx];
4280 for (sec.atom_list.items) |atom_index| {
4281 const atom_ptr = self.atom(atom_index) orelse continue;
4282 if (!atom_ptr.flags.alive) continue;
4283 const relocs = atom_ptr.relocs(self);
4284 shdr.sh_size += shdr.sh_entsize * relocs.len;
4285 }
40554286
4056 if (self.versym_section_index) |index| {4287 if (shdr.sh_size == 0) shdr.sh_offset = 0;
4057 self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
4058 }4288 }
40594289
4060 if (self.verneed_section_index) |index| {4290 if (self.eh_frame_section_index) |index| {
4061 self.shdrs.items[index].sh_size = self.verneed.size();4291 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
4292 }
4293 if (self.eh_frame_rela_section_index) |index| {
4294 const shdr = &self.shdrs.items[index];
4295 shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize;
4062 }4296 }
40634297
4064 self.updateSymtabSize();4298 try self.updateSymtabSize();
4299 self.updateComdatGroupsSizes();
4065 self.updateShStrtabSize();4300 self.updateShStrtabSize();
4066}4301}
40674302
4303fn updateComdatGroupsSizes(self: *Elf) void {
4304 for (self.comdat_group_sections.items) |cg| {
4305 const shdr = &self.shdrs.items[cg.shndx];
4306 shdr.sh_size = cg.size(self);
4307 shdr.sh_link = self.symtab_section_index.?;
4308
4309 const sym = self.symbol(cg.symbol(self));
4310 shdr.sh_info = sym.outputSymtabIndex(self) orelse
4311 self.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
4312 }
4313}
4314
4068fn updateShStrtabSize(self: *Elf) void {4315fn updateShStrtabSize(self: *Elf) void {
4069 if (self.shstrtab_section_index) |index| {4316 if (self.shstrtab_section_index) |index| {
4070 self.shdrs.items[index].sh_size = self.shstrtab.items.len;4317 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
...@@ -4294,6 +4541,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {...@@ -4294,6 +4541,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
4294 }4541 }
4295}4542}
42964543
4544/// Allocates alloc sections when merging relocatable objects files together.
4545fn allocateAllocSectionsObject(self: *Elf) !void {
4546 for (self.shdrs.items) |*shdr| {
4547 if (shdr.sh_type == elf.SHT_NULL) continue;
4548 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
4549 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4550 const needed_size = shdr.sh_size;
4551 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
4552 shdr.sh_size = 0;
4553 const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign);
4554 shdr.sh_offset = new_offset;
4555 shdr.sh_size = needed_size;
4556 }
4557 }
4558}
4559
4297/// Allocates non-alloc sections (debug info, symtabs, etc.).4560/// Allocates non-alloc sections (debug info, symtabs, etc.).
4298fn allocateNonAllocSections(self: *Elf) !void {4561fn allocateNonAllocSections(self: *Elf) !void {
4299 for (self.shdrs.items, 0..) |*shdr, shndx| {4562 for (self.shdrs.items, 0..) |*shdr, shndx| {
...@@ -4418,6 +4681,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -4418,6 +4681,7 @@ fn writeAtoms(self: *Elf) !void {
4418 if (shdr.sh_type == elf.SHT_NOBITS) continue;4681 if (shdr.sh_type == elf.SHT_NOBITS) continue;
44194682
4420 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;4683 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4684 if (atom_list.items.len == 0) continue;
44214685
4422 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});4686 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
44234687
...@@ -4484,93 +4748,165 @@ fn writeAtoms(self: *Elf) !void {...@@ -4484,93 +4748,165 @@ fn writeAtoms(self: *Elf) !void {
4484 try self.reportUndefined(&undefs);4748 try self.reportUndefined(&undefs);
4485}4749}
44864750
4487fn updateSymtabSize(self: *Elf) void {4751fn writeAtomsObject(self: *Elf) !void {
4488 var sizes = SymtabSize{};4752 const gpa = self.base.allocator;
44894753
4490 if (self.zigObjectPtr()) |zig_object| {4754 // TODO iterate over `output_sections` directly
4491 zig_object.asFile().updateSymtabSize(self);4755 for (self.shdrs.items, 0..) |shdr, shndx| {
4492 sizes.add(zig_object.output_symtab_size);4756 if (shdr.sh_type == elf.SHT_NULL) continue;
4757 if (shdr.sh_type == elf.SHT_NOBITS) continue;
4758
4759 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4760 if (atom_list.items.len == 0) continue;
4761
4762 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
4763
4764 // TODO really, really handle debug section separately
4765 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
4766 const zig_object = self.zigObjectPtr().?;
4767 if (shndx == self.debug_info_section_index.?)
4768 break :blk zig_object.debug_info_section_zig_size;
4769 if (shndx == self.debug_abbrev_section_index.?)
4770 break :blk zig_object.debug_abbrev_section_zig_size;
4771 if (shndx == self.debug_str_section_index.?)
4772 break :blk zig_object.debug_str_section_zig_size;
4773 if (shndx == self.debug_aranges_section_index.?)
4774 break :blk zig_object.debug_aranges_section_zig_size;
4775 if (shndx == self.debug_line_section_index.?)
4776 break :blk zig_object.debug_line_section_zig_size;
4777 unreachable;
4778 } else 0;
4779 const sh_offset = shdr.sh_offset + base_offset;
4780 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
4781
4782 const buffer = try gpa.alloc(u8, sh_size);
4783 defer gpa.free(buffer);
4784 const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
4785 shdr.sh_flags & elf.SHF_EXECINSTR != 0)
4786 0xcc // int3
4787 else
4788 0;
4789 @memset(buffer, padding_byte);
4790
4791 for (atom_list.items) |atom_index| {
4792 const atom_ptr = self.atom(atom_index).?;
4793 assert(atom_ptr.flags.alive);
4794
4795 const object = atom_ptr.file(self).?.object;
4796 const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse
4797 return error.Overflow;
4798 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
4799
4800 log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{
4801 atom_index,
4802 sh_offset + offset,
4803 sh_offset + offset + size,
4804 });
4805
4806 // TODO decompress directly into provided buffer
4807 const out_code = buffer[offset..][0..size];
4808 const in_code = try object.codeDecompressAlloc(self, atom_index);
4809 defer gpa.free(in_code);
4810 @memcpy(out_code, in_code);
4811 }
4812
4813 try self.base.file.?.pwriteAll(buffer, sh_offset);
4493 }4814 }
4815}
4816
4817fn updateSymtabSize(self: *Elf) !void {
4818 var nlocals: u32 = 0;
4819 var nglobals: u32 = 0;
4820 var strsize: u32 = 0;
4821
4822 const gpa = self.base.allocator;
4823 var files = std.ArrayList(File.Index).init(gpa);
4824 defer files.deinit();
4825 try files.ensureTotalCapacityPrecise(self.objects.items.len + self.shared_objects.items.len + 1);
44944826
4827 if (self.zig_object_index) |index| files.appendAssumeCapacity(index);
4495 for (self.objects.items) |index| {4828 for (self.objects.items) |index| {
4496 const file_ptr = self.file(index).?;4829 files.appendAssumeCapacity(index);
4497 file_ptr.updateSymtabSize(self);
4498 sizes.add(file_ptr.object.output_symtab_size);
4499 }4830 }
4500
4501 for (self.shared_objects.items) |index| {4831 for (self.shared_objects.items) |index| {
4832 files.appendAssumeCapacity(index);
4833 }
4834
4835 // Section symbols
4836 for (self.output_sections.keys()) |_| {
4837 nlocals += 1;
4838 }
4839 if (self.eh_frame_section_index) |_| {
4840 nlocals += 1;
4841 }
4842
4843 for (files.items) |index| {
4502 const file_ptr = self.file(index).?;4844 const file_ptr = self.file(index).?;
4503 file_ptr.updateSymtabSize(self);4845 const ctx = switch (file_ptr) {
4504 sizes.add(file_ptr.shared_object.output_symtab_size);4846 inline else => |x| &x.output_symtab_ctx,
4847 };
4848 ctx.ilocal = nlocals + 1;
4849 ctx.iglobal = nglobals + 1;
4850 try file_ptr.updateSymtabSize(self);
4851 nlocals += ctx.nlocals;
4852 nglobals += ctx.nglobals;
4853 strsize += ctx.strsize;
4505 }4854 }
45064855
4507 if (self.zig_got_section_index) |_| {4856 if (self.zig_got_section_index) |_| {
4857 self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
4508 self.zig_got.updateSymtabSize(self);4858 self.zig_got.updateSymtabSize(self);
4509 sizes.add(self.zig_got.output_symtab_size);4859 nlocals += self.zig_got.output_symtab_ctx.nlocals;
4860 strsize += self.zig_got.output_symtab_ctx.strsize;
4510 }4861 }
45114862
4512 if (self.got_section_index) |_| {4863 if (self.got_section_index) |_| {
4864 self.got.output_symtab_ctx.ilocal = nlocals + 1;
4513 self.got.updateSymtabSize(self);4865 self.got.updateSymtabSize(self);
4514 sizes.add(self.got.output_symtab_size);4866 nlocals += self.got.output_symtab_ctx.nlocals;
4867 strsize += self.got.output_symtab_ctx.strsize;
4515 }4868 }
45164869
4517 if (self.plt_section_index) |_| {4870 if (self.plt_section_index) |_| {
4871 self.plt.output_symtab_ctx.ilocal = nlocals + 1;
4518 self.plt.updateSymtabSize(self);4872 self.plt.updateSymtabSize(self);
4519 sizes.add(self.plt.output_symtab_size);4873 nlocals += self.plt.output_symtab_ctx.nlocals;
4874 strsize += self.plt.output_symtab_ctx.strsize;
4520 }4875 }
45214876
4522 if (self.plt_got_section_index) |_| {4877 if (self.plt_got_section_index) |_| {
4878 self.plt_got.output_symtab_ctx.ilocal = nlocals + 1;
4523 self.plt_got.updateSymtabSize(self);4879 self.plt_got.updateSymtabSize(self);
4524 sizes.add(self.plt_got.output_symtab_size);4880 nlocals += self.plt_got.output_symtab_ctx.nlocals;
4881 strsize += self.plt_got.output_symtab_ctx.strsize;
4525 }4882 }
45264883
4527 if (self.linker_defined_index) |index| {4884 for (files.items) |index| {
4528 const file_ptr = self.file(index).?;4885 const file_ptr = self.file(index).?;
4529 file_ptr.updateSymtabSize(self);4886 const ctx = switch (file_ptr) {
4530 sizes.add(file_ptr.linker_defined.output_symtab_size);4887 inline else => |x| &x.output_symtab_ctx,
4888 };
4889 ctx.iglobal += nlocals;
4531 }4890 }
45324891
4533 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];4892 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4534 symtab_shdr.sh_info = sizes.nlocals + 1;4893 symtab_shdr.sh_info = nlocals + 1;
4535 symtab_shdr.sh_link = self.strtab_section_index.?;
4536
4537 const sym_size: u64 = switch (self.ptr_width) {
4538 .p32 => @sizeOf(elf.Elf32_Sym),
4539 .p64 => @sizeOf(elf.Elf64_Sym),
4540 };
4541 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
4542 symtab_shdr.sh_size = needed_size;
4543
4544 const strtab = &self.shdrs.items[self.strtab_section_index.?];
4545 strtab.sh_size = sizes.strsize + 1;
4546}
4547
4548fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {
4549 zig_object.asFile().updateSymtabSize(self);
4550 const sizes = zig_object.output_symtab_size;
4551
4552 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4553 symtab_shdr.sh_info = sizes.nlocals + 1;
4554 symtab_shdr.sh_link = self.strtab_section_index.?;4894 symtab_shdr.sh_link = self.strtab_section_index.?;
45554895
4556 const sym_size: u64 = switch (self.ptr_width) {4896 const sym_size: u64 = switch (self.ptr_width) {
4557 .p32 => @sizeOf(elf.Elf32_Sym),4897 .p32 => @sizeOf(elf.Elf32_Sym),
4558 .p64 => @sizeOf(elf.Elf64_Sym),4898 .p64 => @sizeOf(elf.Elf64_Sym),
4559 };4899 };
4560 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;4900 const needed_size = (nlocals + nglobals + 1) * sym_size;
4561 symtab_shdr.sh_size = needed_size;4901 symtab_shdr.sh_size = needed_size;
45624902
4563 const strtab = &self.shdrs.items[self.strtab_section_index.?];4903 const strtab = &self.shdrs.items[self.strtab_section_index.?];
4564 strtab.sh_size = sizes.strsize + 1;4904 strtab.sh_size = strsize + 1;
4565}4905}
45664906
4567fn writeSyntheticSections(self: *Elf) !void {4907fn writeSyntheticSections(self: *Elf) !void {
4568 const gpa = self.base.allocator;4908 const gpa = self.base.allocator;
45694909
4570 if (self.zigObjectPtr()) |zig_object| {
4571 try zig_object.writeRelaSections(self);
4572 }
4573
4574 if (self.interp_section_index) |shndx| {4910 if (self.interp_section_index) |shndx| {
4575 const shdr = self.shdrs.items[shndx];4911 const shdr = self.shdrs.items[shndx];
4576 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;4912 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
...@@ -4698,9 +5034,97 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4698,9 +5034,97 @@ fn writeSyntheticSections(self: *Elf) !void {
4698 try self.writeShStrtab();5034 try self.writeShStrtab();
4699}5035}
47005036
5037fn writeSyntheticSectionsObject(self: *Elf) !void {
5038 const gpa = self.base.allocator;
5039
5040 for (self.output_rela_sections.values()) |sec| {
5041 if (sec.atom_list.items.len == 0) continue;
5042
5043 const shdr = self.shdrs.items[sec.shndx];
5044
5045 const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse
5046 return error.Overflow;
5047 var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
5048 defer relocs.deinit();
5049
5050 for (sec.atom_list.items) |atom_index| {
5051 const atom_ptr = self.atom(atom_index) orelse continue;
5052 if (!atom_ptr.flags.alive) continue;
5053 try atom_ptr.writeRelocs(self, &relocs);
5054 }
5055 assert(relocs.items.len == num_relocs);
5056
5057 const SortRelocs = struct {
5058 pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
5059 _ = ctx;
5060 return lhs.r_offset < rhs.r_offset;
5061 }
5062 };
5063
5064 mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan);
5065
5066 log.debug("writing {s} from 0x{x} to 0x{x}", .{
5067 self.getShString(shdr.sh_name),
5068 shdr.sh_offset,
5069 shdr.sh_offset + shdr.sh_size,
5070 });
5071
5072 try self.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
5073 }
5074
5075 if (self.eh_frame_section_index) |shndx| {
5076 const shdr = self.shdrs.items[shndx];
5077 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
5078 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
5079 defer buffer.deinit();
5080 try eh_frame.writeEhFrameObject(self, buffer.writer());
5081 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
5082 shdr.sh_offset,
5083 shdr.sh_offset + shdr.sh_size,
5084 });
5085 assert(buffer.items.len == sh_size);
5086 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
5087 }
5088 if (self.eh_frame_rela_section_index) |shndx| {
5089 const shdr = self.shdrs.items[shndx];
5090 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
5091 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
5092 defer buffer.deinit();
5093 try eh_frame.writeEhFrameRelocs(self, buffer.writer());
5094 assert(buffer.items.len == sh_size);
5095 log.debug("writing .rela.eh_frame from 0x{x} to 0x{x}", .{
5096 shdr.sh_offset,
5097 shdr.sh_offset + shdr.sh_size,
5098 });
5099 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
5100 }
5101
5102 try self.writeComdatGroups();
5103 try self.writeSymtab();
5104 try self.writeShStrtab();
5105}
5106
5107fn writeComdatGroups(self: *Elf) !void {
5108 const gpa = self.base.allocator;
5109 for (self.comdat_group_sections.items) |cgs| {
5110 const shdr = self.shdrs.items[cgs.shndx];
5111 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
5112 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
5113 defer buffer.deinit();
5114 try cgs.write(self, buffer.writer());
5115 assert(buffer.items.len == sh_size);
5116 log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{
5117 shdr.sh_offset,
5118 shdr.sh_offset + shdr.sh_size,
5119 });
5120 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
5121 }
5122}
5123
4701fn writeShStrtab(self: *Elf) !void {5124fn writeShStrtab(self: *Elf) !void {
4702 if (self.shstrtab_section_index) |index| {5125 if (self.shstrtab_section_index) |index| {
4703 const shdr = self.shdrs.items[index];5126 const shdr = self.shdrs.items[index];
5127 log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size });
4704 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);5128 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
4705 }5129 }
4706}5130}
...@@ -4715,67 +5139,55 @@ fn writeSymtab(self: *Elf) !void {...@@ -4715,67 +5139,55 @@ fn writeSymtab(self: *Elf) !void {
4715 };5139 };
4716 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;5140 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
47175141
4718 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });5142 log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{
5143 nsyms,
5144 symtab_shdr.sh_offset,
5145 symtab_shdr.sh_offset + symtab_shdr.sh_size,
5146 });
5147 log.debug("writing .strtab from 0x{x} to 0x{x}", .{
5148 strtab_shdr.sh_offset,
5149 strtab_shdr.sh_offset + strtab_shdr.sh_size,
5150 });
47195151
4720 try self.symtab.resize(gpa, nsyms);5152 try self.symtab.resize(gpa, nsyms);
4721 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;5153 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
4722 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);5154 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
47235155
4724 const Ctx = struct {5156 self.writeSectionSymbols();
4725 ilocal: usize,
4726 iglobal: usize,
4727
4728 fn incr(this: *@This(), ss: SymtabSize) void {
4729 this.ilocal += ss.nlocals;
4730 this.iglobal += ss.nglobals;
4731 }
4732 };
4733 var ctx: Ctx = .{
4734 .ilocal = 1,
4735 .iglobal = symtab_shdr.sh_info,
4736 };
47375157
4738 if (self.zigObjectPtr()) |zig_object| {5158 if (self.zigObjectPtr()) |zig_object| {
4739 zig_object.asFile().writeSymtab(self, ctx);5159 zig_object.asFile().writeSymtab(self);
4740 ctx.incr(zig_object.output_symtab_size);
4741 }5160 }
47425161
4743 for (self.objects.items) |index| {5162 for (self.objects.items) |index| {
4744 const file_ptr = self.file(index).?;5163 const file_ptr = self.file(index).?;
4745 file_ptr.writeSymtab(self, ctx);5164 file_ptr.writeSymtab(self);
4746 ctx.incr(file_ptr.object.output_symtab_size);
4747 }5165 }
47485166
4749 for (self.shared_objects.items) |index| {5167 for (self.shared_objects.items) |index| {
4750 const file_ptr = self.file(index).?;5168 const file_ptr = self.file(index).?;
4751 file_ptr.writeSymtab(self, ctx);5169 file_ptr.writeSymtab(self);
4752 ctx.incr(file_ptr.shared_object.output_symtab_size);
4753 }5170 }
47545171
4755 if (self.zig_got_section_index) |_| {5172 if (self.zig_got_section_index) |_| {
4756 self.zig_got.writeSymtab(self, ctx);5173 self.zig_got.writeSymtab(self);
4757 ctx.incr(self.zig_got.output_symtab_size);
4758 }5174 }
47595175
4760 if (self.got_section_index) |_| {5176 if (self.got_section_index) |_| {
4761 self.got.writeSymtab(self, ctx);5177 self.got.writeSymtab(self);
4762 ctx.incr(self.got.output_symtab_size);
4763 }5178 }
47645179
4765 if (self.plt_section_index) |_| {5180 if (self.plt_section_index) |_| {
4766 self.plt.writeSymtab(self, ctx);5181 self.plt.writeSymtab(self);
4767 ctx.incr(self.plt.output_symtab_size);
4768 }5182 }
47695183
4770 if (self.plt_got_section_index) |_| {5184 if (self.plt_got_section_index) |_| {
4771 self.plt_got.writeSymtab(self, ctx);5185 self.plt_got.writeSymtab(self);
4772 ctx.incr(self.plt_got.output_symtab_size);
4773 }5186 }
47745187
4775 if (self.linker_defined_index) |index| {5188 if (self.linker_defined_index) |index| {
4776 const file_ptr = self.file(index).?;5189 const file_ptr = self.file(index).?;
4777 file_ptr.writeSymtab(self, ctx);5190 file_ptr.writeSymtab(self);
4778 ctx.incr(file_ptr.linker_defined.output_symtab_size);
4779 }5191 }
47805192
4781 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();5193 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
...@@ -4808,52 +5220,42 @@ fn writeSymtab(self: *Elf) !void {...@@ -4808,52 +5220,42 @@ fn writeSymtab(self: *Elf) !void {
4808 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);5220 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
4809}5221}
48105222
4811fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {5223fn writeSectionSymbols(self: *Elf) void {
4812 const gpa = self.base.allocator;5224 var ilocal: u32 = 1;
4813 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];5225 for (self.output_sections.keys()) |shndx| {
4814 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];5226 const shdr = self.shdrs.items[shndx];
4815 const sym_size: u64 = switch (self.ptr_width) {5227 const out_sym = &self.symtab.items[ilocal];
4816 .p32 => @sizeOf(elf.Elf32_Sym),5228 out_sym.* = .{
4817 .p64 => @sizeOf(elf.Elf64_Sym),5229 .st_name = 0,
4818 };5230 .st_value = shdr.sh_addr,
4819 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;5231 .st_info = elf.STT_SECTION,
48205232 .st_shndx = @intCast(shndx),
4821 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });5233 .st_size = 0,
48225234 .st_other = 0,
4823 try self.symtab.resize(gpa, nsyms);5235 };
4824 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;5236 ilocal += 1;
4825 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);5237 }
4826
4827 zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info });
4828
4829 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
4830 switch (self.ptr_width) {
4831 .p32 => {
4832 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
4833 defer gpa.free(buf);
48345238
4835 for (buf, self.symtab.items) |*out, sym| {5239 if (self.eh_frame_section_index) |shndx| {
4836 out.* = .{5240 const shdr = self.shdrs.items[shndx];
4837 .st_name = sym.st_name,5241 const out_sym = &self.symtab.items[ilocal];
4838 .st_info = sym.st_info,5242 out_sym.* = .{
4839 .st_other = sym.st_other,5243 .st_name = 0,
4840 .st_shndx = sym.st_shndx,5244 .st_value = shdr.sh_addr,
4841 .st_value = @as(u32, @intCast(sym.st_value)),5245 .st_info = elf.STT_SECTION,
4842 .st_size = @as(u32, @intCast(sym.st_size)),5246 .st_shndx = @intCast(shndx),
4843 };5247 .st_size = 0,
4844 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);5248 .st_other = 0,
4845 }5249 };
4846 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);5250 ilocal += 1;
4847 },
4848 .p64 => {
4849 if (foreign_endian) {
4850 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
4851 }
4852 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
4853 },
4854 }5251 }
5252}
48555253
4856 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);5254pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
5255 if (self.eh_frame_section_index) |index| {
5256 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
5257 }
5258 return @intCast(self.output_sections.getIndex(shndx).? + 1);
4857}5259}
48585260
4859/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.5261/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
...@@ -5707,13 +6109,69 @@ fn formatShdr(...@@ -5707,13 +6109,69 @@ fn formatShdr(
5707 _ = options;6109 _ = options;
5708 _ = unused_fmt_string;6110 _ = unused_fmt_string;
5709 const shdr = ctx.shdr;6111 const shdr = ctx.shdr;
5710 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{6112 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{
5711 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,6113 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
5712 shdr.sh_addr, shdr.sh_addralign,6114 shdr.sh_addr, shdr.sh_addralign,
5713 shdr.sh_size,6115 shdr.sh_size, fmtShdrFlags(shdr.sh_flags),
5714 });6116 });
5715}6117}
57166118
6119pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(formatShdrFlags) {
6120 return .{ .data = sh_flags };
6121}
6122
6123fn formatShdrFlags(
6124 sh_flags: u64,
6125 comptime unused_fmt_string: []const u8,
6126 options: std.fmt.FormatOptions,
6127 writer: anytype,
6128) !void {
6129 _ = unused_fmt_string;
6130 _ = options;
6131 if (elf.SHF_WRITE & sh_flags != 0) {
6132 try writer.writeAll("W");
6133 }
6134 if (elf.SHF_ALLOC & sh_flags != 0) {
6135 try writer.writeAll("A");
6136 }
6137 if (elf.SHF_EXECINSTR & sh_flags != 0) {
6138 try writer.writeAll("X");
6139 }
6140 if (elf.SHF_MERGE & sh_flags != 0) {
6141 try writer.writeAll("M");
6142 }
6143 if (elf.SHF_STRINGS & sh_flags != 0) {
6144 try writer.writeAll("S");
6145 }
6146 if (elf.SHF_INFO_LINK & sh_flags != 0) {
6147 try writer.writeAll("I");
6148 }
6149 if (elf.SHF_LINK_ORDER & sh_flags != 0) {
6150 try writer.writeAll("L");
6151 }
6152 if (elf.SHF_EXCLUDE & sh_flags != 0) {
6153 try writer.writeAll("E");
6154 }
6155 if (elf.SHF_COMPRESSED & sh_flags != 0) {
6156 try writer.writeAll("C");
6157 }
6158 if (elf.SHF_GROUP & sh_flags != 0) {
6159 try writer.writeAll("G");
6160 }
6161 if (elf.SHF_OS_NONCONFORMING & sh_flags != 0) {
6162 try writer.writeAll("O");
6163 }
6164 if (elf.SHF_TLS & sh_flags != 0) {
6165 try writer.writeAll("T");
6166 }
6167 if (elf.SHF_X86_64_LARGE & sh_flags != 0) {
6168 try writer.writeAll("l");
6169 }
6170 if (elf.SHF_MIPS_ADDR & sh_flags != 0 or elf.SHF_ARM_PURECODE & sh_flags != 0) {
6171 try writer.writeAll("p");
6172 }
6173}
6174
5717const FormatPhdrCtx = struct {6175const FormatPhdrCtx = struct {
5718 elf_file: *Elf,6176 elf_file: *Elf,
5719 phdr: elf.Elf64_Phdr,6177 phdr: elf.Elf64_Phdr,
...@@ -5813,9 +6271,14 @@ fn fmtDumpState(...@@ -5813,9 +6271,14 @@ fn fmtDumpState(
5813 try writer.print("{}\n", .{self.got.fmt(self)});6271 try writer.print("{}\n", .{self.got.fmt(self)});
5814 try writer.print("{}\n", .{self.zig_got.fmt(self)});6272 try writer.print("{}\n", .{self.zig_got.fmt(self)});
58156273
5816 try writer.writeAll("Output shdrs\n");6274 try writer.writeAll("Output COMDAT groups\n");
6275 for (self.comdat_group_sections.items) |cg| {
6276 try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index });
6277 }
6278
6279 try writer.writeAll("\nOutput shdrs\n");
5817 for (self.shdrs.items, 0..) |shdr, shndx| {6280 for (self.shdrs.items, 0..) |shdr, shndx| {
5818 try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{6281 try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{
5819 shndx,6282 shndx,
5820 self.phdr_to_shdr_table.get(@intCast(shndx)),6283 self.phdr_to_shdr_table.get(@intCast(shndx)),
5821 self.fmtShdr(shdr),6284 self.fmtShdr(shdr),
...@@ -5823,7 +6286,7 @@ fn fmtDumpState(...@@ -5823,7 +6286,7 @@ fn fmtDumpState(
5823 }6286 }
5824 try writer.writeAll("\nOutput phdrs\n");6287 try writer.writeAll("\nOutput phdrs\n");
5825 for (self.phdrs.items, 0..) |phdr, phndx| {6288 for (self.phdrs.items, 0..) |phdr, phndx| {
5826 try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) });6289 try writer.print(" phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) });
5827 }6290 }
5828}6291}
58296292
...@@ -5882,16 +6345,12 @@ pub const ComdatGroup = struct {...@@ -5882,16 +6345,12 @@ pub const ComdatGroup = struct {
5882 pub const Index = u32;6345 pub const Index = u32;
5883};6346};
58846347
5885pub const SymtabSize = struct {6348pub const SymtabCtx = struct {
6349 ilocal: u32 = 0,
6350 iglobal: u32 = 0,
5886 nlocals: u32 = 0,6351 nlocals: u32 = 0,
5887 nglobals: u32 = 0,6352 nglobals: u32 = 0,
5888 strsize: u32 = 0,6353 strsize: u32 = 0,
5889
5890 fn add(ss: *SymtabSize, other: SymtabSize) void {
5891 ss.nlocals += other.nlocals;
5892 ss.nglobals += other.nglobals;
5893 ss.strsize += other.strsize;
5894 }
5895};6354};
58966355
5897pub const null_sym = elf.Elf64_Sym{6356pub const null_sym = elf.Elf64_Sym{
...@@ -5942,8 +6401,13 @@ const LastAtomAndFreeList = struct {...@@ -5942,8 +6401,13 @@ const LastAtomAndFreeList = struct {
5942 /// by 1 byte. It will then have -1 overcapacity.6401 /// by 1 byte. It will then have -1 overcapacity.
5943 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},6402 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
5944};6403};
6404const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndFreeList);
59456405
5946const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);6406const RelaSection = struct {
6407 shndx: u32,
6408 atom_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6409};
6410const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
59476411
5948pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;6412pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
5949pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;6413pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
...@@ -5976,6 +6440,7 @@ const Archive = @import("Elf/Archive.zig");...@@ -5976,6 +6440,7 @@ const Archive = @import("Elf/Archive.zig");
5976pub const Atom = @import("Elf/Atom.zig");6440pub const Atom = @import("Elf/Atom.zig");
5977const Cache = std.Build.Cache;6441const Cache = std.Build.Cache;
5978const Compilation = @import("../Compilation.zig");6442const Compilation = @import("../Compilation.zig");
6443const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
5979const CopyRelSection = synthetic_sections.CopyRelSection;6444const CopyRelSection = synthetic_sections.CopyRelSection;
5980const DynamicSection = synthetic_sections.DynamicSection;6445const DynamicSection = synthetic_sections.DynamicSection;
5981const DynsymSection = synthetic_sections.DynsymSection;6446const DynsymSection = synthetic_sections.DynsymSection;
src/link/Elf/Atom.zig+54-2
...@@ -60,6 +60,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {...@@ -60,6 +60,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
60 };60 };
61}61}
6262
63pub fn relocsShndx(self: Atom) ?u32 {
64 if (self.relocs_section_index == 0) return null;
65 return self.relocs_section_index;
66}
67
63pub fn outputShndx(self: Atom) ?u16 {68pub fn outputShndx(self: Atom) ?u16 {
64 if (self.output_section_index == 0) return null;69 if (self.output_section_index == 0) return null;
65 return self.output_section_index;70 return self.output_section_index;
...@@ -280,13 +285,60 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -280,13 +285,60 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
280}285}
281286
282pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {287pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
288 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
283 return switch (self.file(elf_file).?) {289 return switch (self.file(elf_file).?) {
284 .zig_object => |x| x.relocs.items[self.relocs_section_index].items,290 .zig_object => |x| x.relocs.items[shndx].items,
285 .object => |x| x.getRelocs(self.relocs_section_index),291 .object => |x| x.getRelocs(shndx),
286 else => unreachable,292 else => unreachable,
287 };293 };
288}294}
289295
296pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
297 relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
298
299 const file_ptr = self.file(elf_file).?;
300 for (self.relocs(elf_file)) |rel| {
301 const target_index = switch (file_ptr) {
302 .zig_object => |x| x.symbol(rel.r_sym()),
303 .object => |x| x.symbols.items[rel.r_sym()],
304 else => unreachable,
305 };
306 const target = elf_file.symbol(target_index);
307 const r_type = switch (rel.r_type()) {
308 Elf.R_X86_64_ZIG_GOT32,
309 Elf.R_X86_64_ZIG_GOTPCREL,
310 => unreachable, // Sanity check if we accidentally emitted those.
311 else => |r_type| r_type,
312 };
313 const r_offset = self.value + rel.r_offset;
314 var r_addend = rel.r_addend;
315 var r_sym: u32 = 0;
316 switch (target.type(elf_file)) {
317 elf.STT_SECTION => {
318 r_addend += @intCast(target.value);
319 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
320 },
321 else => {
322 r_sym = target.outputSymtabIndex(elf_file) orelse 0;
323 },
324 }
325
326 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
327 fmtRelocType(r_type),
328 r_offset,
329 r_sym,
330 target.name(elf_file),
331 r_addend,
332 });
333
334 out_relocs.appendAssumeCapacity(.{
335 .r_offset = r_offset,
336 .r_addend = r_addend,
337 .r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type,
338 });
339 }
340}
341
290pub fn fdes(self: Atom, elf_file: *Elf) []Fde {342pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
291 if (self.fde_start == self.fde_end) return &[0]Fde{};343 if (self.fde_start == self.fde_end) return &[0]Fde{};
292 const object = self.file(elf_file).?.object;344 const object = self.file(elf_file).?.object;
src/link/Elf/LinkerDefined.zig+1-1
...@@ -3,7 +3,7 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},...@@ -3,7 +3,7 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
3strtab: std.ArrayListUnmanaged(u8) = .{},3strtab: std.ArrayListUnmanaged(u8) = .{},
4symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},4symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
55
6output_symtab_size: Elf.SymtabSize = .{},6output_symtab_ctx: Elf.SymtabCtx = .{},
77
8pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {8pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
9 self.symtab.deinit(allocator);9 self.symtab.deinit(allocator);
src/link/Elf/Object.zig+65-5
...@@ -19,7 +19,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},...@@ -19,7 +19,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
19alive: bool = true,19alive: bool = true,
20num_dynrelocs: u32 = 0,20num_dynrelocs: u32 = 0,
2121
22output_symtab_size: Elf.SymtabSize = .{},22output_symtab_ctx: Elf.SymtabCtx = .{},
23output_ar_state: Archive.ArState = .{},23output_ar_state: Archive.ArState = .{},
2424
25pub fn isObject(path: []const u8) !bool {25pub fn isObject(path: []const u8) !bool {
...@@ -142,7 +142,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {...@@ -142,7 +142,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
142 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));142 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
143 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];143 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
144144
145 if (group_members[0] != 0x1) { // GRP_COMDAT145 if (group_members[0] != elf.GRP_COMDAT) {
146 // TODO convert into an error146 // TODO convert into an error
147 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});147 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
148 continue;148 continue;
...@@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf...@@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
211fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {211fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
212 const name = blk: {212 const name = blk: {
213 const name = self.getString(shdr.sh_name);213 const name = self.getString(shdr.sh_name);
214 if (elf_file.isRelocatable()) break :blk name;
214 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;215 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
215 const sh_name_prefixes: []const [:0]const u8 = &.{216 const sh_name_prefixes: []const [:0]const u8 = &.{
216 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",217 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
...@@ -237,7 +238,10 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem...@@ -237,7 +238,10 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
237 else => shdr.sh_type,238 else => shdr.sh_type,
238 };239 };
239 const flags = blk: {240 const flags = blk: {
240 const flags = shdr.sh_flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);241 var flags = shdr.sh_flags;
242 if (!elf_file.isRelocatable()) {
243 flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
244 }
241 break :blk switch (@"type") {245 break :blk switch (@"type") {
242 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,246 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
243 else => flags,247 else => flags,
...@@ -487,6 +491,25 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {...@@ -487,6 +491,25 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
487 }491 }
488}492}
489493
494pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
495 const first_global = self.first_global orelse return;
496 for (self.globals(), 0..) |index, i| {
497 const esym_index = @as(u32, @intCast(first_global + i));
498 const esym = self.symtab.items[esym_index];
499 if (esym.st_shndx != elf.SHN_UNDEF) continue;
500
501 const global = elf_file.symbol(index);
502 if (global.file(elf_file)) |file| {
503 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
504 }
505
506 global.value = 0;
507 global.atom_index = 0;
508 global.esym_index = esym_index;
509 global.file_index = self.index;
510 }
511}
512
490pub fn markLive(self: *Object, elf_file: *Elf) void {513pub fn markLive(self: *Object, elf_file: *Elf) void {
491 const first_global = self.first_global orelse return;514 const first_global = self.first_global orelse return;
492 for (self.globals(), 0..) |index, i| {515 for (self.globals(), 0..) |index, i| {
...@@ -654,6 +677,40 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {...@@ -654,6 +677,40 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
654 }677 }
655}678}
656679
680pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
681 for (self.atoms.items) |atom_index| {
682 const atom = elf_file.atom(atom_index) orelse continue;
683 if (!atom.flags.alive) continue;
684 const shndx = atom.relocsShndx() orelse continue;
685 const shdr = self.shdrs.items[shndx];
686 const out_shndx = try self.initOutputSection(elf_file, shdr);
687 const out_shdr = &elf_file.shdrs.items[out_shndx];
688 out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);
689 out_shdr.sh_entsize = @sizeOf(elf.Elf64_Rela);
690 out_shdr.sh_flags |= elf.SHF_INFO_LINK;
691 }
692}
693
694pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
695 for (self.atoms.items) |atom_index| {
696 const atom = elf_file.atom(atom_index) orelse continue;
697 if (!atom.flags.alive) continue;
698 const shndx = blk: {
699 const shndx = atom.relocsShndx() orelse continue;
700 const shdr = self.shdrs.items[shndx];
701 break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
702 };
703 const shdr = &elf_file.shdrs.items[shndx];
704 shdr.sh_info = atom.outputShndx().?;
705 shdr.sh_link = elf_file.symtab_section_index.?;
706
707 const gpa = elf_file.base.allocator;
708 const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
709 if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };
710 try gop.value_ptr.atom_list.append(gpa, atom_index);
711 }
712}
713
657pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {714pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
658 const gpa = elf_file.base.allocator;715 const gpa = elf_file.base.allocator;
659 const start = self.first_global orelse self.symtab.items.len;716 const start = self.first_global orelse self.symtab.items.len;
...@@ -685,11 +742,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {...@@ -685,11 +742,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {
685}742}
686743
687pub fn locals(self: Object) []const Symbol.Index {744pub fn locals(self: Object) []const Symbol.Index {
745 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
688 const end = self.first_global orelse self.symbols.items.len;746 const end = self.first_global orelse self.symbols.items.len;
689 return self.symbols.items[0..end];747 return self.symbols.items[0..end];
690}748}
691749
692pub fn globals(self: Object) []const Symbol.Index {750pub fn globals(self: Object) []const Symbol.Index {
751 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
693 const start = self.first_global orelse self.symbols.items.len;752 const start = self.first_global orelse self.symbols.items.len;
694 return self.symbols.items[start..];753 return self.symbols.items[start..];
695}754}
...@@ -881,16 +940,17 @@ fn formatComdatGroups(...@@ -881,16 +940,17 @@ fn formatComdatGroups(
881 _ = options;940 _ = options;
882 const object = ctx.object;941 const object = ctx.object;
883 const elf_file = ctx.elf_file;942 const elf_file = ctx.elf_file;
884 try writer.writeAll(" comdat groups\n");943 try writer.writeAll(" COMDAT groups\n");
885 for (object.comdat_groups.items) |cg_index| {944 for (object.comdat_groups.items) |cg_index| {
886 const cg = elf_file.comdatGroup(cg_index);945 const cg = elf_file.comdatGroup(cg_index);
887 const cg_owner = elf_file.comdatGroupOwner(cg.owner);946 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
888 if (cg_owner.file != object.index) continue;947 if (cg_owner.file != object.index) continue;
948 try writer.print(" COMDAT({d})\n", .{cg_index});
889 const cg_members = object.comdatGroupMembers(cg.shndx);949 const cg_members = object.comdatGroupMembers(cg.shndx);
890 for (cg_members) |shndx| {950 for (cg_members) |shndx| {
891 const atom_index = object.atoms.items[shndx];951 const atom_index = object.atoms.items[shndx];
892 const atom = elf_file.atom(atom_index) orelse continue;952 const atom = elf_file.atom(atom_index) orelse continue;
893 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });953 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
894 }954 }
895 }955 }
896}956}
src/link/Elf/SharedObject.zig+1-1
...@@ -21,7 +21,7 @@ verdef_sect_index: ?u16 = null,...@@ -21,7 +21,7 @@ verdef_sect_index: ?u16 = null,
21needed: bool,21needed: bool,
22alive: bool,22alive: bool,
2323
24output_symtab_size: Elf.SymtabSize = .{},24output_symtab_ctx: Elf.SymtabCtx = .{},
2525
26pub fn isSharedObject(path: []const u8) !bool {26pub fn isSharedObject(path: []const u8) !bool {
27 const file = try std.fs.cwd().openFile(path, .{});27 const file = try std.fs.cwd().openFile(path, .{});
src/link/Elf/Symbol.zig+22-5
...@@ -107,6 +107,24 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf...@@ -107,6 +107,24 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
107 return symbol.value;107 return symbol.value;
108}108}
109109
110pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
111 if (!symbol.flags.output_symtab) return null;
112 const file_ptr = symbol.file(elf_file).?;
113 const symtab_ctx = switch (file_ptr) {
114 inline else => |x| x.output_symtab_ctx,
115 };
116 const idx = symbol.extra(elf_file).?.symtab;
117 return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
118}
119
120pub fn setOutputSymtabIndex(symbol: *Symbol, index: u32, elf_file: *Elf) !void {
121 if (symbol.extra(elf_file)) |extras| {
122 var new_extras = extras;
123 new_extras.symtab = index;
124 symbol.setExtra(new_extras, elf_file);
125 } else try symbol.addExtra(.{ .symtab = index }, elf_file);
126}
127
110pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {128pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
111 if (!symbol.flags.has_got) return 0;129 if (!symbol.flags.has_got) return 0;
112 const extras = symbol.extra(elf_file).?;130 const extras = symbol.extra(elf_file).?;
...@@ -219,10 +237,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -219,10 +237,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
219 const st_shndx = blk: {237 const st_shndx = blk: {
220 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;238 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
221 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;239 if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
222 // TODO I think this is wrong and obsolete240 if (elf_file.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
223 if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;241 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
224 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
225 break :blk elf.SHN_ABS;
226 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;242 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
227 };243 };
228 const st_value = blk: {244 const st_value = blk: {
...@@ -231,7 +247,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {...@@ -231,7 +247,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
231 if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);247 if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
232 break :blk 0;248 break :blk 0;
233 }249 }
234 if (st_shndx == elf.SHN_ABS) break :blk symbol.value;250 if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.value;
235 const shdr = &elf_file.shdrs.items[st_shndx];251 const shdr = &elf_file.shdrs.items[st_shndx];
236 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)252 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
237 break :blk symbol.value - elf_file.tlsAddress();253 break :blk symbol.value - elf_file.tlsAddress();
...@@ -390,6 +406,7 @@ pub const Extra = struct {...@@ -390,6 +406,7 @@ pub const Extra = struct {
390 plt: u32 = 0,406 plt: u32 = 0,
391 plt_got: u32 = 0,407 plt_got: u32 = 0,
392 dynamic: u32 = 0,408 dynamic: u32 = 0,
409 symtab: u32 = 0,
393 copy_rel: u32 = 0,410 copy_rel: u32 = 0,
394 tlsgd: u32 = 0,411 tlsgd: u32 = 0,
395 gottp: u32 = 0,412 gottp: u32 = 0,
src/link/Elf/ZigObject.zig+15-107
...@@ -18,7 +18,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},...@@ -18,7 +18,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
1818
19num_dynrelocs: u32 = 0,19num_dynrelocs: u32 = 0,
2020
21output_symtab_size: Elf.SymtabSize = .{},21output_symtab_ctx: Elf.SymtabCtx = .{},
22output_ar_state: Archive.ArState = .{},22output_ar_state: Archive.ArState = .{},
2323
24dwarf: ?Dwarf = null,24dwarf: ?Dwarf = null,
...@@ -75,6 +75,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {...@@ -75,6 +75,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
75 const gpa = elf_file.base.allocator;75 const gpa = elf_file.base.allocator;
7676
77 try self.atoms.append(gpa, 0); // null input section77 try self.atoms.append(gpa, 0); // null input section
78 try self.relocs.append(gpa, .{}); // null relocs section
78 try self.strtab.buffer.append(gpa, 0);79 try self.strtab.buffer.append(gpa, 0);
7980
80 const name_off = try self.strtab.insert(gpa, self.path);81 const name_off = try self.strtab.insert(gpa, self.path);
...@@ -287,22 +288,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {...@@ -287,22 +288,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
287 return symbol_index;288 return symbol_index;
288}289}
289290
290pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void {
291 assert(elf_file.isRelocatable());
292 const gpa = elf_file.base.allocator;
293 const symbol_index = try elf_file.addSymbol();
294 try self.local_symbols.append(gpa, symbol_index);
295 const symbol_ptr = elf_file.symbol(symbol_index);
296 symbol_ptr.file_index = self.index;
297 symbol_ptr.output_section_index = shndx;
298
299 const esym_index = try self.addLocalEsym(gpa);
300 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
301 esym.st_info = elf.STT_SECTION;
302 esym.st_shndx = shndx;
303 symbol_ptr.esym_index = esym_index;
304}
305
306/// TODO actually create fake input shdrs and return that instead.291/// TODO actually create fake input shdrs and return that instead.
307pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {292pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
308 _ = self;293 _ = self;
...@@ -393,8 +378,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {...@@ -393,8 +378,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
393378
394 const global = elf_file.symbol(index);379 const global = elf_file.symbol(index);
395 if (global.file(elf_file)) |file| {380 if (global.file(elf_file)) |file| {
396 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or381 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
397 file.index() <= self.index) continue;
398 }382 }
399383
400 global.value = 0;384 global.value = 0;
...@@ -549,94 +533,18 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {...@@ -549,94 +533,18 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
549 try writer.writeAll(contents);533 try writer.writeAll(contents);
550}534}
551535
552pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {536pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
553 _ = self;537 for (self.atoms.items) |atom_index| {
554538 const atom = elf_file.atom(atom_index) orelse continue;
555 for (&[_]?u16{539 if (!atom.flags.alive) continue;
556 elf_file.zig_text_rela_section_index,540 _ = atom.relocsShndx() orelse continue;
557 elf_file.zig_data_rel_ro_rela_section_index,541 const out_shndx = atom.outputShndx().?;
558 elf_file.zig_data_rela_section_index,542 const out_shdr = elf_file.shdrs.items[out_shndx];
559 }) |maybe_index| {543 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
560 const index = maybe_index orelse continue;544
561 const shdr = &elf_file.shdrs.items[index];545 const gpa = elf_file.base.allocator;
562 const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;546 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
563 const last_atom_index = meta.last_atom_index;547 try sec.atom_list.append(gpa, atom_index);
564
565 var atom = elf_file.atom(last_atom_index) orelse continue;
566 while (true) {
567 const relocs = atom.relocs(elf_file);
568 shdr.sh_size += relocs.len * shdr.sh_entsize;
569 if (elf_file.atom(atom.prev_index)) |prev| {
570 atom = prev;
571 } else break;
572 }
573 }
574
575 for (&[_]?u16{
576 elf_file.zig_text_rela_section_index,
577 elf_file.zig_data_rel_ro_rela_section_index,
578 elf_file.zig_data_rela_section_index,
579 }) |maybe_index| {
580 const index = maybe_index orelse continue;
581 const shdr = &elf_file.shdrs.items[index];
582 if (shdr.sh_size == 0) shdr.sh_offset = 0;
583 }
584}
585
586pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
587 const gpa = elf_file.base.allocator;
588
589 for (&[_]?u16{
590 elf_file.zig_text_rela_section_index,
591 elf_file.zig_data_rel_ro_rela_section_index,
592 elf_file.zig_data_rela_section_index,
593 }) |maybe_index| {
594 const index = maybe_index orelse continue;
595 const shdr = elf_file.shdrs.items[index];
596 const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
597 const last_atom_index = meta.last_atom_index;
598
599 var atom = elf_file.atom(last_atom_index) orelse continue;
600
601 var relocs = std.ArrayList(elf.Elf64_Rela).init(gpa);
602 defer relocs.deinit();
603 try relocs.ensureTotalCapacityPrecise(@intCast(@divExact(shdr.sh_size, shdr.sh_entsize)));
604
605 while (true) {
606 for (atom.relocs(elf_file)) |rel| {
607 const target = elf_file.symbol(self.symbol(rel.r_sym()));
608 const r_offset = atom.value + rel.r_offset;
609 const r_sym: u32 = if (target.flags.global)
610 (target.esym_index & symbol_mask) + @as(u32, @intCast(self.local_esyms.slice().len))
611 else
612 target.esym_index;
613 const r_type = switch (rel.r_type()) {
614 Elf.R_X86_64_ZIG_GOT32,
615 Elf.R_X86_64_ZIG_GOTPCREL,
616 => unreachable, // Sanity check if we accidentally emitted those.
617 else => |r_type| r_type,
618 };
619 relocs.appendAssumeCapacity(.{
620 .r_offset = r_offset,
621 .r_addend = rel.r_addend,
622 .r_info = (@as(u64, @intCast(r_sym + 1)) << 32) | r_type,
623 });
624 }
625 if (elf_file.atom(atom.prev_index)) |prev| {
626 atom = prev;
627 } else break;
628 }
629
630 const SortRelocs = struct {
631 pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
632 _ = ctx;
633 return lhs.r_offset < rhs.r_offset;
634 }
635 };
636
637 mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan);
638
639 try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
640 }548 }
641}549}
642550
src/link/Elf/eh_frame.zig+110-1
...@@ -268,7 +268,11 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {...@@ -268,7 +268,11 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
268 }268 }
269 }269 }
270270
271 return offset + 4; // NULL terminator271 if (!elf_file.isRelocatable()) {
272 offset += 4; // NULL terminator
273 }
274
275 return offset;
272}276}
273277
274pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {278pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
...@@ -282,6 +286,22 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {...@@ -282,6 +286,22 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
282 return eh_frame_hdr_header_size + count * 8;286 return eh_frame_hdr_header_size + count * 8;
283}287}
284288
289pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
290 var count: usize = 0;
291 for (elf_file.objects.items) |index| {
292 const object = elf_file.file(index).?.object;
293 for (object.cies.items) |cie| {
294 if (!cie.alive) continue;
295 count += cie.relocs(elf_file).len;
296 }
297 for (object.fdes.items) |fde| {
298 if (!fde.alive) continue;
299 count += fde.relocs(elf_file).len;
300 }
301 }
302 return count;
303}
304
285fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {305fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {
286 const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow;306 const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow;
287 const P = @as(i64, @intCast(rec.address(elf_file) + offset));307 const P = @as(i64, @intCast(rec.address(elf_file) + offset));
...@@ -357,6 +377,95 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {...@@ -357,6 +377,95 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
357 try writer.writeInt(u32, 0, .little);377 try writer.writeInt(u32, 0, .little);
358}378}
359379
380pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
381 const gpa = elf_file.base.allocator;
382
383 for (elf_file.objects.items) |index| {
384 const object = elf_file.file(index).?.object;
385
386 for (object.cies.items) |cie| {
387 if (!cie.alive) continue;
388 try writer.writeAll(cie.data(elf_file));
389 }
390 }
391
392 for (elf_file.objects.items) |index| {
393 const object = elf_file.file(index).?.object;
394
395 for (object.fdes.items) |fde| {
396 if (!fde.alive) continue;
397
398 const contents = try gpa.dupe(u8, fde.data(elf_file));
399 defer gpa.free(contents);
400
401 std.mem.writeInt(
402 i32,
403 contents[4..8],
404 @truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
405 .little,
406 );
407
408 try writer.writeAll(contents);
409 }
410 }
411}
412
413fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
414 const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset;
415 const r_type = rel.r_type();
416 var r_addend = rel.r_addend;
417 var r_sym: u32 = 0;
418 switch (sym.type(elf_file)) {
419 elf.STT_SECTION => {
420 r_addend += @intCast(sym.value);
421 r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
422 },
423 else => {
424 r_sym = sym.outputSymtabIndex(elf_file) orelse 0;
425 },
426 }
427
428 relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
429 Atom.fmtRelocType(r_type),
430 r_offset,
431 r_sym,
432 sym.name(elf_file),
433 r_addend,
434 });
435
436 return .{
437 .r_offset = r_offset,
438 .r_addend = r_addend,
439 .r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type,
440 };
441}
442
443pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
444 relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr});
445
446 for (elf_file.objects.items) |index| {
447 const object = elf_file.file(index).?.object;
448
449 for (object.cies.items) |cie| {
450 if (!cie.alive) continue;
451 for (cie.relocs(elf_file)) |rel| {
452 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
453 const out_rel = emitReloc(elf_file, cie, sym, rel);
454 try writer.writeStruct(out_rel);
455 }
456 }
457
458 for (object.fdes.items) |fde| {
459 if (!fde.alive) continue;
460 for (fde.relocs(elf_file)) |rel| {
461 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
462 const out_rel = emitReloc(elf_file, fde, sym, rel);
463 try writer.writeStruct(out_rel);
464 }
465 }
466 }
467}
468
360pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {469pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
361 try writer.writeByte(1); // version470 try writer.writeByte(1); // version
362 try writer.writeByte(EH_PE.pcrel | EH_PE.sdata4);471 try writer.writeByte(EH_PE.pcrel | EH_PE.sdata4);
src/link/Elf/file.zig+19-28
...@@ -127,22 +127,22 @@ pub const File = union(enum) {...@@ -127,22 +127,22 @@ pub const File = union(enum) {
127 };127 };
128 }128 }
129129
130 pub fn updateSymtabSize(file: File, elf_file: *Elf) void {130 pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
131 const output_symtab_size = switch (file) {131 const output_symtab_ctx = switch (file) {
132 inline else => |x| &x.output_symtab_size,132 inline else => |x| &x.output_symtab_ctx,
133 };133 };
134 for (file.locals()) |local_index| {134 for (file.locals()) |local_index| {
135 const local = elf_file.symbol(local_index);135 const local = elf_file.symbol(local_index);
136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137 const esym = local.elfSym(elf_file);137 const esym = local.elfSym(elf_file);
138 switch (esym.st_type()) {138 switch (esym.st_type()) {
139 elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,139 elf.STT_SECTION, elf.STT_NOTYPE => continue,
140 elf.STT_NOTYPE => continue,
141 else => {},140 else => {},
142 }141 }
143 local.flags.output_symtab = true;142 local.flags.output_symtab = true;
144 output_symtab_size.nlocals += 1;143 try local.setOutputSymtabIndex(output_symtab_ctx.nlocals, elf_file);
145 output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;144 output_symtab_ctx.nlocals += 1;
145 output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
146 }146 }
147147
148 for (file.globals()) |global_index| {148 for (file.globals()) |global_index| {
...@@ -152,47 +152,38 @@ pub const File = union(enum) {...@@ -152,47 +152,38 @@ pub const File = union(enum) {
152 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;152 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
153 global.flags.output_symtab = true;153 global.flags.output_symtab = true;
154 if (global.isLocal(elf_file)) {154 if (global.isLocal(elf_file)) {
155 output_symtab_size.nlocals += 1;155 try global.setOutputSymtabIndex(output_symtab_ctx.nlocals, elf_file);
156 output_symtab_ctx.nlocals += 1;
156 } else {157 } else {
157 output_symtab_size.nglobals += 1;158 try global.setOutputSymtabIndex(output_symtab_ctx.nglobals, elf_file);
159 output_symtab_ctx.nglobals += 1;
158 }160 }
159 output_symtab_size.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;161 output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
160 }162 }
161 }163 }
162164
163 pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {165 pub fn writeSymtab(file: File, elf_file: *Elf) void {
164 var ilocal: usize = ctx.ilocal;
165 for (file.locals()) |local_index| {166 for (file.locals()) |local_index| {
166 const local = elf_file.symbol(local_index);167 const local = elf_file.symbol(local_index);
167 if (!local.flags.output_symtab) continue;168 const idx = local.outputSymtabIndex(elf_file) orelse continue;
168 const out_sym = &elf_file.symtab.items[ilocal];169 const out_sym = &elf_file.symtab.items[idx];
169 out_sym.st_name = @intCast(elf_file.strtab.items.len);170 out_sym.st_name = @intCast(elf_file.strtab.items.len);
170 elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));171 elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
171 elf_file.strtab.appendAssumeCapacity(0);172 elf_file.strtab.appendAssumeCapacity(0);
172 local.setOutputSym(elf_file, out_sym);173 local.setOutputSym(elf_file, out_sym);
173 ilocal += 1;
174 }174 }
175175
176 var iglobal: usize = ctx.iglobal;
177 for (file.globals()) |global_index| {176 for (file.globals()) |global_index| {
178 const global = elf_file.symbol(global_index);177 const global = elf_file.symbol(global_index);
179 const file_ptr = global.file(elf_file) orelse continue;178 const file_ptr = global.file(elf_file) orelse continue;
180 if (file_ptr.index() != file.index()) continue;179 if (file_ptr.index() != file.index()) continue;
181 if (!global.flags.output_symtab) continue;180 const idx = global.outputSymtabIndex(elf_file) orelse continue;
182 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));181 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
183 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));182 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
184 elf_file.strtab.appendAssumeCapacity(0);183 elf_file.strtab.appendAssumeCapacity(0);
185 if (global.isLocal(elf_file)) {184 const out_sym = &elf_file.symtab.items[idx];
186 const out_sym = &elf_file.symtab.items[ilocal];185 out_sym.st_name = st_name;
187 out_sym.st_name = st_name;186 global.setOutputSym(elf_file, out_sym);
188 global.setOutputSym(elf_file, out_sym);
189 ilocal += 1;
190 } else {
191 const out_sym = &elf_file.symtab.items[iglobal];
192 out_sym.st_name = st_name;
193 global.setOutputSym(elf_file, out_sym);
194 iglobal += 1;
195 }
196 }187 }
197 }188 }
198189
src/link/Elf/synthetic_sections.zig+68-20
...@@ -222,7 +222,7 @@ pub const DynamicSection = struct {...@@ -222,7 +222,7 @@ pub const DynamicSection = struct {
222222
223pub const ZigGotSection = struct {223pub const ZigGotSection = struct {
224 entries: std.ArrayListUnmanaged(Symbol.Index) = .{},224 entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
225 output_symtab_size: Elf.SymtabSize = .{},225 output_symtab_ctx: Elf.SymtabCtx = .{},
226 flags: Flags = .{},226 flags: Flags = .{},
227227
228 const Flags = packed struct {228 const Flags = packed struct {
...@@ -359,15 +359,15 @@ pub const ZigGotSection = struct {...@@ -359,15 +359,15 @@ pub const ZigGotSection = struct {
359 }359 }
360360
361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {361 pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
362 zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));362 zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
363 for (zig_got.entries.items) |entry| {363 for (zig_got.entries.items) |entry| {
364 const name = elf_file.symbol(entry).name(elf_file);364 const name = elf_file.symbol(entry).name(elf_file);
365 zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;365 zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
366 }366 }
367 }367 }
368368
369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
370 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {370 for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
371 const symbol = elf_file.symbol(entry);371 const symbol = elf_file.symbol(entry);
372 const symbol_name = symbol.name(elf_file);372 const symbol_name = symbol.name(elf_file);
373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
...@@ -420,7 +420,7 @@ pub const ZigGotSection = struct {...@@ -420,7 +420,7 @@ pub const ZigGotSection = struct {
420420
421pub const GotSection = struct {421pub const GotSection = struct {
422 entries: std.ArrayListUnmanaged(Entry) = .{},422 entries: std.ArrayListUnmanaged(Entry) = .{},
423 output_symtab_size: Elf.SymtabSize = .{},423 output_symtab_ctx: Elf.SymtabCtx = .{},
424 tlsld_index: ?u32 = null,424 tlsld_index: ?u32 = null,
425 flags: Flags = .{},425 flags: Flags = .{},
426426
...@@ -760,18 +760,18 @@ pub const GotSection = struct {...@@ -760,18 +760,18 @@ pub const GotSection = struct {
760 }760 }
761761
762 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {762 pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
763 got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));763 got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len));
764 for (got.entries.items) |entry| {764 for (got.entries.items) |entry| {
765 const symbol_name = switch (entry.tag) {765 const symbol_name = switch (entry.tag) {
766 .tlsld => "",766 .tlsld => "",
767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
768 };768 };
769 got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;769 got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
770 }770 }
771 }771 }
772772
773 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {773 pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {
774 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {774 for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {
775 const symbol = switch (entry.tag) {775 const symbol = switch (entry.tag) {
776 .tlsld => null,776 .tlsld => null,
777 inline else => elf_file.symbol(entry.symbol_index),777 inline else => elf_file.symbol(entry.symbol_index),
...@@ -831,7 +831,7 @@ pub const GotSection = struct {...@@ -831,7 +831,7 @@ pub const GotSection = struct {
831831
832pub const PltSection = struct {832pub const PltSection = struct {
833 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},833 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
834 output_symtab_size: Elf.SymtabSize = .{},834 output_symtab_ctx: Elf.SymtabCtx = .{},
835835
836 pub const preamble_size = 32;836 pub const preamble_size = 32;
837837
...@@ -909,15 +909,15 @@ pub const PltSection = struct {...@@ -909,15 +909,15 @@ pub const PltSection = struct {
909 }909 }
910910
911 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {911 pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
912 plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));912 plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len));
913 for (plt.symbols.items) |sym_index| {913 for (plt.symbols.items) |sym_index| {
914 const name = elf_file.symbol(sym_index).name(elf_file);914 const name = elf_file.symbol(sym_index).name(elf_file);
915 plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;915 plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
916 }916 }
917 }917 }
918918
919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {
920 var ilocal = ctx.ilocal;920 var ilocal = plt.output_symtab_ctx.ilocal;
921 for (plt.symbols.items) |sym_index| {921 for (plt.symbols.items) |sym_index| {
922 const sym = elf_file.symbol(sym_index);922 const sym = elf_file.symbol(sym_index);
923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
...@@ -968,7 +968,7 @@ pub const GotPltSection = struct {...@@ -968,7 +968,7 @@ pub const GotPltSection = struct {
968968
969pub const PltGotSection = struct {969pub const PltGotSection = struct {
970 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},970 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
971 output_symtab_size: Elf.SymtabSize = .{},971 output_symtab_ctx: Elf.SymtabCtx = .{},
972972
973 pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {973 pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
974 plt_got.symbols.deinit(allocator);974 plt_got.symbols.deinit(allocator);
...@@ -1008,15 +1008,15 @@ pub const PltGotSection = struct {...@@ -1008,15 +1008,15 @@ pub const PltGotSection = struct {
1008 }1008 }
10091009
1010 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {1010 pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
1011 plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));1011 plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
1012 for (plt_got.symbols.items) |sym_index| {1012 for (plt_got.symbols.items) |sym_index| {
1013 const name = elf_file.symbol(sym_index).name(elf_file);1013 const name = elf_file.symbol(sym_index).name(elf_file);
1014 plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;1014 plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
1015 }1015 }
1016 }1016 }
10171017
1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {
1019 var ilocal = ctx.ilocal;1019 var ilocal = plt_got.output_symtab_ctx.ilocal;
1020 for (plt_got.symbols.items) |sym_index| {1020 for (plt_got.symbols.items) |sym_index| {
1021 const sym = elf_file.symbol(sym_index);1021 const sym = elf_file.symbol(sym_index);
1022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));1022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
...@@ -1499,6 +1499,54 @@ pub const VerneedSection = struct {...@@ -1499,6 +1499,54 @@ pub const VerneedSection = struct {
1499 }1499 }
1500};1500};
15011501
1502pub const ComdatGroupSection = struct {
1503 shndx: u32,
1504 cg_index: u32,
1505
1506 fn file(cgs: ComdatGroupSection, elf_file: *Elf) ?File {
1507 const cg = elf_file.comdatGroup(cgs.cg_index);
1508 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
1509 return elf_file.file(cg_owner.file);
1510 }
1511
1512 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
1513 const cg = elf_file.comdatGroup(cgs.cg_index);
1514 const object = cgs.file(elf_file).?.object;
1515 const shdr = object.shdrs.items[cg.shndx];
1516 return object.symbols.items[shdr.sh_info];
1517 }
1518
1519 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
1520 const cg = elf_file.comdatGroup(cgs.cg_index);
1521 const object = cgs.file(elf_file).?.object;
1522 const members = object.comdatGroupMembers(cg.shndx);
1523 return (members.len + 1) * @sizeOf(u32);
1524 }
1525
1526 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
1527 const cg = elf_file.comdatGroup(cgs.cg_index);
1528 const object = cgs.file(elf_file).?.object;
1529 const members = object.comdatGroupMembers(cg.shndx);
1530 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
1531 for (members) |shndx| {
1532 const shdr = object.shdrs.items[shndx];
1533 switch (shdr.sh_type) {
1534 elf.SHT_RELA => {
1535 const atom_index = object.atoms.items[shdr.sh_info];
1536 const atom = elf_file.atom(atom_index).?;
1537 const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;
1538 try writer.writeInt(u32, rela.shndx, .little);
1539 },
1540 else => {
1541 const atom_index = object.atoms.items[shndx];
1542 const atom = elf_file.atom(atom_index).?;
1543 try writer.writeInt(u32, atom.outputShndx().?, .little);
1544 },
1545 }
1546 }
1547 }
1548};
1549
1502fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {1550fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
1503 const entry_size = elf_file.archPtrWidthBytes();1551 const entry_size = elf_file.archPtrWidthBytes();
1504 const endian = elf_file.base.options.target.cpu.arch.endian();1552 const endian = elf_file.base.options.target.cpu.arch.endian();
test/link/elf.zig+135-1
...@@ -21,6 +21,11 @@ pub fn build(b: *Build) void {...@@ -21,6 +21,11 @@ pub fn build(b: *Build) void {
21 .abi = .gnu,21 .abi = .gnu,
22 };22 };
2323
24 // Exercise linker in -r mode
25 elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = musl_target }));
26 elf_step.dependOn(testEmitRelocatable(b, .{ .target = musl_target }));
27 elf_step.dependOn(testRelocatableEhFrame(b, .{ .target = musl_target }));
28
24 // Exercise linker in ar mode29 // Exercise linker in ar mode
25 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));30 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
2631
...@@ -629,6 +634,53 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {...@@ -629,6 +634,53 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
629 return test_step;634 return test_step;
630}635}
631636
637fn testEmitRelocatable(b: *Build, opts: Options) *Step {
638 const test_step = addTestStep(b, "emit-relocatable", opts);
639
640 const obj1 = addObject(b, "obj1", opts);
641 addZigSourceBytes(obj1,
642 \\const std = @import("std");
643 \\extern var bar: i32;
644 \\export fn foo() i32 {
645 \\ return bar;
646 \\}
647 \\export fn printFoo() void {
648 \\ std.debug.print("foo={d}\n", .{foo()});
649 \\}
650 );
651 addCSourceBytes(obj1,
652 \\#include <stdio.h>
653 \\int bar = 42;
654 \\void printBar() {
655 \\ fprintf(stderr, "bar=%d\n", bar);
656 \\}
657 , &.{});
658 obj1.linkLibC();
659
660 const exe = addExecutable(b, "test", opts);
661 addZigSourceBytes(exe,
662 \\const std = @import("std");
663 \\extern fn printFoo() void;
664 \\extern fn printBar() void;
665 \\pub fn main() void {
666 \\ printFoo();
667 \\ printBar();
668 \\}
669 );
670 exe.addObject(obj1);
671 exe.linkLibC();
672
673 const run = addRunArtifact(exe);
674 run.expectStdErrEqual(
675 \\foo=42
676 \\bar=42
677 \\
678 );
679 test_step.dependOn(&run.step);
680
681 return test_step;
682}
683
632fn testEmitStaticLib(b: *Build, opts: Options) *Step {684fn testEmitStaticLib(b: *Build, opts: Options) *Step {
633 const test_step = addTestStep(b, "emit-static-lib", opts);685 const test_step = addTestStep(b, "emit-static-lib", opts);
634686
...@@ -951,7 +1003,6 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {...@@ -951,7 +1003,6 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
951 const obj = addObject(b, "obj", .{1003 const obj = addObject(b, "obj", .{
952 .target = opts.target,1004 .target = opts.target,
953 .use_llvm = true,1005 .use_llvm = true,
954 .use_lld = true,
955 });1006 });
956 addCSourceBytes(obj,1007 addCSourceBytes(obj,
957 \\int live_var1 = 1;1008 \\int live_var1 = 1;
...@@ -2089,6 +2140,89 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {...@@ -2089,6 +2140,89 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
2089 return test_step;2140 return test_step;
2090}2141}
20912142
2143fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2144 const test_step = addTestStep(b, "relocatable-eh-frame", opts);
2145
2146 {
2147 const obj = addObject(b, "obj1", opts);
2148 addCppSourceBytes(obj,
2149 \\#include <stdexcept>
2150 \\int try_me() {
2151 \\ throw std::runtime_error("Oh no!");
2152 \\}
2153 , &.{});
2154 addCppSourceBytes(obj,
2155 \\extern int try_me();
2156 \\int try_again() {
2157 \\ return try_me();
2158 \\}
2159 , &.{});
2160 obj.linkLibCpp();
2161
2162 const exe = addExecutable(b, "test1", opts);
2163 addCppSourceBytes(exe,
2164 \\#include <iostream>
2165 \\#include <stdexcept>
2166 \\extern int try_again();
2167 \\int main() {
2168 \\ try {
2169 \\ try_again();
2170 \\ } catch (const std::exception &e) {
2171 \\ std::cout << "exception=" << e.what();
2172 \\ }
2173 \\ return 0;
2174 \\}
2175 , &.{});
2176 exe.addObject(obj);
2177 exe.linkLibCpp();
2178
2179 const run = addRunArtifact(exe);
2180 run.expectStdOutEqual("exception=Oh no!");
2181 test_step.dependOn(&run.step);
2182 }
2183
2184 {
2185 // Let's make the object file COMDAT group heavy!
2186 const obj = addObject(b, "obj2", opts);
2187 addCppSourceBytes(obj,
2188 \\#include <stdexcept>
2189 \\int try_me() {
2190 \\ throw std::runtime_error("Oh no!");
2191 \\}
2192 , &.{});
2193 addCppSourceBytes(obj,
2194 \\extern int try_me();
2195 \\int try_again() {
2196 \\ return try_me();
2197 \\}
2198 , &.{});
2199 addCppSourceBytes(obj,
2200 \\#include <iostream>
2201 \\#include <stdexcept>
2202 \\extern int try_again();
2203 \\int main() {
2204 \\ try {
2205 \\ try_again();
2206 \\ } catch (const std::exception &e) {
2207 \\ std::cout << "exception=" << e.what();
2208 \\ }
2209 \\ return 0;
2210 \\}
2211 , &.{});
2212 obj.linkLibCpp();
2213
2214 const exe = addExecutable(b, "test2", opts);
2215 exe.addObject(obj);
2216 exe.linkLibCpp();
2217
2218 const run = addRunArtifact(exe);
2219 run.expectStdOutEqual("exception=Oh no!");
2220 test_step.dependOn(&run.step);
2221 }
2222
2223 return test_step;
2224}
2225
2092fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {2226fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2093 const test_step = addTestStep(b, "shared-abs-symbol", opts);2227 const test_step = addTestStep(b, "shared-abs-symbol", opts);
20942228