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) {
16641664 }
16651665};
16661666
1667pub const GRP_COMDAT = 1;
1668
16671669/// Section data should be writable during execution.
16681670pub const SHF_WRITE = 0x1;
16691671
src/link/Elf.zig+966-501
......@@ -18,12 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
1818/// Same order as in the file.
1919shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
2020/// 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) = .{},
2222/// File offset into the shdr table.
2323shdr_table_offset: ?u64 = null,
2424/// Table of lists of atoms per output section.
2525/// 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
2829/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
2930/// Same order as in the file.
......@@ -101,15 +102,15 @@ copy_rel: CopyRelSection = .{},
101102rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
102103/// .got.zig section
103104zig_got: ZigGotSection = .{},
105/// SHT_GROUP sections
106/// Applies only to a relocatable.
107comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
104108
105109/// Tracked section headers with incremental updates to Zig object.
106110/// .rela.* sections are only used when emitting a relocatable object file.
107111zig_text_section_index: ?u16 = null,
108zig_text_rela_section_index: ?u16 = null,
109112zig_data_rel_ro_section_index: ?u16 = null,
110zig_data_rel_ro_rela_section_index: ?u16 = null,
111113zig_data_section_index: ?u16 = null,
112zig_data_rela_section_index: ?u16 = null,
113114zig_bss_section_index: ?u16 = null,
114115zig_got_section_index: ?u16 = null,
115116
......@@ -124,6 +125,7 @@ dynamic_section_index: ?u16 = null,
124125dynstrtab_section_index: ?u16 = null,
125126dynsymtab_section_index: ?u16 = null,
126127eh_frame_section_index: ?u16 = null,
128eh_frame_rela_section_index: ?u16 = null,
127129eh_frame_hdr_section_index: ?u16 = null,
128130hash_section_index: ?u16 = null,
129131gnu_hash_section_index: ?u16 = null,
......@@ -216,10 +218,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
216218 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
217219 });
218220 }
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 }
223221 }
224222 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
225223
......@@ -361,6 +359,10 @@ pub fn deinit(self: *Elf) void {
361359 list.deinit(gpa);
362360 }
363361 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);
364366 self.shstrtab.deinit(gpa);
365367 self.symtab.deinit(gpa);
366368 self.strtab.deinit(gpa);
......@@ -395,6 +397,7 @@ pub fn deinit(self: *Elf) void {
395397 self.rela_dyn.deinit(gpa);
396398 self.rela_plt.deinit(gpa);
397399 self.zig_got.deinit(gpa);
400 self.comdat_group_sections.deinit(gpa);
398401}
399402
400403pub 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 {
601604 const shdr = &self.shdrs.items[self.zig_text_section_index.?];
602605 fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
603606 if (self.isRelocatable()) {
604 try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
605 self.zig_text_rela_section_index = try self.addRelaShdr(
606 ".rela.text.zig",
607 self.zig_text_section_index.?,
608 );
607 const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?);
608 try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{
609 .shndx = rela_shndx,
610 });
609611 } else {
610612 try self.phdr_to_shdr_table.putNoClobber(
611613 gpa,
......@@ -613,6 +615,7 @@ pub fn initMetadata(self: *Elf) !void {
613615 self.phdr_zig_load_re_index.?,
614616 );
615617 }
618 try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{});
616619 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
617620 }
618621
......@@ -642,17 +645,19 @@ pub fn initMetadata(self: *Elf) !void {
642645 .name = ".data.rel.ro.zig",
643646 .type = elf.SHT_PROGBITS,
644647 .addralign = 1,
645 .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro
648 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
646649 .offset = std.math.maxInt(u64),
647650 });
648651 const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
649652 fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
650653 if (self.isRelocatable()) {
651 try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
652 self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
654 const rela_shndx = try self.addRelaShdr(
653655 ".rela.data.rel.ro.zig",
654656 self.zig_data_rel_ro_section_index.?,
655657 );
658 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{
659 .shndx = rela_shndx,
660 });
656661 } else {
657662 try self.phdr_to_shdr_table.putNoClobber(
658663 gpa,
......@@ -660,6 +665,7 @@ pub fn initMetadata(self: *Elf) !void {
660665 self.phdr_zig_load_ro_index.?,
661666 );
662667 }
668 try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
663669 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
664670 }
665671
......@@ -674,11 +680,13 @@ pub fn initMetadata(self: *Elf) !void {
674680 const shdr = &self.shdrs.items[self.zig_data_section_index.?];
675681 fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
676682 if (self.isRelocatable()) {
677 try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
678 self.zig_data_rela_section_index = try self.addRelaShdr(
683 const rela_shndx = try self.addRelaShdr(
679684 ".rela.data.zig",
680685 self.zig_data_section_index.?,
681686 );
687 try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{
688 .shndx = rela_shndx,
689 });
682690 } else {
683691 try self.phdr_to_shdr_table.putNoClobber(
684692 gpa,
......@@ -686,6 +694,7 @@ pub fn initMetadata(self: *Elf) !void {
686694 self.phdr_zig_load_rw_index.?,
687695 );
688696 }
697 try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{});
689698 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
690699 }
691700
......@@ -704,9 +713,9 @@ pub fn initMetadata(self: *Elf) !void {
704713 shdr.sh_size = phdr.p_memsz;
705714 try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
706715 } else {
707 try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
708716 shdr.sh_size = 1024;
709717 }
718 try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
710719 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
711720 }
712721
......@@ -728,6 +737,7 @@ pub fn initMetadata(self: *Elf) !void {
728737 shdr.sh_offset = off;
729738 shdr.sh_size = size;
730739 zig_object.debug_strtab_dirty = true;
740 try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
731741 }
732742
733743 if (self.debug_info_section_index == null) {
......@@ -743,6 +753,7 @@ pub fn initMetadata(self: *Elf) !void {
743753 shdr.sh_offset = off;
744754 shdr.sh_size = size;
745755 zig_object.debug_info_header_dirty = true;
756 try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
746757 }
747758
748759 if (self.debug_abbrev_section_index == null) {
......@@ -758,6 +769,7 @@ pub fn initMetadata(self: *Elf) !void {
758769 shdr.sh_offset = off;
759770 shdr.sh_size = size;
760771 zig_object.debug_abbrev_section_dirty = true;
772 try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
761773 }
762774
763775 if (self.debug_aranges_section_index == null) {
......@@ -773,6 +785,7 @@ pub fn initMetadata(self: *Elf) !void {
773785 shdr.sh_offset = off;
774786 shdr.sh_size = size;
775787 zig_object.debug_aranges_section_dirty = true;
788 try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
776789 }
777790
778791 if (self.debug_line_section_index == null) {
......@@ -788,8 +801,17 @@ pub fn initMetadata(self: *Elf) !void {
788801 shdr.sh_offset = off;
789802 shdr.sh_size = size;
790803 zig_object.debug_line_header_dirty = true;
804 try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
791805 }
792806 }
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);
793815}
794816
795817pub 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
942964 } else null;
943965 const gc_sections = self.base.options.gc_sections orelse false;
944966
945 if (self.isObject() and self.zig_object_index == null) {
946 // TODO this will become -r route I guess. For now, just copy the object file.
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 }
967 // --verbose-link
968 if (self.base.options.verbose_link) try self.dumpArgv(comp);
969969
970970 var csu = try CsuObjects.init(arena, self.base.options, comp);
971971 const compiler_rt_path: ?[]const u8 = blk: {
......@@ -974,247 +974,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
974974 break :blk null;
975975 };
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
1217977 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
1219981 // Here we will parse input positional and library files (if referenced).
1220982 // 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
12401002 // rpaths
12411003 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);
12421004 defer rpath_table.deinit();
1005
12431006 for (self.base.options.rpath_list) |rpath| {
12441007 _ = try rpath_table.put(rpath, {});
12451008 }
......@@ -1388,8 +1151,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13881151 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
13891152 }
13901153
1391 if (self.isStaticLib()) return self.flushStaticLib(comp);
1392
13931154 // Init all objects
13941155 for (self.objects.items) |index| {
13951156 try self.file(index).?.object.init(self);
......@@ -1418,7 +1179,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14181179
14191180 // If we haven't already, create a linker-generated input file comprising of
14201181 // 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) {
14221183 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
14231184 self.files.set(index, .{ .linker_defined = .{ .index = index } });
14241185 self.linker_defined_index = index;
......@@ -1432,8 +1193,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14321193 self.resolveSymbols();
14331194 self.markEhFrameAtomsDead();
14341195
1435 if (self.isObject()) return self.flushObject(comp);
1436
14371196 try self.convertCommonSymbols();
14381197 self.markImportsExports();
14391198
......@@ -1527,10 +1286,30 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15271286 }
15281287}
15291288
1530pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {
1531 _ = comp;
1289pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
15321290 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
15341313 // First, we flush relocatable object file generated with our backends.
15351314 if (self.zigObjectPtr()) |zig_object| {
15361315 zig_object.resolveSymbols(self);
......@@ -1539,16 +1318,17 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
15391318 try self.initSymtab();
15401319 try self.initShStrtab();
15411320 try self.sortShdrs();
1542 zig_object.updateRelaSectionSizes(self);
1543 self.updateSymtabSizeObject(zig_object);
1544 self.updateShStrtabSize();
1321 try zig_object.addAtomsToRelaSections(self);
1322 try self.updateSectionSizesObject();
15451323
15461324 try self.allocateNonAllocSections();
15471325
1326 if (build_options.enable_logging) {
1327 state_log.debug("{}", .{self.dumpState()});
1328 }
1329
1330 try self.writeSyntheticSectionsObject();
15481331 try self.writeShdrTable();
1549 try zig_object.writeRelaSections(self);
1550 try self.writeSymtabObject(zig_object);
1551 try self.writeShStrtab();
15521332 try self.writeElfHeader();
15531333 }
15541334
......@@ -1603,67 +1383,391 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void
16031383 pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
16041384 }
16051385
1606 break :blk pos;
1607 };
1386 break :blk pos;
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) {
1610 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1611 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
1612 }
1649 var whole_archive = false;
1650 for (self.base.options.objects) |obj| {
1651 if (obj.must_link and !whole_archive) {
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);
1615 defer buffer.deinit();
1616 try buffer.ensureTotalCapacityPrecise(total_size);
1659 if (obj.loption) {
1660 assert(obj.path[0] == ':');
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 magic
1619 try buffer.writer().writeAll(elf.ARMAG);
1670 for (comp.c_object_table.keys()) |key| {
1671 try argv.append(key.status.success.object_path);
1672 }
16201673
1621 // Write symtab
1622 try ar_symtab.write(.p64, self, buffer.writer());
1674 if (module_obj_path) |p| {
1675 try argv.append(p);
1676 }
16231677
1624 // Write strtab
1625 if (ar_strtab.size() > 0) {
1626 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1627 try ar_strtab.write(buffer.writer());
1628 }
1678 // TSAN
1679 if (self.base.options.tsan) {
1680 try argv.append(comp.tsan_static_lib.?.full_object_path);
1681 }
16291682
1630 // Write object files
1631 for (files.items) |index| {
1632 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1633 try self.file(index).?.writeAr(self, buffer.writer());
1634 }
1683 // libc
1684 if (!self.base.options.skip_linker_dependencies and
1685 !self.base.options.link_libc)
1686 {
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);
1639 try self.base.file.?.pwriteAll(buffer.items, 0);
1640}
1698 // Shared libraries.
1699 // Worst-case, we need an --as-needed argument for every lib, as well
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 {
1643 _ = comp;
1705 for (self.base.options.system_libs.values()) |lib_info| {
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) {
1646 var err = try self.addErrorWithNotes(1);
1647 try err.addMsg(self, "fatal linker error: too many input positionals", .{});
1648 try err.addNote(self, "TODO implement '-r' option", .{});
1649 return;
1650 }
1721 if (!as_needed) {
1722 argv.appendAssumeCapacity("--as-needed");
1723 as_needed = true;
1724 }
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();
1655 try self.sortShdrs();
1656 try self.updateSectionSizes();
1732 // libunwind dep
1733 if (self.base.options.link_libunwind) {
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) {
1661 state_log.debug("{}", .{self.dumpState()});
1760 // compiler-rt
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);
16621768 }
16631769
1664 try self.writeShdrTable();
1665 try self.writeSyntheticSections();
1666 try self.writeElfHeader();
1770 Compilation.dump_argv(argv.items);
16671771}
16681772
16691773const ParseError = error{
......@@ -2047,8 +2151,7 @@ fn claimUnresolved(self: *Elf) void {
20472151 zig_object.claimUnresolved(self);
20482152 }
20492153 for (self.objects.items) |index| {
2050 const object = self.file(index).?.object;
2051 object.claimUnresolved(self);
2154 self.file(index).?.object.claimUnresolved(self);
20522155 }
20532156}
20542157
......@@ -2056,6 +2159,9 @@ fn claimUnresolvedObject(self: *Elf) void {
20562159 if (self.zigObjectPtr()) |zig_object| {
20572160 zig_object.claimUnresolvedObject(self);
20582161 }
2162 for (self.objects.items) |index| {
2163 self.file(index).?.object.claimUnresolvedObject(self);
2164 }
20592165}
20602166
20612167/// In scanRelocs we will go over all live atoms and scan their relocs.
......@@ -3460,6 +3566,60 @@ fn initSections(self: *Elf) !void {
34603566 try self.initShStrtab();
34613567}
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
34633623fn initSymtab(self: *Elf) !void {
34643624 const small_ptr = switch (self.ptr_width) {
34653625 .p32 => true,
......@@ -3586,7 +3746,8 @@ fn sortInitFini(self: *Elf) !void {
35863746
35873747 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
35913752 var entries = std.ArrayList(Entry).init(gpa);
35923753 try entries.ensureTotalCapacityPrecise(atom_list.items.len);
......@@ -3627,8 +3788,10 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
36273788 try self.dynamic.addNeeded(shared_object, self);
36283789 }
36293790
3630 if (self.base.options.soname) |soname| {
3631 try self.dynamic.setSoname(soname, self);
3791 if (self.isDynLib()) {
3792 if (self.base.options.soname) |soname| {
3793 try self.dynamic.setSoname(soname, self);
3794 }
36323795 }
36333796
36343797 try self.dynamic.setRpath(rpaths, self);
......@@ -3760,7 +3923,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 {
37603923
37613924 elf.SHT_DYNAMIC => return 0xf3,
37623925
3763 elf.SHT_RELA => return 0xf,
3926 elf.SHT_RELA, elf.SHT_GROUP => return 0xf,
37643927
37653928 elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
37663929 if (flags & elf.SHF_EXECINSTR != 0) {
......@@ -3819,8 +3982,15 @@ fn sortShdrs(self: *Elf) !void {
38193982 self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
38203983 }
38213984
3985 try self.resetShdrIndexes(backlinks);
3986}
3987
3988fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void {
3989 const gpa = self.base.allocator;
3990
38223991 for (&[_]*?u16{
38233992 &self.eh_frame_section_index,
3993 &self.eh_frame_rela_section_index,
38243994 &self.eh_frame_hdr_section_index,
38253995 &self.got_section_index,
38263996 &self.symtab_section_index,
......@@ -3841,12 +4011,9 @@ fn sortShdrs(self: *Elf) !void {
38414011 &self.versym_section_index,
38424012 &self.verneed_section_index,
38434013 &self.zig_text_section_index,
3844 &self.zig_text_rela_section_index,
38454014 &self.zig_got_section_index,
38464015 &self.zig_data_rel_ro_section_index,
3847 &self.zig_data_rel_ro_rela_section_index,
38484016 &self.zig_data_section_index,
3849 &self.zig_data_rela_section_index,
38504017 &self.zig_bss_section_index,
38514018 &self.debug_str_section_index,
38524019 &self.debug_info_section_index,
......@@ -3905,15 +4072,39 @@ fn sortShdrs(self: *Elf) !void {
39054072 shdr.sh_info = self.plt_section_index.?;
39064073 }
39074074
3908 for (&[_]?u16{
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;
4075 if (self.eh_frame_rela_section_index) |index| {
39144076 const shdr = &self.shdrs.items[index];
39154077 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 }
39174108 }
39184109
39194110 {
......@@ -3965,11 +4156,20 @@ fn sortShdrs(self: *Elf) !void {
39654156 global.output_section_index = backlinks[out_shndx];
39664157 }
39674158 }
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 }
39684169}
39694170
39704171fn updateSectionSizes(self: *Elf) !void {
39714172 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
3972 if (atom_list.items.len == 0) continue;
39734173 const shdr = &self.shdrs.items[shndx];
39744174 for (atom_list.items) |atom_index| {
39754175 const atom_ptr = self.atom(atom_index) orelse continue;
......@@ -3982,10 +4182,6 @@ fn updateSectionSizes(self: *Elf) !void {
39824182 }
39834183 }
39844184
3985 if (self.zigObjectPtr()) |zig_object| {
3986 zig_object.updateRelaSectionSizes(self);
3987 }
3988
39894185 if (self.eh_frame_section_index) |index| {
39904186 self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
39914187 }
......@@ -4049,22 +4245,73 @@ fn updateSectionSizes(self: *Elf) !void {
40494245 self.shdrs.items[index].sh_size = self.dynsym.size();
40504246 }
40514247
4052 if (self.dynstrtab_section_index) |index| {
4053 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
4054 }
4248 if (self.dynstrtab_section_index) |index| {
4249 self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
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| {
4057 self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
4287 if (shdr.sh_size == 0) shdr.sh_offset = 0;
40584288 }
40594289
4060 if (self.verneed_section_index) |index| {
4061 self.shdrs.items[index].sh_size = self.verneed.size();
4290 if (self.eh_frame_section_index) |index| {
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;
40624296 }
40634297
4064 self.updateSymtabSize();
4298 try self.updateSymtabSize();
4299 self.updateComdatGroupsSizes();
40654300 self.updateShStrtabSize();
40664301}
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
40684315fn updateShStrtabSize(self: *Elf) void {
40694316 if (self.shstrtab_section_index) |index| {
40704317 self.shdrs.items[index].sh_size = self.shstrtab.items.len;
......@@ -4294,6 +4541,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
42944541 }
42954542}
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
42974560/// Allocates non-alloc sections (debug info, symtabs, etc.).
42984561fn allocateNonAllocSections(self: *Elf) !void {
42994562 for (self.shdrs.items, 0..) |*shdr, shndx| {
......@@ -4418,6 +4681,7 @@ fn writeAtoms(self: *Elf) !void {
44184681 if (shdr.sh_type == elf.SHT_NOBITS) continue;
44194682
44204683 const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
4684 if (atom_list.items.len == 0) continue;
44214685
44224686 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
44234687
......@@ -4484,93 +4748,165 @@ fn writeAtoms(self: *Elf) !void {
44844748 try self.reportUndefined(&undefs);
44854749}
44864750
4487fn updateSymtabSize(self: *Elf) void {
4488 var sizes = SymtabSize{};
4751fn writeAtomsObject(self: *Elf) !void {
4752 const gpa = self.base.allocator;
44894753
4490 if (self.zigObjectPtr()) |zig_object| {
4491 zig_object.asFile().updateSymtabSize(self);
4492 sizes.add(zig_object.output_symtab_size);
4754 // TODO iterate over `output_sections` directly
4755 for (self.shdrs.items, 0..) |shdr, shndx| {
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);
44934814 }
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);
44954828 for (self.objects.items) |index| {
4496 const file_ptr = self.file(index).?;
4497 file_ptr.updateSymtabSize(self);
4498 sizes.add(file_ptr.object.output_symtab_size);
4829 files.appendAssumeCapacity(index);
44994830 }
4500
45014831 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| {
45024844 const file_ptr = self.file(index).?;
4503 file_ptr.updateSymtabSize(self);
4504 sizes.add(file_ptr.shared_object.output_symtab_size);
4845 const ctx = switch (file_ptr) {
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;
45054854 }
45064855
45074856 if (self.zig_got_section_index) |_| {
4857 self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
45084858 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;
45104861 }
45114862
45124863 if (self.got_section_index) |_| {
4864 self.got.output_symtab_ctx.ilocal = nlocals + 1;
45134865 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;
45154868 }
45164869
45174870 if (self.plt_section_index) |_| {
4871 self.plt.output_symtab_ctx.ilocal = nlocals + 1;
45184872 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;
45204875 }
45214876
45224877 if (self.plt_got_section_index) |_| {
4878 self.plt_got.output_symtab_ctx.ilocal = nlocals + 1;
45234879 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;
45254882 }
45264883
4527 if (self.linker_defined_index) |index| {
4884 for (files.items) |index| {
45284885 const file_ptr = self.file(index).?;
4529 file_ptr.updateSymtabSize(self);
4530 sizes.add(file_ptr.linker_defined.output_symtab_size);
4886 const ctx = switch (file_ptr) {
4887 inline else => |x| &x.output_symtab_ctx,
4888 };
4889 ctx.iglobal += nlocals;
45314890 }
45324891
45334892 const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
4534 symtab_shdr.sh_info = sizes.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;
4893 symtab_shdr.sh_info = nlocals + 1;
45544894 symtab_shdr.sh_link = self.strtab_section_index.?;
45554895
45564896 const sym_size: u64 = switch (self.ptr_width) {
45574897 .p32 => @sizeOf(elf.Elf32_Sym),
45584898 .p64 => @sizeOf(elf.Elf64_Sym),
45594899 };
4560 const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
4900 const needed_size = (nlocals + nglobals + 1) * sym_size;
45614901 symtab_shdr.sh_size = needed_size;
45624902
45634903 const strtab = &self.shdrs.items[self.strtab_section_index.?];
4564 strtab.sh_size = sizes.strsize + 1;
4904 strtab.sh_size = strsize + 1;
45654905}
45664906
45674907fn writeSyntheticSections(self: *Elf) !void {
45684908 const gpa = self.base.allocator;
45694909
4570 if (self.zigObjectPtr()) |zig_object| {
4571 try zig_object.writeRelaSections(self);
4572 }
4573
45744910 if (self.interp_section_index) |shndx| {
45754911 const shdr = self.shdrs.items[shndx];
45764912 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
......@@ -4698,9 +5034,97 @@ fn writeSyntheticSections(self: *Elf) !void {
46985034 try self.writeShStrtab();
46995035}
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
47015124fn writeShStrtab(self: *Elf) !void {
47025125 if (self.shstrtab_section_index) |index| {
47035126 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 });
47045128 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
47055129 }
47065130}
......@@ -4715,67 +5139,55 @@ fn writeSymtab(self: *Elf) !void {
47155139 };
47165140 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
47205152 try self.symtab.resize(gpa, nsyms);
47215153 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
47225154 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
47235155
4724 const Ctx = struct {
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 };
5156 self.writeSectionSymbols();
47375157
47385158 if (self.zigObjectPtr()) |zig_object| {
4739 zig_object.asFile().writeSymtab(self, ctx);
4740 ctx.incr(zig_object.output_symtab_size);
5159 zig_object.asFile().writeSymtab(self);
47415160 }
47425161
47435162 for (self.objects.items) |index| {
47445163 const file_ptr = self.file(index).?;
4745 file_ptr.writeSymtab(self, ctx);
4746 ctx.incr(file_ptr.object.output_symtab_size);
5164 file_ptr.writeSymtab(self);
47475165 }
47485166
47495167 for (self.shared_objects.items) |index| {
47505168 const file_ptr = self.file(index).?;
4751 file_ptr.writeSymtab(self, ctx);
4752 ctx.incr(file_ptr.shared_object.output_symtab_size);
5169 file_ptr.writeSymtab(self);
47535170 }
47545171
47555172 if (self.zig_got_section_index) |_| {
4756 self.zig_got.writeSymtab(self, ctx);
4757 ctx.incr(self.zig_got.output_symtab_size);
5173 self.zig_got.writeSymtab(self);
47585174 }
47595175
47605176 if (self.got_section_index) |_| {
4761 self.got.writeSymtab(self, ctx);
4762 ctx.incr(self.got.output_symtab_size);
5177 self.got.writeSymtab(self);
47635178 }
47645179
47655180 if (self.plt_section_index) |_| {
4766 self.plt.writeSymtab(self, ctx);
4767 ctx.incr(self.plt.output_symtab_size);
5181 self.plt.writeSymtab(self);
47685182 }
47695183
47705184 if (self.plt_got_section_index) |_| {
4771 self.plt_got.writeSymtab(self, ctx);
4772 ctx.incr(self.plt_got.output_symtab_size);
5185 self.plt_got.writeSymtab(self);
47735186 }
47745187
47755188 if (self.linker_defined_index) |index| {
47765189 const file_ptr = self.file(index).?;
4777 file_ptr.writeSymtab(self, ctx);
4778 ctx.incr(file_ptr.linker_defined.output_symtab_size);
5190 file_ptr.writeSymtab(self);
47795191 }
47805192
47815193 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
......@@ -4808,52 +5220,42 @@ fn writeSymtab(self: *Elf) !void {
48085220 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
48095221}
48105222
4811fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
4812 const gpa = self.base.allocator;
4813 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
4814 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
4815 const sym_size: u64 = switch (self.ptr_width) {
4816 .p32 => @sizeOf(elf.Elf32_Sym),
4817 .p64 => @sizeOf(elf.Elf64_Sym),
4818 };
4819 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
4820
4821 log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
4822
4823 try self.symtab.resize(gpa, nsyms);
4824 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
4825 try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
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);
5223fn writeSectionSymbols(self: *Elf) void {
5224 var ilocal: u32 = 1;
5225 for (self.output_sections.keys()) |shndx| {
5226 const shdr = self.shdrs.items[shndx];
5227 const out_sym = &self.symtab.items[ilocal];
5228 out_sym.* = .{
5229 .st_name = 0,
5230 .st_value = shdr.sh_addr,
5231 .st_info = elf.STT_SECTION,
5232 .st_shndx = @intCast(shndx),
5233 .st_size = 0,
5234 .st_other = 0,
5235 };
5236 ilocal += 1;
5237 }
48345238
4835 for (buf, self.symtab.items) |*out, sym| {
4836 out.* = .{
4837 .st_name = sym.st_name,
4838 .st_info = sym.st_info,
4839 .st_other = sym.st_other,
4840 .st_shndx = sym.st_shndx,
4841 .st_value = @as(u32, @intCast(sym.st_value)),
4842 .st_size = @as(u32, @intCast(sym.st_size)),
4843 };
4844 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
4845 }
4846 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
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 },
5239 if (self.eh_frame_section_index) |shndx| {
5240 const shdr = self.shdrs.items[shndx];
5241 const out_sym = &self.symtab.items[ilocal];
5242 out_sym.* = .{
5243 .st_name = 0,
5244 .st_value = shdr.sh_addr,
5245 .st_info = elf.STT_SECTION,
5246 .st_shndx = @intCast(shndx),
5247 .st_size = 0,
5248 .st_other = 0,
5249 };
5250 ilocal += 1;
48545251 }
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);
48575259}
48585260
48595261/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
......@@ -5707,13 +6109,69 @@ fn formatShdr(
57076109 _ = options;
57086110 _ = unused_fmt_string;
57096111 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({})", .{
57116113 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
57126114 shdr.sh_addr, shdr.sh_addralign,
5713 shdr.sh_size,
6115 shdr.sh_size, fmtShdrFlags(shdr.sh_flags),
57146116 });
57156117}
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
57176175const FormatPhdrCtx = struct {
57186176 elf_file: *Elf,
57196177 phdr: elf.Elf64_Phdr,
......@@ -5813,9 +6271,14 @@ fn fmtDumpState(
58136271 try writer.print("{}\n", .{self.got.fmt(self)});
58146272 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");
58176280 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", .{
58196282 shndx,
58206283 self.phdr_to_shdr_table.get(@intCast(shndx)),
58216284 self.fmtShdr(shdr),
......@@ -5823,7 +6286,7 @@ fn fmtDumpState(
58236286 }
58246287 try writer.writeAll("\nOutput phdrs\n");
58256288 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) });
58276290 }
58286291}
58296292
......@@ -5882,16 +6345,12 @@ pub const ComdatGroup = struct {
58826345 pub const Index = u32;
58836346};
58846347
5885pub const SymtabSize = struct {
6348pub const SymtabCtx = struct {
6349 ilocal: u32 = 0,
6350 iglobal: u32 = 0,
58866351 nlocals: u32 = 0,
58876352 nglobals: u32 = 0,
58886353 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 }
58956354};
58966355
58976356pub const null_sym = elf.Elf64_Sym{
......@@ -5942,8 +6401,13 @@ const LastAtomAndFreeList = struct {
59426401 /// by 1 byte. It will then have -1 overcapacity.
59436402 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
59446403};
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
59486412pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
59496413pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
......@@ -5976,6 +6440,7 @@ const Archive = @import("Elf/Archive.zig");
59766440pub const Atom = @import("Elf/Atom.zig");
59776441const Cache = std.Build.Cache;
59786442const Compilation = @import("../Compilation.zig");
6443const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
59796444const CopyRelSection = synthetic_sections.CopyRelSection;
59806445const DynamicSection = synthetic_sections.DynamicSection;
59816446const 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 {
6060 };
6161}
6262
63pub fn relocsShndx(self: Atom) ?u32 {
64 if (self.relocs_section_index == 0) return null;
65 return self.relocs_section_index;
66}
67
6368pub fn outputShndx(self: Atom) ?u16 {
6469 if (self.output_section_index == 0) return null;
6570 return self.output_section_index;
......@@ -280,13 +285,60 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
280285}
281286
282287pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
288 const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
283289 return switch (self.file(elf_file).?) {
284 .zig_object => |x| x.relocs.items[self.relocs_section_index].items,
285 .object => |x| x.getRelocs(self.relocs_section_index),
290 .zig_object => |x| x.relocs.items[shndx].items,
291 .object => |x| x.getRelocs(shndx),
286292 else => unreachable,
287293 };
288294}
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
290342pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
291343 if (self.fde_start == self.fde_end) return &[0]Fde{};
292344 const object = self.file(elf_file).?.object;
src/link/Elf/LinkerDefined.zig+1-1
......@@ -3,7 +3,7 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
33strtab: std.ArrayListUnmanaged(u8) = .{},
44symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
55
6output_symtab_size: Elf.SymtabSize = .{},
6output_symtab_ctx: Elf.SymtabCtx = .{},
77
88pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
99 self.symtab.deinit(allocator);
src/link/Elf/Object.zig+65-5
......@@ -19,7 +19,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
1919alive: bool = true,
2020num_dynrelocs: u32 = 0,
2121
22output_symtab_size: Elf.SymtabSize = .{},
22output_symtab_ctx: Elf.SymtabCtx = .{},
2323output_ar_state: Archive.ArState = .{},
2424
2525pub fn isObject(path: []const u8) !bool {
......@@ -142,7 +142,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
142142 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
143143 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
144144
145 if (group_members[0] != 0x1) { // GRP_COMDAT
145 if (group_members[0] != elf.GRP_COMDAT) {
146146 // TODO convert into an error
147147 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
148148 continue;
......@@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
211211fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
212212 const name = blk: {
213213 const name = self.getString(shdr.sh_name);
214 if (elf_file.isRelocatable()) break :blk name;
214215 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
215216 const sh_name_prefixes: []const [:0]const u8 = &.{
216217 ".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
237238 else => shdr.sh_type,
238239 };
239240 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 }
241245 break :blk switch (@"type") {
242246 elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
243247 else => flags,
......@@ -487,6 +491,25 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
487491 }
488492}
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
490513pub fn markLive(self: *Object, elf_file: *Elf) void {
491514 const first_global = self.first_global orelse return;
492515 for (self.globals(), 0..) |index, i| {
......@@ -654,6 +677,40 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
654677 }
655678}
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
657714pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
658715 const gpa = elf_file.base.allocator;
659716 const start = self.first_global orelse self.symtab.items.len;
......@@ -685,11 +742,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {
685742}
686743
687744pub fn locals(self: Object) []const Symbol.Index {
745 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
688746 const end = self.first_global orelse self.symbols.items.len;
689747 return self.symbols.items[0..end];
690748}
691749
692750pub fn globals(self: Object) []const Symbol.Index {
751 if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
693752 const start = self.first_global orelse self.symbols.items.len;
694753 return self.symbols.items[start..];
695754}
......@@ -881,16 +940,17 @@ fn formatComdatGroups(
881940 _ = options;
882941 const object = ctx.object;
883942 const elf_file = ctx.elf_file;
884 try writer.writeAll(" comdat groups\n");
943 try writer.writeAll(" COMDAT groups\n");
885944 for (object.comdat_groups.items) |cg_index| {
886945 const cg = elf_file.comdatGroup(cg_index);
887946 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
888947 if (cg_owner.file != object.index) continue;
948 try writer.print(" COMDAT({d})\n", .{cg_index});
889949 const cg_members = object.comdatGroupMembers(cg.shndx);
890950 for (cg_members) |shndx| {
891951 const atom_index = object.atoms.items[shndx];
892952 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) });
894954 }
895955 }
896956}
src/link/Elf/SharedObject.zig+1-1
......@@ -21,7 +21,7 @@ verdef_sect_index: ?u16 = null,
2121needed: bool,
2222alive: bool,
2323
24output_symtab_size: Elf.SymtabSize = .{},
24output_symtab_ctx: Elf.SymtabCtx = .{},
2525
2626pub fn isSharedObject(path: []const u8) !bool {
2727 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
107107 return symbol.value;
108108}
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
110128pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
111129 if (!symbol.flags.has_got) return 0;
112130 const extras = symbol.extra(elf_file).?;
......@@ -219,10 +237,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
219237 const st_shndx = blk: {
220238 if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
221239 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 obsolete
223 if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
224 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
225 break :blk elf.SHN_ABS;
240 if (elf_file.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
241 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
226242 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
227243 };
228244 const st_value = blk: {
......@@ -231,7 +247,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
231247 if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
232248 break :blk 0;
233249 }
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;
235251 const shdr = &elf_file.shdrs.items[st_shndx];
236252 if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
237253 break :blk symbol.value - elf_file.tlsAddress();
......@@ -390,6 +406,7 @@ pub const Extra = struct {
390406 plt: u32 = 0,
391407 plt_got: u32 = 0,
392408 dynamic: u32 = 0,
409 symtab: u32 = 0,
393410 copy_rel: u32 = 0,
394411 tlsgd: u32 = 0,
395412 gottp: u32 = 0,
src/link/Elf/ZigObject.zig+15-107
......@@ -18,7 +18,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
1818
1919num_dynrelocs: u32 = 0,
2020
21output_symtab_size: Elf.SymtabSize = .{},
21output_symtab_ctx: Elf.SymtabCtx = .{},
2222output_ar_state: Archive.ArState = .{},
2323
2424dwarf: ?Dwarf = null,
......@@ -75,6 +75,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
7575 const gpa = elf_file.base.allocator;
7676
7777 try self.atoms.append(gpa, 0); // null input section
78 try self.relocs.append(gpa, .{}); // null relocs section
7879 try self.strtab.buffer.append(gpa, 0);
7980
8081 const name_off = try self.strtab.insert(gpa, self.path);
......@@ -287,22 +288,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
287288 return symbol_index;
288289}
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
306291/// TODO actually create fake input shdrs and return that instead.
307292pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
308293 _ = self;
......@@ -393,8 +378,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
393378
394379 const global = elf_file.symbol(index);
395380 if (global.file(elf_file)) |file| {
396 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or
397 file.index() <= self.index) continue;
381 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
398382 }
399383
400384 global.value = 0;
......@@ -549,94 +533,18 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
549533 try writer.writeAll(contents);
550534}
551535
552pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
553 _ = self;
554
555 for (&[_]?u16{
556 elf_file.zig_text_rela_section_index,
557 elf_file.zig_data_rel_ro_rela_section_index,
558 elf_file.zig_data_rela_section_index,
559 }) |maybe_index| {
560 const index = maybe_index orelse continue;
561 const shdr = &elf_file.shdrs.items[index];
562 const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
563 const last_atom_index = meta.last_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);
536pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
537 for (self.atoms.items) |atom_index| {
538 const atom = elf_file.atom(atom_index) orelse continue;
539 if (!atom.flags.alive) continue;
540 _ = atom.relocsShndx() orelse continue;
541 const out_shndx = atom.outputShndx().?;
542 const out_shdr = elf_file.shdrs.items[out_shndx];
543 if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
544
545 const gpa = elf_file.base.allocator;
546 const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
547 try sec.atom_list.append(gpa, atom_index);
640548 }
641549}
642550
src/link/Elf/eh_frame.zig+110-1
......@@ -268,7 +268,11 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
268268 }
269269 }
270270
271 return offset + 4; // NULL terminator
271 if (!elf_file.isRelocatable()) {
272 offset += 4; // NULL terminator
273 }
274
275 return offset;
272276}
273277
274278pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
......@@ -282,6 +286,22 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
282286 return eh_frame_hdr_header_size + count * 8;
283287}
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
285305fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {
286306 const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow;
287307 const P = @as(i64, @intCast(rec.address(elf_file) + offset));
......@@ -357,6 +377,95 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
357377 try writer.writeInt(u32, 0, .little);
358378}
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
360469pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
361470 try writer.writeByte(1); // version
362471 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) {
127127 };
128128 }
129129
130 pub fn updateSymtabSize(file: File, elf_file: *Elf) void {
131 const output_symtab_size = switch (file) {
132 inline else => |x| &x.output_symtab_size,
130 pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
131 const output_symtab_ctx = switch (file) {
132 inline else => |x| &x.output_symtab_ctx,
133133 };
134134 for (file.locals()) |local_index| {
135135 const local = elf_file.symbol(local_index);
136136 if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
137137 const esym = local.elfSym(elf_file);
138138 switch (esym.st_type()) {
139 elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
140 elf.STT_NOTYPE => continue,
139 elf.STT_SECTION, elf.STT_NOTYPE => continue,
141140 else => {},
142141 }
143142 local.flags.output_symtab = true;
144 output_symtab_size.nlocals += 1;
145 output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
143 try local.setOutputSymtabIndex(output_symtab_ctx.nlocals, elf_file);
144 output_symtab_ctx.nlocals += 1;
145 output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
146146 }
147147
148148 for (file.globals()) |global_index| {
......@@ -152,47 +152,38 @@ pub const File = union(enum) {
152152 if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
153153 global.flags.output_symtab = true;
154154 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;
156157 } else {
157 output_symtab_size.nglobals += 1;
158 try global.setOutputSymtabIndex(output_symtab_ctx.nglobals, elf_file);
159 output_symtab_ctx.nglobals += 1;
158160 }
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;
160162 }
161163 }
162164
163 pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
164 var ilocal: usize = ctx.ilocal;
165 pub fn writeSymtab(file: File, elf_file: *Elf) void {
165166 for (file.locals()) |local_index| {
166167 const local = elf_file.symbol(local_index);
167 if (!local.flags.output_symtab) continue;
168 const out_sym = &elf_file.symtab.items[ilocal];
168 const idx = local.outputSymtabIndex(elf_file) orelse continue;
169 const out_sym = &elf_file.symtab.items[idx];
169170 out_sym.st_name = @intCast(elf_file.strtab.items.len);
170171 elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
171172 elf_file.strtab.appendAssumeCapacity(0);
172173 local.setOutputSym(elf_file, out_sym);
173 ilocal += 1;
174174 }
175175
176 var iglobal: usize = ctx.iglobal;
177176 for (file.globals()) |global_index| {
178177 const global = elf_file.symbol(global_index);
179178 const file_ptr = global.file(elf_file) orelse continue;
180179 if (file_ptr.index() != file.index()) continue;
181 if (!global.flags.output_symtab) continue;
180 const idx = global.outputSymtabIndex(elf_file) orelse continue;
182181 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
183182 elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
184183 elf_file.strtab.appendAssumeCapacity(0);
185 if (global.isLocal(elf_file)) {
186 const out_sym = &elf_file.symtab.items[ilocal];
187 out_sym.st_name = st_name;
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 }
184 const out_sym = &elf_file.symtab.items[idx];
185 out_sym.st_name = st_name;
186 global.setOutputSym(elf_file, out_sym);
196187 }
197188 }
198189
src/link/Elf/synthetic_sections.zig+68-20
......@@ -222,7 +222,7 @@ pub const DynamicSection = struct {
222222
223223pub const ZigGotSection = struct {
224224 entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
225 output_symtab_size: Elf.SymtabSize = .{},
225 output_symtab_ctx: Elf.SymtabCtx = .{},
226226 flags: Flags = .{},
227227
228228 const Flags = packed struct {
......@@ -359,15 +359,15 @@ pub const ZigGotSection = struct {
359359 }
360360
361361 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));
363363 for (zig_got.entries.items) |entry| {
364364 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;
366366 }
367367 }
368368
369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
370 for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
369 pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
370 for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
371371 const symbol = elf_file.symbol(entry);
372372 const symbol_name = symbol.name(elf_file);
373373 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
......@@ -420,7 +420,7 @@ pub const ZigGotSection = struct {
420420
421421pub const GotSection = struct {
422422 entries: std.ArrayListUnmanaged(Entry) = .{},
423 output_symtab_size: Elf.SymtabSize = .{},
423 output_symtab_ctx: Elf.SymtabCtx = .{},
424424 tlsld_index: ?u32 = null,
425425 flags: Flags = .{},
426426
......@@ -760,18 +760,18 @@ pub const GotSection = struct {
760760 }
761761
762762 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));
764764 for (got.entries.items) |entry| {
765765 const symbol_name = switch (entry.tag) {
766766 .tlsld => "",
767767 inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
768768 };
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;
770770 }
771771 }
772772
773 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
774 for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
773 pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {
774 for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {
775775 const symbol = switch (entry.tag) {
776776 .tlsld => null,
777777 inline else => elf_file.symbol(entry.symbol_index),
......@@ -831,7 +831,7 @@ pub const GotSection = struct {
831831
832832pub const PltSection = struct {
833833 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
834 output_symtab_size: Elf.SymtabSize = .{},
834 output_symtab_ctx: Elf.SymtabCtx = .{},
835835
836836 pub const preamble_size = 32;
837837
......@@ -909,15 +909,15 @@ pub const PltSection = struct {
909909 }
910910
911911 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));
913913 for (plt.symbols.items) |sym_index| {
914914 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;
916916 }
917917 }
918918
919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
920 var ilocal = ctx.ilocal;
919 pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {
920 var ilocal = plt.output_symtab_ctx.ilocal;
921921 for (plt.symbols.items) |sym_index| {
922922 const sym = elf_file.symbol(sym_index);
923923 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
......@@ -968,7 +968,7 @@ pub const GotPltSection = struct {
968968
969969pub const PltGotSection = struct {
970970 symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
971 output_symtab_size: Elf.SymtabSize = .{},
971 output_symtab_ctx: Elf.SymtabCtx = .{},
972972
973973 pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
974974 plt_got.symbols.deinit(allocator);
......@@ -1008,15 +1008,15 @@ pub const PltGotSection = struct {
10081008 }
10091009
10101010 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));
10121012 for (plt_got.symbols.items) |sym_index| {
10131013 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;
10151015 }
10161016 }
10171017
1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
1019 var ilocal = ctx.ilocal;
1018 pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {
1019 var ilocal = plt_got.output_symtab_ctx.ilocal;
10201020 for (plt_got.symbols.items) |sym_index| {
10211021 const sym = elf_file.symbol(sym_index);
10221022 const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
......@@ -1499,6 +1499,54 @@ pub const VerneedSection = struct {
14991499 }
15001500};
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
15021550fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
15031551 const entry_size = elf_file.archPtrWidthBytes();
15041552 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 {
2121 .abi = .gnu,
2222 };
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
2429 // Exercise linker in ar mode
2530 elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
2631
......@@ -629,6 +634,53 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
629634 return test_step;
630635}
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
632684fn testEmitStaticLib(b: *Build, opts: Options) *Step {
633685 const test_step = addTestStep(b, "emit-static-lib", opts);
634686
......@@ -951,7 +1003,6 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
9511003 const obj = addObject(b, "obj", .{
9521004 .target = opts.target,
9531005 .use_llvm = true,
954 .use_lld = true,
9551006 });
9561007 addCSourceBytes(obj,
9571008 \\int live_var1 = 1;
......@@ -2089,6 +2140,89 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
20892140 return test_step;
20902141}
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
20922226fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
20932227 const test_step = addTestStep(b, "shared-abs-symbol", opts);
20942228