authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-11 23:28:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-12 10:44:17-07:00
log1ba3fc90bef145310e09026e7e9e09623117a800
treea7f86838e8fae04336e5254b10c373416548a7ad
parent7e530c13b3ef9b61417a610c00fc1d37c11ff7ed

link.Elf: eliminate an O(N^2) algorithm in flush()

Make shared_objects a StringArrayHashMap so that deduping does not need to happen in flush. That deduping code also was using an O(N^2) algorithm, which is not allowed in this codebase. There is another violation of this rule in resolveSymbols but this commit does not address it. This required reworking shared object parsing, breaking it into independent components so that we could access soname earlier. Shared object parsing had a few problems that I noticed and fixed in this commit: * Many instances of incorrect use of align(1). * `shnum * @sizeOf(elf.Elf64_Shdr)` can overflow based on user data. * `@divExact` can cause illegal behavior based on user data. * Strange versyms logic that wasn't present in mold nor lld. The logic was not commented and there is no git blame information in ziglang/zig nor kubkon/zld. I changed it to match mold and lld instead. * Use of ArrayList for slices of memory that are never resized. * finding DT_VERDEFNUM in a different loop than finding DT_SONAME. Ultimately I think we should follow mold's lead and ignore this integer, relying on null termination instead. * Doing logic based on VER_FLG_BASE rather than ignoring it like mold and LLD do. No comment explaining why the behavior is different. * Mutating the original ELF symbols rather than only storing the mangled name on the new Symbol struct. I noticed something that I didn't try to address in this commit: Symbol stores a lot of redundant information that is already present in the ELF symbols. I suspect that the codebase could benefit from reworking Symbol to not store redundant information. Additionally: * Add some type safety to std.elf. * Eliminate 1-3 file system reads for determining the kind of input files, by taking advantage of file name extension and handling error codes properly. * Move more error handling methods to link.Diags and make them infallible and thread-safe * Make the data dependencies obvious in the parameters of parseSharedObject. It's now clear that the first two steps (Header and Parsed) can be done during the main Compilation pipeline, rather than waiting for flush().

18 files changed, 781 insertions(+), 712 deletions(-)

lib/std/Build/Cache.zig+8
......@@ -150,6 +150,14 @@ pub const File = struct {
150150 inode: fs.File.INode,
151151 size: u64,
152152 mtime: i128,
153
154 pub fn fromFs(fs_stat: fs.File.Stat) Stat {
155 return .{
156 .inode = fs_stat.inode,
157 .size = fs_stat.size,
158 .mtime = fs_stat.mtime,
159 };
160 }
153161 };
154162
155163 pub fn deinit(self: *File, gpa: Allocator) void {
lib/std/elf.zig+137-164
......@@ -258,17 +258,26 @@ pub const DF_1_SINGLETON = 0x02000000;
258258pub const DF_1_STUB = 0x04000000;
259259pub const DF_1_PIE = 0x08000000;
260260
261pub const VERSYM_HIDDEN = 0x8000;
262pub const VERSYM_VERSION = 0x7fff;
263
264/// Symbol is local
265pub const VER_NDX_LOCAL = 0;
266/// Symbol is global
267pub const VER_NDX_GLOBAL = 1;
268/// Beginning of reserved entries
269pub const VER_NDX_LORESERVE = 0xff00;
270/// Symbol is to be eliminated
271pub const VER_NDX_ELIMINATE = 0xff01;
261pub const Versym = packed struct(u16) {
262 VERSION: u15,
263 HIDDEN: bool,
264
265 pub const LOCAL: Versym = @bitCast(@intFromEnum(VER_NDX.LOCAL));
266 pub const GLOBAL: Versym = @bitCast(@intFromEnum(VER_NDX.GLOBAL));
267};
268
269pub const VER_NDX = enum(u16) {
270 /// Symbol is local
271 LOCAL = 0,
272 /// Symbol is global
273 GLOBAL = 1,
274 /// Beginning of reserved entries
275 LORESERVE = 0xff00,
276 /// Symbol is to be eliminated
277 ELIMINATE = 0xff01,
278 UNSPECIFIED = 0xffff,
279 _,
280};
272281
273282/// Version definition of the file itself
274283pub const VER_FLG_BASE = 1;
......@@ -698,12 +707,9 @@ pub const EI_PAD = 9;
698707
699708pub const EI_NIDENT = 16;
700709
701pub const Elf32_Half = u16;
702pub const Elf64_Half = u16;
703pub const Elf32_Word = u32;
704pub const Elf32_Sword = i32;
705pub const Elf64_Word = u32;
706pub const Elf64_Sword = i32;
710pub const Half = u16;
711pub const Word = u32;
712pub const Sword = i32;
707713pub const Elf32_Xword = u64;
708714pub const Elf32_Sxword = i64;
709715pub const Elf64_Xword = u64;
......@@ -714,53 +720,51 @@ pub const Elf32_Off = u32;
714720pub const Elf64_Off = u64;
715721pub const Elf32_Section = u16;
716722pub const Elf64_Section = u16;
717pub const Elf32_Versym = Elf32_Half;
718pub const Elf64_Versym = Elf64_Half;
719723pub const Elf32_Ehdr = extern struct {
720724 e_ident: [EI_NIDENT]u8,
721725 e_type: ET,
722726 e_machine: EM,
723 e_version: Elf32_Word,
727 e_version: Word,
724728 e_entry: Elf32_Addr,
725729 e_phoff: Elf32_Off,
726730 e_shoff: Elf32_Off,
727 e_flags: Elf32_Word,
728 e_ehsize: Elf32_Half,
729 e_phentsize: Elf32_Half,
730 e_phnum: Elf32_Half,
731 e_shentsize: Elf32_Half,
732 e_shnum: Elf32_Half,
733 e_shstrndx: Elf32_Half,
731 e_flags: Word,
732 e_ehsize: Half,
733 e_phentsize: Half,
734 e_phnum: Half,
735 e_shentsize: Half,
736 e_shnum: Half,
737 e_shstrndx: Half,
734738};
735739pub const Elf64_Ehdr = extern struct {
736740 e_ident: [EI_NIDENT]u8,
737741 e_type: ET,
738742 e_machine: EM,
739 e_version: Elf64_Word,
743 e_version: Word,
740744 e_entry: Elf64_Addr,
741745 e_phoff: Elf64_Off,
742746 e_shoff: Elf64_Off,
743 e_flags: Elf64_Word,
744 e_ehsize: Elf64_Half,
745 e_phentsize: Elf64_Half,
746 e_phnum: Elf64_Half,
747 e_shentsize: Elf64_Half,
748 e_shnum: Elf64_Half,
749 e_shstrndx: Elf64_Half,
747 e_flags: Word,
748 e_ehsize: Half,
749 e_phentsize: Half,
750 e_phnum: Half,
751 e_shentsize: Half,
752 e_shnum: Half,
753 e_shstrndx: Half,
750754};
751755pub const Elf32_Phdr = extern struct {
752 p_type: Elf32_Word,
756 p_type: Word,
753757 p_offset: Elf32_Off,
754758 p_vaddr: Elf32_Addr,
755759 p_paddr: Elf32_Addr,
756 p_filesz: Elf32_Word,
757 p_memsz: Elf32_Word,
758 p_flags: Elf32_Word,
759 p_align: Elf32_Word,
760 p_filesz: Word,
761 p_memsz: Word,
762 p_flags: Word,
763 p_align: Word,
760764};
761765pub const Elf64_Phdr = extern struct {
762 p_type: Elf64_Word,
763 p_flags: Elf64_Word,
766 p_type: Word,
767 p_flags: Word,
764768 p_offset: Elf64_Off,
765769 p_vaddr: Elf64_Addr,
766770 p_paddr: Elf64_Addr,
......@@ -769,44 +773,44 @@ pub const Elf64_Phdr = extern struct {
769773 p_align: Elf64_Xword,
770774};
771775pub const Elf32_Shdr = extern struct {
772 sh_name: Elf32_Word,
773 sh_type: Elf32_Word,
774 sh_flags: Elf32_Word,
776 sh_name: Word,
777 sh_type: Word,
778 sh_flags: Word,
775779 sh_addr: Elf32_Addr,
776780 sh_offset: Elf32_Off,
777 sh_size: Elf32_Word,
778 sh_link: Elf32_Word,
779 sh_info: Elf32_Word,
780 sh_addralign: Elf32_Word,
781 sh_entsize: Elf32_Word,
781 sh_size: Word,
782 sh_link: Word,
783 sh_info: Word,
784 sh_addralign: Word,
785 sh_entsize: Word,
782786};
783787pub const Elf64_Shdr = extern struct {
784 sh_name: Elf64_Word,
785 sh_type: Elf64_Word,
788 sh_name: Word,
789 sh_type: Word,
786790 sh_flags: Elf64_Xword,
787791 sh_addr: Elf64_Addr,
788792 sh_offset: Elf64_Off,
789793 sh_size: Elf64_Xword,
790 sh_link: Elf64_Word,
791 sh_info: Elf64_Word,
794 sh_link: Word,
795 sh_info: Word,
792796 sh_addralign: Elf64_Xword,
793797 sh_entsize: Elf64_Xword,
794798};
795799pub const Elf32_Chdr = extern struct {
796800 ch_type: COMPRESS,
797 ch_size: Elf32_Word,
798 ch_addralign: Elf32_Word,
801 ch_size: Word,
802 ch_addralign: Word,
799803};
800804pub const Elf64_Chdr = extern struct {
801805 ch_type: COMPRESS,
802 ch_reserved: Elf64_Word = 0,
806 ch_reserved: Word = 0,
803807 ch_size: Elf64_Xword,
804808 ch_addralign: Elf64_Xword,
805809};
806810pub const Elf32_Sym = extern struct {
807 st_name: Elf32_Word,
811 st_name: Word,
808812 st_value: Elf32_Addr,
809 st_size: Elf32_Word,
813 st_size: Word,
810814 st_info: u8,
811815 st_other: u8,
812816 st_shndx: Elf32_Section,
......@@ -819,7 +823,7 @@ pub const Elf32_Sym = extern struct {
819823 }
820824};
821825pub const Elf64_Sym = extern struct {
822 st_name: Elf64_Word,
826 st_name: Word,
823827 st_info: u8,
824828 st_other: u8,
825829 st_shndx: Elf64_Section,
......@@ -834,16 +838,16 @@ pub const Elf64_Sym = extern struct {
834838 }
835839};
836840pub const Elf32_Syminfo = extern struct {
837 si_boundto: Elf32_Half,
838 si_flags: Elf32_Half,
841 si_boundto: Half,
842 si_flags: Half,
839843};
840844pub const Elf64_Syminfo = extern struct {
841 si_boundto: Elf64_Half,
842 si_flags: Elf64_Half,
845 si_boundto: Half,
846 si_flags: Half,
843847};
844848pub const Elf32_Rel = extern struct {
845849 r_offset: Elf32_Addr,
846 r_info: Elf32_Word,
850 r_info: Word,
847851
848852 pub inline fn r_sym(self: @This()) u24 {
849853 return @truncate(self.r_info >> 8);
......@@ -865,8 +869,8 @@ pub const Elf64_Rel = extern struct {
865869};
866870pub const Elf32_Rela = extern struct {
867871 r_offset: Elf32_Addr,
868 r_info: Elf32_Word,
869 r_addend: Elf32_Sword,
872 r_info: Word,
873 r_addend: Sword,
870874
871875 pub inline fn r_sym(self: @This()) u24 {
872876 return @truncate(self.r_info >> 8);
......@@ -887,69 +891,49 @@ pub const Elf64_Rela = extern struct {
887891 return @truncate(self.r_info);
888892 }
889893};
890pub const Elf32_Relr = Elf32_Word;
894pub const Elf32_Relr = Word;
891895pub const Elf64_Relr = Elf64_Xword;
892896pub const Elf32_Dyn = extern struct {
893 d_tag: Elf32_Sword,
897 d_tag: Sword,
894898 d_val: Elf32_Addr,
895899};
896900pub const Elf64_Dyn = extern struct {
897901 d_tag: Elf64_Sxword,
898902 d_val: Elf64_Addr,
899903};
900pub const Elf32_Verdef = extern struct {
901 vd_version: Elf32_Half,
902 vd_flags: Elf32_Half,
903 vd_ndx: Elf32_Half,
904 vd_cnt: Elf32_Half,
905 vd_hash: Elf32_Word,
906 vd_aux: Elf32_Word,
907 vd_next: Elf32_Word,
908};
909pub const Elf64_Verdef = extern struct {
910 vd_version: Elf64_Half,
911 vd_flags: Elf64_Half,
912 vd_ndx: Elf64_Half,
913 vd_cnt: Elf64_Half,
914 vd_hash: Elf64_Word,
915 vd_aux: Elf64_Word,
916 vd_next: Elf64_Word,
904pub const Verdef = extern struct {
905 version: Half,
906 flags: Half,
907 ndx: VER_NDX,
908 cnt: Half,
909 hash: Word,
910 aux: Word,
911 next: Word,
917912};
918pub const Elf32_Verdaux = extern struct {
919 vda_name: Elf32_Word,
920 vda_next: Elf32_Word,
921};
922pub const Elf64_Verdaux = extern struct {
923 vda_name: Elf64_Word,
924 vda_next: Elf64_Word,
913pub const Verdaux = extern struct {
914 name: Word,
915 next: Word,
925916};
926917pub const Elf32_Verneed = extern struct {
927 vn_version: Elf32_Half,
928 vn_cnt: Elf32_Half,
929 vn_file: Elf32_Word,
930 vn_aux: Elf32_Word,
931 vn_next: Elf32_Word,
918 vn_version: Half,
919 vn_cnt: Half,
920 vn_file: Word,
921 vn_aux: Word,
922 vn_next: Word,
932923};
933924pub const Elf64_Verneed = extern struct {
934 vn_version: Elf64_Half,
935 vn_cnt: Elf64_Half,
936 vn_file: Elf64_Word,
937 vn_aux: Elf64_Word,
938 vn_next: Elf64_Word,
939};
940pub const Elf32_Vernaux = extern struct {
941 vna_hash: Elf32_Word,
942 vna_flags: Elf32_Half,
943 vna_other: Elf32_Half,
944 vna_name: Elf32_Word,
945 vna_next: Elf32_Word,
925 vn_version: Half,
926 vn_cnt: Half,
927 vn_file: Word,
928 vn_aux: Word,
929 vn_next: Word,
946930};
947pub const Elf64_Vernaux = extern struct {
948 vna_hash: Elf64_Word,
949 vna_flags: Elf64_Half,
950 vna_other: Elf64_Half,
951 vna_name: Elf64_Word,
952 vna_next: Elf64_Word,
931pub const Vernaux = extern struct {
932 hash: Word,
933 flags: Half,
934 other: Half,
935 name: Word,
936 next: Word,
953937};
954938pub const Elf32_auxv_t = extern struct {
955939 a_type: u32,
......@@ -964,81 +948,81 @@ pub const Elf64_auxv_t = extern struct {
964948 },
965949};
966950pub const Elf32_Nhdr = extern struct {
967 n_namesz: Elf32_Word,
968 n_descsz: Elf32_Word,
969 n_type: Elf32_Word,
951 n_namesz: Word,
952 n_descsz: Word,
953 n_type: Word,
970954};
971955pub const Elf64_Nhdr = extern struct {
972 n_namesz: Elf64_Word,
973 n_descsz: Elf64_Word,
974 n_type: Elf64_Word,
956 n_namesz: Word,
957 n_descsz: Word,
958 n_type: Word,
975959};
976960pub const Elf32_Move = extern struct {
977961 m_value: Elf32_Xword,
978 m_info: Elf32_Word,
979 m_poffset: Elf32_Word,
980 m_repeat: Elf32_Half,
981 m_stride: Elf32_Half,
962 m_info: Word,
963 m_poffset: Word,
964 m_repeat: Half,
965 m_stride: Half,
982966};
983967pub const Elf64_Move = extern struct {
984968 m_value: Elf64_Xword,
985969 m_info: Elf64_Xword,
986970 m_poffset: Elf64_Xword,
987 m_repeat: Elf64_Half,
988 m_stride: Elf64_Half,
971 m_repeat: Half,
972 m_stride: Half,
989973};
990974pub const Elf32_gptab = extern union {
991975 gt_header: extern struct {
992 gt_current_g_value: Elf32_Word,
993 gt_unused: Elf32_Word,
976 gt_current_g_value: Word,
977 gt_unused: Word,
994978 },
995979 gt_entry: extern struct {
996 gt_g_value: Elf32_Word,
997 gt_bytes: Elf32_Word,
980 gt_g_value: Word,
981 gt_bytes: Word,
998982 },
999983};
1000984pub const Elf32_RegInfo = extern struct {
1001 ri_gprmask: Elf32_Word,
1002 ri_cprmask: [4]Elf32_Word,
1003 ri_gp_value: Elf32_Sword,
985 ri_gprmask: Word,
986 ri_cprmask: [4]Word,
987 ri_gp_value: Sword,
1004988};
1005989pub const Elf_Options = extern struct {
1006990 kind: u8,
1007991 size: u8,
1008992 section: Elf32_Section,
1009 info: Elf32_Word,
993 info: Word,
1010994};
1011995pub const Elf_Options_Hw = extern struct {
1012 hwp_flags1: Elf32_Word,
1013 hwp_flags2: Elf32_Word,
996 hwp_flags1: Word,
997 hwp_flags2: Word,
1014998};
1015999pub const Elf32_Lib = extern struct {
1016 l_name: Elf32_Word,
1017 l_time_stamp: Elf32_Word,
1018 l_checksum: Elf32_Word,
1019 l_version: Elf32_Word,
1020 l_flags: Elf32_Word,
1000 l_name: Word,
1001 l_time_stamp: Word,
1002 l_checksum: Word,
1003 l_version: Word,
1004 l_flags: Word,
10211005};
10221006pub const Elf64_Lib = extern struct {
1023 l_name: Elf64_Word,
1024 l_time_stamp: Elf64_Word,
1025 l_checksum: Elf64_Word,
1026 l_version: Elf64_Word,
1027 l_flags: Elf64_Word,
1007 l_name: Word,
1008 l_time_stamp: Word,
1009 l_checksum: Word,
1010 l_version: Word,
1011 l_flags: Word,
10281012};
10291013pub const Elf32_Conflict = Elf32_Addr;
10301014pub const Elf_MIPS_ABIFlags_v0 = extern struct {
1031 version: Elf32_Half,
1015 version: Half,
10321016 isa_level: u8,
10331017 isa_rev: u8,
10341018 gpr_size: u8,
10351019 cpr1_size: u8,
10361020 cpr2_size: u8,
10371021 fp_abi: u8,
1038 isa_ext: Elf32_Word,
1039 ases: Elf32_Word,
1040 flags1: Elf32_Word,
1041 flags2: Elf32_Word,
1022 isa_ext: Word,
1023 ases: Word,
1024 flags1: Word,
1025 flags2: Word,
10421026};
10431027
10441028comptime {
......@@ -1102,22 +1086,11 @@ pub const Sym = switch (@sizeOf(usize)) {
11021086 8 => Elf64_Sym,
11031087 else => @compileError("expected pointer size of 32 or 64"),
11041088};
1105pub const Verdef = switch (@sizeOf(usize)) {
1106 4 => Elf32_Verdef,
1107 8 => Elf64_Verdef,
1108 else => @compileError("expected pointer size of 32 or 64"),
1109};
1110pub const Verdaux = switch (@sizeOf(usize)) {
1111 4 => Elf32_Verdaux,
1112 8 => Elf64_Verdaux,
1113 else => @compileError("expected pointer size of 32 or 64"),
1114};
11151089pub const Addr = switch (@sizeOf(usize)) {
11161090 4 => Elf32_Addr,
11171091 8 => Elf64_Addr,
11181092 else => @compileError("expected pointer size of 32 or 64"),
11191093};
1120pub const Half = u16;
11211094
11221095pub const OSABI = enum(u8) {
11231096 /// UNIX System V ABI
lib/std/os/linux/vdso.zig+9-11
......@@ -37,7 +37,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
3737 var maybe_strings: ?[*]u8 = null;
3838 var maybe_syms: ?[*]elf.Sym = null;
3939 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
40 var maybe_versym: ?[*]u16 = null;
40 var maybe_versym: ?[*]elf.Versym = null;
4141 var maybe_verdef: ?*elf.Verdef = null;
4242
4343 {
......@@ -48,7 +48,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
4848 elf.DT_STRTAB => maybe_strings = @as([*]u8, @ptrFromInt(p)),
4949 elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
5050 elf.DT_HASH => maybe_hashtab = @as([*]linux.Elf_Symndx, @ptrFromInt(p)),
51 elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
51 elf.DT_VERSYM => maybe_versym = @as([*]elf.Versym, @ptrFromInt(p)),
5252 elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
5353 else => {},
5454 }
......@@ -80,17 +80,15 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
8080 return 0;
8181}
8282
83fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {
83fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, strings: [*]u8) bool {
8484 var def = def_arg;
85 const vsym = @as(u32, @bitCast(vsym_arg)) & 0x7fff;
85 const vsym_index = vsym_arg.VERSION;
8686 while (true) {
87 if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
88 break;
89 if (def.vd_next == 0)
90 return false;
91 def = @as(*elf.Verdef, @ptrFromInt(@intFromPtr(def) + def.vd_next));
87 if (0 == (def.flags & elf.VER_FLG_BASE) and @intFromEnum(def.ndx) == vsym_index) break;
88 if (def.next == 0) return false;
89 def = @ptrFromInt(@intFromPtr(def) + def.next);
9290 }
93 const aux = @as(*elf.Verdaux, @ptrFromInt(@intFromPtr(def) + def.vd_aux));
94 const vda_name = @as([*:0]u8, @ptrCast(strings + aux.vda_name));
91 const aux: *elf.Verdaux = @ptrFromInt(@intFromPtr(def) + def.aux);
92 const vda_name: [*:0]u8 = @ptrCast(strings + aux.name);
9593 return mem.eql(u8, vername, mem.sliceTo(vda_name, 0));
9694}
src/Compilation.zig+2
......@@ -1002,6 +1002,7 @@ const CacheUse = union(CacheMode) {
10021002pub const LinkObject = struct {
10031003 path: Path,
10041004 must_link: bool = false,
1005 needed: bool = false,
10051006 // When the library is passed via a positional argument, it will be
10061007 // added as a full path. If it's `-l<lib>`, then just the basename.
10071008 //
......@@ -2561,6 +2562,7 @@ fn addNonIncrementalStuffToCacheManifest(
25612562 for (comp.objects) |obj| {
25622563 _ = try man.addFilePath(obj.path, null);
25632564 man.hash.add(obj.must_link);
2565 man.hash.add(obj.needed);
25642566 man.hash.add(obj.loption);
25652567 }
25662568
src/link.zig+83-27
......@@ -207,23 +207,19 @@ pub const Diags = struct {
207207 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
208208 @branchHint(.cold);
209209 const gpa = diags.gpa;
210 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
210211 diags.mutex.lock();
211212 defer diags.mutex.unlock();
212 diags.msgs.ensureUnusedCapacity(gpa, 1) catch |err| switch (err) {
213 error.OutOfMemory => {
214 diags.flags.alloc_failure_occurred = true;
215 return;
216 },
217 };
218 const err_msg: Msg = .{
219 .msg = std.fmt.allocPrint(gpa, format, args) catch |err| switch (err) {
220 error.OutOfMemory => {
221 diags.flags.alloc_failure_occurred = true;
222 return;
223 },
224 },
213 addErrorLockedFallible(diags, eu_main_msg) catch |err| switch (err) {
214 error.OutOfMemory => diags.setAllocFailureLocked(),
225215 };
226 diags.msgs.appendAssumeCapacity(err_msg);
216 }
217
218 fn addErrorLockedFallible(diags: *Diags, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void {
219 const gpa = diags.gpa;
220 const main_msg = try eu_main_msg;
221 errdefer gpa.free(main_msg);
222 try diags.msgs.append(gpa, .{ .msg = main_msg });
227223 }
228224
229225 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
......@@ -242,7 +238,7 @@ pub const Diags = struct {
242238 const err = diags.msgs.addOneAssumeCapacity();
243239 err.* = .{
244240 .msg = undefined,
245 .notes = try gpa.alloc(Diags.Msg, note_count),
241 .notes = try gpa.alloc(Msg, note_count),
246242 };
247243 return .{
248244 .diags = diags,
......@@ -250,34 +246,93 @@ pub const Diags = struct {
250246 };
251247 }
252248
253 pub fn reportMissingLibraryError(
249 pub fn addMissingLibraryError(
254250 diags: *Diags,
255251 checked_paths: []const []const u8,
256252 comptime format: []const u8,
257253 args: anytype,
258 ) error{OutOfMemory}!void {
254 ) void {
259255 @branchHint(.cold);
260 var err = try diags.addErrorWithNotes(checked_paths.len);
261 try err.addMsg(format, args);
262 for (checked_paths) |path| {
263 try err.addNote("tried {s}", .{path});
256 const gpa = diags.gpa;
257 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
258 diags.mutex.lock();
259 defer diags.mutex.unlock();
260 addMissingLibraryErrorLockedFallible(diags, checked_paths, eu_main_msg) catch |err| switch (err) {
261 error.OutOfMemory => diags.setAllocFailureLocked(),
262 };
263 }
264
265 fn addMissingLibraryErrorLockedFallible(
266 diags: *Diags,
267 checked_paths: []const []const u8,
268 eu_main_msg: Allocator.Error![]u8,
269 ) Allocator.Error!void {
270 const gpa = diags.gpa;
271 const main_msg = try eu_main_msg;
272 errdefer gpa.free(main_msg);
273 try diags.msgs.ensureUnusedCapacity(gpa, 1);
274 const notes = try gpa.alloc(Msg, checked_paths.len);
275 errdefer gpa.free(notes);
276 for (checked_paths, notes) |path, *note| {
277 note.* = .{ .msg = try std.fmt.allocPrint(gpa, "tried {s}", .{path}) };
264278 }
279 diags.msgs.appendAssumeCapacity(.{
280 .msg = main_msg,
281 .notes = notes,
282 });
283 }
284
285 pub fn addParseError(
286 diags: *Diags,
287 path: Path,
288 comptime format: []const u8,
289 args: anytype,
290 ) void {
291 @branchHint(.cold);
292 const gpa = diags.gpa;
293 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
294 diags.mutex.lock();
295 defer diags.mutex.unlock();
296 addParseErrorLockedFallible(diags, path, eu_main_msg) catch |err| switch (err) {
297 error.OutOfMemory => diags.setAllocFailureLocked(),
298 };
265299 }
266300
267 pub fn reportParseError(
301 fn addParseErrorLockedFallible(diags: *Diags, path: Path, m: Allocator.Error![]u8) Allocator.Error!void {
302 const gpa = diags.gpa;
303 const main_msg = try m;
304 errdefer gpa.free(main_msg);
305 try diags.msgs.ensureUnusedCapacity(gpa, 1);
306 const note = try std.fmt.allocPrint(gpa, "while parsing {}", .{path});
307 errdefer gpa.free(note);
308 const notes = try gpa.create([1]Msg);
309 errdefer gpa.destroy(notes);
310 notes.* = .{.{ .msg = note }};
311 diags.msgs.appendAssumeCapacity(.{
312 .msg = main_msg,
313 .notes = notes,
314 });
315 }
316
317 pub fn failParse(
268318 diags: *Diags,
269319 path: Path,
270320 comptime format: []const u8,
271321 args: anytype,
272 ) error{OutOfMemory}!void {
322 ) error{LinkFailure} {
273323 @branchHint(.cold);
274 var err = try diags.addErrorWithNotes(1);
275 try err.addMsg(format, args);
276 try err.addNote("while parsing {}", .{path});
324 addParseError(diags, path, format, args);
325 return error.LinkFailure;
277326 }
278327
279328 pub fn setAllocFailure(diags: *Diags) void {
280329 @branchHint(.cold);
330 diags.mutex.lock();
331 defer diags.mutex.unlock();
332 setAllocFailureLocked(diags);
333 }
334
335 fn setAllocFailureLocked(diags: *Diags) void {
281336 log.debug("memory allocation failure", .{});
282337 diags.flags.alloc_failure_occurred = true;
283338 }
......@@ -727,7 +782,8 @@ pub const File = struct {
727782 FailedToEmit,
728783 FileSystem,
729784 FilesOpenedWithWrongFlags,
730 /// Indicates an error will be present in `Compilation.link_errors`.
785 /// Deprecated. Use `LinkFailure` instead.
786 /// Formerly used to indicate an error will be present in `Compilation.link_errors`.
731787 FlushFailure,
732788 /// Indicates an error will be present in `Compilation.link_errors`.
733789 LinkFailure,
src/link/Elf.zig+191-175
......@@ -46,7 +46,7 @@ file_handles: std.ArrayListUnmanaged(File.Handle) = .empty,
4646zig_object_index: ?File.Index = null,
4747linker_defined_index: ?File.Index = null,
4848objects: std.ArrayListUnmanaged(File.Index) = .empty,
49shared_objects: std.ArrayListUnmanaged(File.Index) = .empty,
49shared_objects: std.StringArrayHashMapUnmanaged(File.Index) = .empty,
5050
5151/// List of all output sections and their associated metadata.
5252sections: std.MultiArrayList(Section) = .{},
......@@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{},
6262section_indexes: SectionIndexes = .{},
6363
6464page_size: u32,
65default_sym_version: elf.Elf64_Versym,
65default_sym_version: elf.Versym,
6666
6767/// .shstrtab buffer
6868shstrtab: std.ArrayListUnmanaged(u8) = .empty,
......@@ -75,7 +75,7 @@ dynsym: DynsymSection = .{},
7575/// .dynstrtab buffer
7676dynstrtab: std.ArrayListUnmanaged(u8) = .empty,
7777/// Version symbol table. Only populated and emitted when linking dynamically.
78versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty,
78versym: std.ArrayListUnmanaged(elf.Versym) = .empty,
7979/// .verneed section
8080verneed: VerneedSection = .{},
8181/// .got section
......@@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,
114114merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,
115115comment_merge_section_index: ?Merge.Section.Index = null,
116116
117first_eflags: ?elf.Elf64_Word = null,
117first_eflags: ?elf.Word = null,
118118
119119const SectionIndexes = struct {
120120 copy_rel: ?u32 = null,
......@@ -265,10 +265,7 @@ pub fn createEmpty(
265265 };
266266
267267 const is_dyn_lib = output_mode == .Lib and link_mode == .dynamic;
268 const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or comp.config.rdynamic)
269 elf.VER_NDX_GLOBAL
270 else
271 elf.VER_NDX_LOCAL;
268 const default_sym_version: elf.Versym = if (is_dyn_lib or comp.config.rdynamic) .GLOBAL else .LOCAL;
272269
273270 // If using LLD to link, this code should produce an object file so that it
274271 // can be passed to LLD.
......@@ -794,58 +791,51 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
794791 // --verbose-link
795792 if (comp.verbose_link) try self.dumpArgv(comp);
796793
797 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self, tid);
794 if (self.zigObjectPtr()) |zig_object| try zig_object.flush(self, tid);
798795 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
799796 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
800797
801798 const csu = try comp.getCrtPaths(arena);
802799
803800 // csu prelude
804 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
805 if (csu.crti) |path| try parseObjectReportingFailure(self, path);
806 if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path);
801 if (csu.crt0) |path| parseObjectReportingFailure(self, path);
802 if (csu.crti) |path| parseObjectReportingFailure(self, path);
803 if (csu.crtbegin) |path| parseObjectReportingFailure(self, path);
807804
808805 for (comp.objects) |obj| {
809 if (obj.isObject()) {
810 try parseObjectReportingFailure(self, obj.path);
811 } else {
812 try parseLibraryReportingFailure(self, .{ .path = obj.path }, obj.must_link);
813 }
806 parseInputReportingFailure(self, obj.path, obj.needed, obj.must_link);
814807 }
815808
816809 // This is a set of object files emitted by clang in a single `build-exe` invocation.
817810 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
818811 // in this set.
819812 for (comp.c_object_table.keys()) |key| {
820 try parseObjectReportingFailure(self, key.status.success.object_path);
813 parseObjectReportingFailure(self, key.status.success.object_path);
821814 }
822815
823 if (module_obj_path) |path| try parseObjectReportingFailure(self, path);
816 if (module_obj_path) |path| parseObjectReportingFailure(self, path);
824817
825 if (comp.config.any_sanitize_thread) try parseCrtFileReportingFailure(self, comp.tsan_lib.?);
826 if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
818 if (comp.config.any_sanitize_thread) parseCrtFileReportingFailure(self, comp.tsan_lib.?);
819 if (comp.config.any_fuzz) parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
827820
828821 // libc
829822 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
830 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
823 if (comp.libc_static_lib) |lib| parseCrtFileReportingFailure(self, lib);
831824 }
832825
833826 for (comp.system_libs.values()) |lib_info| {
834 try self.parseLibraryReportingFailure(.{
835 .needed = lib_info.needed,
836 .path = lib_info.path.?,
837 }, false);
827 parseInputReportingFailure(self, lib_info.path.?, lib_info.needed, false);
838828 }
839829
840830 // libc++ dep
841831 if (comp.config.link_libcpp) {
842 try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);
843 try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);
832 parseInputReportingFailure(self, comp.libcxxabi_static_lib.?.full_object_path, false, false);
833 parseInputReportingFailure(self, comp.libcxx_static_lib.?.full_object_path, false, false);
844834 }
845835
846836 // libunwind dep
847837 if (comp.config.link_libunwind) {
848 try self.parseLibraryReportingFailure(.{ .path = comp.libunwind_static_lib.?.full_object_path }, false);
838 parseInputReportingFailure(self, comp.libunwind_static_lib.?.full_object_path, false, false);
849839 }
850840
851841 // libc dep
......@@ -869,17 +859,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
869859 if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))
870860 break :success;
871861
872 try diags.reportMissingLibraryError(
862 diags.addMissingLibraryError(
873863 checked_paths.items,
874864 "missing system library: '{s}' was not found",
875865 .{lib_name},
876866 );
877
878867 continue;
879868 }
880869
881870 const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));
882 try self.parseLibraryReportingFailure(.{ .path = resolved_path }, false);
871 parseInputReportingFailure(self, resolved_path, false, false);
883872 }
884873 } else if (target.isGnuLibC()) {
885874 for (glibc.libs) |lib| {
......@@ -890,17 +879,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
890879 const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
891880 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
892881 }));
893 try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);
882 parseInputReportingFailure(self, lib_path, false, false);
894883 }
895 try self.parseLibraryReportingFailure(.{
896 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
897 }, false);
884 parseInputReportingFailure(self, try comp.get_libc_crt_file(arena, "libc_nonshared.a"), false, false);
898885 } else if (target.isMusl()) {
899886 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
900887 .static => "libc.a",
901888 .dynamic => "libc.so",
902889 });
903 try self.parseLibraryReportingFailure(.{ .path = path }, false);
890 parseInputReportingFailure(self, path, false, false);
904891 } else {
905892 diags.flags.missing_libc = true;
906893 }
......@@ -912,35 +899,17 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
912899 // to be after the shared libraries, so they are picked up from the shared
913900 // libraries, not libcompiler_rt.
914901 if (comp.compiler_rt_lib) |crt_file| {
915 try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
902 parseInputReportingFailure(self, crt_file.full_object_path, false, false);
916903 } else if (comp.compiler_rt_obj) |crt_file| {
917 try parseObjectReportingFailure(self, crt_file.full_object_path);
904 parseObjectReportingFailure(self, crt_file.full_object_path);
918905 }
919906
920907 // csu postlude
921 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);
922 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);
908 if (csu.crtend) |path| parseObjectReportingFailure(self, path);
909 if (csu.crtn) |path| parseObjectReportingFailure(self, path);
923910
924911 if (diags.hasErrors()) return error.FlushFailure;
925912
926 // Dedup shared objects
927 {
928 var seen_dsos = std.StringHashMap(void).init(gpa);
929 defer seen_dsos.deinit();
930 try seen_dsos.ensureTotalCapacity(@as(u32, @intCast(self.shared_objects.items.len)));
931
932 var i: usize = 0;
933 while (i < self.shared_objects.items.len) {
934 const index = self.shared_objects.items[i];
935 const shared_object = self.file(index).?.shared_object;
936 const soname = shared_object.soname();
937 const gop = seen_dsos.getOrPutAssumeCapacity(soname);
938 if (gop.found_existing) {
939 _ = self.shared_objects.orderedRemove(i);
940 } else i += 1;
941 }
942 }
943
944913 // If we haven't already, create a linker-generated input file comprising of
945914 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
946915 if (self.linker_defined_index == null) {
......@@ -1372,42 +1341,51 @@ pub const ParseError = error{
13721341 UnknownFileType,
13731342} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
13741343
1375fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) error{OutOfMemory}!void {
1376 if (crt_file.isObject()) {
1377 try parseObjectReportingFailure(self, crt_file.full_object_path);
1378 } else {
1379 try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
1380 }
1344fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) void {
1345 parseInputReportingFailure(self, crt_file.full_object_path, false, false);
13811346}
13821347
1383pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {
1384 self.parseObject(path) catch |err| switch (err) {
1385 error.LinkFailure => return, // already reported
1386 error.OutOfMemory => return error.OutOfMemory,
1387 else => |e| try self.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),
1388 };
1348pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_link: bool) void {
1349 const gpa = self.base.comp.gpa;
1350 const diags = &self.base.comp.link_diags;
1351 const target = self.getTarget();
1352
1353 switch (Compilation.classifyFileExt(path.sub_path)) {
1354 .object => parseObjectReportingFailure(self, path),
1355 .shared_library => parseSharedObject(gpa, diags, .{
1356 .path = path,
1357 .needed = needed,
1358 }, &self.shared_objects, &self.files, target) catch |err| switch (err) {
1359 error.LinkFailure => return, // already reported
1360 error.BadMagic, error.UnexpectedEndOfFile => {
1361 // It could be a linker script.
1362 self.parseLdScript(.{ .path = path, .needed = needed }) catch |err2| switch (err2) {
1363 error.LinkFailure => return, // already reported
1364 else => |e| diags.addParseError(path, "failed to parse linker script: {s}", .{@errorName(e)}),
1365 };
1366 },
1367 else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),
1368 },
1369 .static_library => parseArchive(self, path, must_link) catch |err| switch (err) {
1370 error.LinkFailure => return, // already reported
1371 else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
1372 },
1373 .unknown => self.parseLdScript(.{ .path = path, .needed = needed }) catch |err| switch (err) {
1374 error.LinkFailure => return, // already reported
1375 else => |e| diags.addParseError(path, "failed to parse linker script: {s}", .{@errorName(e)}),
1376 },
1377 else => diags.addParseError(path, "unrecognized file type", .{}),
1378 }
13891379}
13901380
1391pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool) error{OutOfMemory}!void {
1392 self.parseLibrary(lib, must_link) catch |err| switch (err) {
1381pub fn parseObjectReportingFailure(self: *Elf, path: Path) void {
1382 const diags = &self.base.comp.link_diags;
1383 self.parseObject(path) catch |err| switch (err) {
13931384 error.LinkFailure => return, // already reported
1394 error.OutOfMemory => return error.OutOfMemory,
1395 else => |e| try self.addParseError(lib.path, "unable to parse library: {s}", .{@errorName(e)}),
1385 else => |e| diags.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),
13961386 };
13971387}
13981388
1399fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
1400 const tracy = trace(@src());
1401 defer tracy.end();
1402 if (try Archive.isArchive(lib.path)) {
1403 try self.parseArchive(lib.path, must_link);
1404 } else if (try SharedObject.isSharedObject(lib.path)) {
1405 try self.parseSharedObject(lib);
1406 } else {
1407 try self.parseLdScript(lib);
1408 }
1409}
1410
14111389fn parseObject(self: *Elf, path: Path) ParseError!void {
14121390 const tracy = trace(@src());
14131391 defer tracy.end();
......@@ -1457,28 +1435,80 @@ fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
14571435 }
14581436}
14591437
1460fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
1438fn parseSharedObject(
1439 gpa: Allocator,
1440 diags: *Diags,
1441 lib: SystemLib,
1442 shared_objects: *std.StringArrayHashMapUnmanaged(File.Index),
1443 files: *std.MultiArrayList(File.Entry),
1444 target: std.Target,
1445) !void {
14611446 const tracy = trace(@src());
14621447 defer tracy.end();
14631448
1464 const gpa = self.base.comp.gpa;
14651449 const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
14661450 defer handle.close();
14671451
1468 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1469 self.files.set(index, .{ .shared_object = .{
1470 .path = .{
1471 .root_dir = lib.path.root_dir,
1472 .sub_path = try gpa.dupe(u8, lib.path.sub_path),
1452 const stat = Stat.fromFs(try handle.stat());
1453 var header = try SharedObject.parseHeader(gpa, diags, lib.path, handle, stat, target);
1454 defer header.deinit(gpa);
1455
1456 const soname = header.soname() orelse lib.path.basename();
1457
1458 const gop = try shared_objects.getOrPut(gpa, soname);
1459 if (gop.found_existing) {
1460 header.deinit(gpa);
1461 return;
1462 }
1463 errdefer _ = shared_objects.pop();
1464
1465 const index: File.Index = @intCast(try files.addOne(gpa));
1466 errdefer _ = files.pop();
1467
1468 gop.value_ptr.* = index;
1469
1470 var parsed = try SharedObject.parse(gpa, &header, handle);
1471 errdefer parsed.deinit(gpa);
1472
1473 const duped_path: Path = .{
1474 .root_dir = lib.path.root_dir,
1475 .sub_path = try gpa.dupe(u8, lib.path.sub_path),
1476 };
1477 errdefer gpa.free(duped_path.sub_path);
1478
1479 files.set(index, .{
1480 .shared_object = .{
1481 .parsed = parsed,
1482 .path = duped_path,
1483 .index = index,
1484 .needed = lib.needed,
1485 .alive = lib.needed,
1486 .aliases = null,
1487 .symbols = .empty,
1488 .symbols_extra = .empty,
1489 .symbols_resolver = .empty,
1490 .output_symtab_ctx = .{},
14731491 },
1474 .index = index,
1475 .needed = lib.needed,
1476 .alive = lib.needed,
1477 } });
1478 try self.shared_objects.append(gpa, index);
1492 });
1493 const so = fileLookup(files.*, index).?.shared_object;
14791494
1480 const shared_object = self.file(index).?.shared_object;
1481 try shared_object.parse(self, handle);
1495 // TODO: save this work for later
1496 const nsyms = parsed.symbols.len;
1497 try so.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
1498 try so.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @typeInfo(Symbol.Extra).@"struct".fields.len);
1499 try so.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
1500 so.symbols_resolver.appendNTimesAssumeCapacity(0, nsyms);
1501
1502 for (parsed.symtab, parsed.symbols, parsed.versyms, 0..) |esym, sym, versym, i| {
1503 const out_sym_index = so.addSymbolAssumeCapacity();
1504 const out_sym = &so.symbols.items[out_sym_index];
1505 out_sym.value = @intCast(esym.st_value);
1506 out_sym.name_offset = sym.mangled_name;
1507 out_sym.ref = .{ .index = 0, .file = 0 };
1508 out_sym.esym_index = @intCast(i);
1509 out_sym.version_index = versym;
1510 out_sym.extra_index = so.addSymbolExtraAssumeCapacity(.{});
1511 }
14821512}
14831513
14841514fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
......@@ -1537,7 +1567,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
15371567 }
15381568 }
15391569
1540 try diags.reportMissingLibraryError(
1570 diags.addMissingLibraryError(
15411571 checked_paths.items,
15421572 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
15431573 .{ @as(Path, lib.path), script_arg.path },
......@@ -1546,26 +1576,16 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
15461576 }
15471577
15481578 const full_path = Path.initCwd(test_path.items);
1549 self.parseLibrary(.{
1550 .needed = script_arg.needed,
1551 .path = full_path,
1552 }, false) catch |err| switch (err) {
1553 error.LinkFailure => continue, // already reported
1554 else => |e| try self.addParseError(
1555 full_path,
1556 "unexpected error: parsing library failed with error {s}",
1557 .{@errorName(e)},
1558 ),
1559 };
1579 parseInputReportingFailure(self, full_path, script_arg.needed, false);
15601580 }
15611581}
15621582
1563pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {
1583pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Word) !void {
15641584 if (self.first_eflags == null) {
15651585 self.first_eflags = e_flags;
15661586 return; // there isn't anything to conflict with yet
15671587 }
1568 const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;
1588 const self_eflags: *elf.Word = &self.first_eflags.?;
15691589
15701590 switch (self.getTarget().cpu.arch) {
15711591 .riscv64 => {
......@@ -1641,11 +1661,14 @@ fn accessLibPath(
16411661/// 5. Remove references to dead objects/shared objects
16421662/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
16431663pub fn resolveSymbols(self: *Elf) !void {
1664 // This function mutates `shared_objects`.
1665 const shared_objects = &self.shared_objects;
1666
16441667 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
16451668 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
16461669 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
16471670 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1648 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1671 for (shared_objects.values()) |index| try self.file(index).?.resolveSymbols(self);
16491672 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
16501673
16511674 // Mark live objects.
......@@ -1662,11 +1685,14 @@ pub fn resolveSymbols(self: *Elf) !void {
16621685 _ = self.objects.orderedRemove(i);
16631686 } else i += 1;
16641687 }
1688 // TODO This loop has 2 major flaws:
1689 // 1. It is O(N^2) which is never allowed in the codebase.
1690 // 2. It mutates shared_objects, which is a non-starter for incremental compilation.
16651691 i = 0;
1666 while (i < self.shared_objects.items.len) {
1667 const index = self.shared_objects.items[i];
1692 while (i < shared_objects.values().len) {
1693 const index = shared_objects.values()[i];
16681694 if (!self.file(index).?.isAlive()) {
1669 _ = self.shared_objects.orderedRemove(i);
1695 _ = shared_objects.orderedRemoveAt(i);
16701696 } else i += 1;
16711697 }
16721698
......@@ -1687,7 +1713,7 @@ pub fn resolveSymbols(self: *Elf) !void {
16871713 // Re-resolve the symbols.
16881714 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
16891715 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
1690 for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
1716 for (shared_objects.values()) |index| try self.file(index).?.resolveSymbols(self);
16911717 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
16921718}
16931719
......@@ -1696,12 +1722,13 @@ pub fn resolveSymbols(self: *Elf) !void {
16961722/// This routine will prune unneeded objects extracted from archives and
16971723/// unneeded shared objects.
16981724fn markLive(self: *Elf) void {
1725 const shared_objects = self.shared_objects.values();
16991726 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
17001727 for (self.objects.items) |index| {
17011728 const file_ptr = self.file(index).?;
17021729 if (file_ptr.isAlive()) file_ptr.markLive(self);
17031730 }
1704 for (self.shared_objects.items) |index| {
1731 for (shared_objects) |index| {
17051732 const file_ptr = self.file(index).?;
17061733 if (file_ptr.isAlive()) file_ptr.markLive(self);
17071734 }
......@@ -1716,6 +1743,7 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {
17161743}
17171744
17181745fn markImportsExports(self: *Elf) void {
1746 const shared_objects = self.shared_objects.values();
17191747 if (self.zigObjectPtr()) |zo| {
17201748 zo.markImportsExports(self);
17211749 }
......@@ -1723,7 +1751,7 @@ fn markImportsExports(self: *Elf) void {
17231751 self.file(index).?.object.markImportsExports(self);
17241752 }
17251753 if (!self.isEffectivelyDynLib()) {
1726 for (self.shared_objects.items) |index| {
1754 for (shared_objects) |index| {
17271755 self.file(index).?.shared_object.markImportExports(self);
17281756 }
17291757 }
......@@ -1744,6 +1772,7 @@ fn claimUnresolved(self: *Elf) void {
17441772/// alloc sections.
17451773fn scanRelocs(self: *Elf) !void {
17461774 const gpa = self.base.comp.gpa;
1775 const shared_objects = self.shared_objects.values();
17471776
17481777 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
17491778 defer {
......@@ -1787,7 +1816,7 @@ fn scanRelocs(self: *Elf) !void {
17871816 for (self.objects.items) |index| {
17881817 try self.file(index).?.createSymbolIndirection(self);
17891818 }
1790 for (self.shared_objects.items) |index| {
1819 for (shared_objects) |index| {
17911820 try self.file(index).?.createSymbolIndirection(self);
17921821 }
17931822 if (self.linkerDefinedPtr()) |obj| {
......@@ -1905,10 +1934,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
19051934 // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.
19061935 const id_symlink_basename = "lld.id";
19071936
1908 var man: Cache.Manifest = undefined;
1937 var man: std.Build.Cache.Manifest = undefined;
19091938 defer if (!self.base.disable_lld_caching) man.deinit();
19101939
1911 var digest: [Cache.hex_digest_len]u8 = undefined;
1940 var digest: [std.Build.Cache.hex_digest_len]u8 = undefined;
19121941
19131942 if (!self.base.disable_lld_caching) {
19141943 man = comp.cache_parent.obtain();
......@@ -1988,7 +2017,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
19882017 digest = man.final();
19892018
19902019 var prev_digest_buf: [digest.len]u8 = undefined;
1991 const prev_digest: []u8 = Cache.readSmallFile(
2020 const prev_digest: []u8 = std.Build.Cache.readSmallFile(
19922021 directory.handle,
19932022 id_symlink_basename,
19942023 &prev_digest_buf,
......@@ -2442,7 +2471,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
24422471 if (!self.base.disable_lld_caching) {
24432472 // Update the file with the digest. If it fails we can continue; it only
24442473 // means that the next invocation will have an unnecessary cache miss.
2445 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
2474 std.Build.Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
24462475 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
24472476 };
24482477 // Again failure here only means an unnecessary cache miss.
......@@ -2899,6 +2928,7 @@ fn initSyntheticSections(self: *Elf) !void {
28992928 const comp = self.base.comp;
29002929 const target = self.getTarget();
29012930 const ptr_size = self.ptrWidthBytes();
2931 const shared_objects = self.shared_objects.values();
29022932
29032933 const needs_eh_frame = blk: {
29042934 if (self.zigObjectPtr()) |zo|
......@@ -3023,7 +3053,7 @@ fn initSyntheticSections(self: *Elf) !void {
30233053 });
30243054 }
30253055
3026 if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
3056 if (self.isEffectivelyDynLib() or shared_objects.len > 0 or comp.config.pie) {
30273057 if (self.section_indexes.dynstrtab == null) {
30283058 self.section_indexes.dynstrtab = try self.addSection(.{
30293059 .name = try self.insertShString(".dynstr"),
......@@ -3072,7 +3102,7 @@ fn initSyntheticSections(self: *Elf) !void {
30723102
30733103 const needs_versions = for (self.dynsym.entries.items) |entry| {
30743104 const sym = self.symbol(entry.ref).?;
3075 if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
3105 if (sym.flags.import and sym.version_index.VERSION > elf.Versym.GLOBAL.VERSION) break true;
30763106 } else false;
30773107 if (needs_versions) {
30783108 if (self.section_indexes.versym == null) {
......@@ -3080,8 +3110,8 @@ fn initSyntheticSections(self: *Elf) !void {
30803110 .name = try self.insertShString(".gnu.version"),
30813111 .flags = elf.SHF_ALLOC,
30823112 .type = elf.SHT_GNU_VERSYM,
3083 .addralign = @alignOf(elf.Elf64_Versym),
3084 .entsize = @sizeOf(elf.Elf64_Versym),
3113 .addralign = @alignOf(elf.Versym),
3114 .entsize = @sizeOf(elf.Versym),
30853115 });
30863116 }
30873117 if (self.section_indexes.verneed == null) {
......@@ -3259,7 +3289,9 @@ fn sortInitFini(self: *Elf) !void {
32593289fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
32603290 if (self.section_indexes.dynamic == null) return;
32613291
3262 for (self.shared_objects.items) |index| {
3292 const shared_objects = self.shared_objects.values();
3293
3294 for (shared_objects) |index| {
32633295 const shared_object = self.file(index).?.shared_object;
32643296 if (!shared_object.alive) continue;
32653297 try self.dynamic.addNeeded(shared_object, self);
......@@ -3283,7 +3315,7 @@ fn setVersionSymtab(self: *Elf) !void {
32833315 const gpa = self.base.comp.gpa;
32843316 if (self.section_indexes.versym == null) return;
32853317 try self.versym.resize(gpa, self.dynsym.count());
3286 self.versym.items[0] = elf.VER_NDX_LOCAL;
3318 self.versym.items[0] = .LOCAL;
32873319 for (self.dynsym.entries.items, 1..) |entry, i| {
32883320 const sym = self.symbol(entry.ref).?;
32893321 self.versym.items[i] = sym.version_index;
......@@ -3653,7 +3685,7 @@ fn updateSectionSizes(self: *Elf) !void {
36533685 }
36543686
36553687 if (self.section_indexes.versym) |index| {
3656 shdrs[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
3688 shdrs[index].sh_size = self.versym.items.len * @sizeOf(elf.Versym);
36573689 }
36583690
36593691 if (self.section_indexes.verneed) |index| {
......@@ -4055,13 +4087,15 @@ pub fn updateSymtabSize(self: *Elf) !void {
40554087 var strsize: u32 = 0;
40564088
40574089 const gpa = self.base.comp.gpa;
4090 const shared_objects = self.shared_objects.values();
4091
40584092 var files = std.ArrayList(File.Index).init(gpa);
40594093 defer files.deinit();
4060 try files.ensureTotalCapacityPrecise(self.objects.items.len + self.shared_objects.items.len + 2);
4094 try files.ensureTotalCapacityPrecise(self.objects.items.len + shared_objects.len + 2);
40614095
40624096 if (self.zig_object_index) |index| files.appendAssumeCapacity(index);
40634097 for (self.objects.items) |index| files.appendAssumeCapacity(index);
4064 for (self.shared_objects.items) |index| files.appendAssumeCapacity(index);
4098 for (shared_objects) |index| files.appendAssumeCapacity(index);
40654099 if (self.linker_defined_index) |index| files.appendAssumeCapacity(index);
40664100
40674101 // Section symbols
......@@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void {
42844318
42854319pub fn writeSymtab(self: *Elf) !void {
42864320 const gpa = self.base.comp.gpa;
4321 const shared_objects = self.shared_objects.values();
4322
42874323 const slice = self.sections.slice();
42884324 const symtab_shdr = slice.items(.shdr)[self.section_indexes.symtab.?];
42894325 const strtab_shdr = slice.items(.shdr)[self.section_indexes.strtab.?];
......@@ -4335,7 +4371,7 @@ pub fn writeSymtab(self: *Elf) !void {
43354371 file_ptr.writeSymtab(self);
43364372 }
43374373
4338 for (self.shared_objects.items) |index| {
4374 for (shared_objects) |index| {
43394375 const file_ptr = self.file(index).?;
43404376 file_ptr.writeSymtab(self);
43414377 }
......@@ -4368,8 +4404,8 @@ pub fn writeSymtab(self: *Elf) !void {
43684404 .st_info = sym.st_info,
43694405 .st_other = sym.st_other,
43704406 .st_shndx = sym.st_shndx,
4371 .st_value = @as(u32, @intCast(sym.st_value)),
4372 .st_size = @as(u32, @intCast(sym.st_size)),
4407 .st_value = @intCast(sym.st_value),
4408 .st_size = @intCast(sym.st_size),
43734409 };
43744410 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
43754411 }
......@@ -4925,18 +4961,6 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
49254961 });
49264962}
49274963
4928pub fn addParseError(
4929 self: *Elf,
4930 path: Path,
4931 comptime format: []const u8,
4932 args: anytype,
4933) error{OutOfMemory}!void {
4934 const diags = &self.base.comp.link_diags;
4935 var err = try diags.addErrorWithNotes(1);
4936 try err.addMsg(format, args);
4937 try err.addNote("while parsing {}", .{path});
4938}
4939
49404964pub fn addFileError(
49414965 self: *Elf,
49424966 file_index: File.Index,
......@@ -4959,16 +4983,6 @@ pub fn failFile(
49594983 return error.LinkFailure;
49604984}
49614985
4962pub fn failParse(
4963 self: *Elf,
4964 path: Path,
4965 comptime format: []const u8,
4966 args: anytype,
4967) error{ OutOfMemory, LinkFailure } {
4968 try addParseError(self, path, format, args);
4969 return error.LinkFailure;
4970}
4971
49724986const FormatShdrCtx = struct {
49734987 elf_file: *Elf,
49744988 shdr: elf.Elf64_Shdr,
......@@ -5113,6 +5127,8 @@ fn fmtDumpState(
51135127 _ = unused_fmt_string;
51145128 _ = options;
51155129
5130 const shared_objects = self.shared_objects.values();
5131
51165132 if (self.zigObjectPtr()) |zig_object| {
51175133 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
51185134 try writer.print("{}{}", .{
......@@ -5136,11 +5152,11 @@ fn fmtDumpState(
51365152 });
51375153 }
51385154
5139 for (self.shared_objects.items) |index| {
5155 for (shared_objects) |index| {
51405156 const shared_object = self.file(index).?.shared_object;
5141 try writer.print("shared_object({d}) : ", .{index});
5142 try writer.print("{}", .{shared_object.path});
5143 try writer.print(" : needed({})", .{shared_object.needed});
5157 try writer.print("shared_object({d}) : {} : needed({})", .{
5158 index, shared_object.path, shared_object.needed,
5159 });
51445160 if (!shared_object.alive) try writer.writeAll(" : [*]");
51455161 try writer.writeByte('\n');
51465162 try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
......@@ -5204,10 +5220,7 @@ pub fn preadAllAlloc(allocator: Allocator, handle: fs.File, offset: u64, size: u
52045220}
52055221
52065222/// Binary search
5207pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
5208 if (!@hasDecl(@TypeOf(predicate), "predicate"))
5209 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
5210
5223pub fn bsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
52115224 var min: usize = 0;
52125225 var max: usize = haystack.len;
52135226 while (min < max) {
......@@ -5223,10 +5236,7 @@ pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp
52235236}
52245237
52255238/// Linear search
5226pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
5227 if (!@hasDecl(@TypeOf(predicate), "predicate"))
5228 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
5229
5239pub fn lsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
52305240 var i: usize = 0;
52315241 while (i < haystack.len) : (i += 1) {
52325242 if (predicate.predicate(haystack[i])) break;
......@@ -5569,6 +5579,11 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
55695579 }
55705580}
55715581
5582pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 {
5583 const slice = strtab[off..];
5584 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
5585}
5586
55725587const std = @import("std");
55735588const build_options = @import("build_options");
55745589const builtin = @import("builtin");
......@@ -5581,8 +5596,9 @@ const state_log = std.log.scoped(.link_state);
55815596const math = std.math;
55825597const mem = std.mem;
55835598const Allocator = std.mem.Allocator;
5584const Cache = std.Build.Cache;
55855599const Hash = std.hash.Wyhash;
5600const Path = std.Build.Cache.Path;
5601const Stat = std.Build.Cache.File.Stat;
55865602
55875603const codegen = @import("../codegen.zig");
55885604const dev = @import("../dev.zig");
......@@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig");
56015617const Air = @import("../Air.zig");
56025618const Archive = @import("Elf/Archive.zig");
56035619const AtomList = @import("Elf/AtomList.zig");
5604const Path = Cache.Path;
56055620const Compilation = @import("../Compilation.zig");
56065621const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
56075622const CopyRelSection = synthetic_sections.CopyRelSection;
5623const Diags = @import("../link.zig").Diags;
56085624const DynamicSection = synthetic_sections.DynamicSection;
56095625const DynsymSection = synthetic_sections.DynsymSection;
56105626const Dwarf = @import("Dwarf.zig");
src/link/Elf/Archive.zig+2-10
......@@ -1,15 +1,6 @@
11objects: std.ArrayListUnmanaged(Object) = .empty,
22strtab: std.ArrayListUnmanaged(u8) = .empty,
33
4pub fn isArchive(path: Path) !bool {
5 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
6 defer file.close();
7 const reader = file.reader();
8 const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;
9 if (!mem.eql(u8, &magic, elf.ARMAG)) return false;
10 return true;
11}
12
134pub fn deinit(self: *Archive, allocator: Allocator) void {
145 self.objects.deinit(allocator);
156 self.strtab.deinit(allocator);
......@@ -18,6 +9,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
189pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
1910 const comp = elf_file.base.comp;
2011 const gpa = comp.gpa;
12 const diags = &comp.link_diags;
2113 const handle = elf_file.fileHandle(handle_index);
2214 const size = (try handle.stat()).size;
2315
......@@ -35,7 +27,7 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
3527 pos += @sizeOf(elf.ar_hdr);
3628
3729 if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
38 return elf_file.failParse(path, "invalid archive header delimiter: {s}", .{
30 return diags.failParse(path, "invalid archive header delimiter: {s}", .{
3931 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
4032 });
4133 }
src/link/Elf/Atom.zig+1
......@@ -592,6 +592,7 @@ fn reportUndefined(
592592 const file_ptr = self.file(elf_file).?;
593593 const rel_esym = switch (file_ptr) {
594594 .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),
595 .shared_object => |so| so.parsed.symtab[rel.r_sym()],
595596 inline else => |x| x.symtab.items[rel.r_sym()],
596597 };
597598 const esym = sym.elfSym(elf_file);
src/link/Elf/LdScript.zig+4-2
......@@ -21,6 +21,8 @@ pub const Error = error{
2121pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
2222 const comp = elf_file.base.comp;
2323 const gpa = comp.gpa;
24 const diags = &comp.link_diags;
25
2426 var tokenizer = Tokenizer{ .source = data };
2527 var tokens = std.ArrayList(Token).init(gpa);
2628 defer tokens.deinit();
......@@ -37,7 +39,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
3739 try line_col.append(.{ .line = line, .column = column });
3840 switch (tok.id) {
3941 .invalid => {
40 return elf_file.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
42 return diags.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
4143 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
4244 });
4345 },
......@@ -61,7 +63,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
6163 const last_token_id = parser.it.pos - 1;
6264 const last_token = parser.it.get(last_token_id);
6365 const lcol = line_col.items[last_token_id];
64 return elf_file.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
66 return diags.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
6567 @tagName(last_token.id),
6668 last_token.get(data),
6769 lcol.line,
src/link/Elf/Object.zig+5-4
......@@ -310,7 +310,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
310310 sym_ptr.name_offset = sym.st_name;
311311 sym_ptr.esym_index = @intCast(i);
312312 sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
313 sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL;
313 sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else .LOCAL;
314314 sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
315315 if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
316316 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
......@@ -536,7 +536,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
536536 sym.ref = .{ .index = 0, .file = 0 };
537537 sym.esym_index = esym_index;
538538 sym.file_index = self.index;
539 sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
539 sym.version_index = if (is_import) .LOCAL else elf_file.default_sym_version;
540540 sym.flags.import = is_import;
541541
542542 const idx = self.symbols_resolver.items[i];
......@@ -598,8 +598,9 @@ pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
598598 const ref = self.resolveSymbol(@intCast(idx), elf_file);
599599 const sym = elf_file.symbol(ref) orelse continue;
600600 const file = sym.file(elf_file).?;
601 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
602 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
601 // https://github.com/ziglang/zig/issues/21678
602 if (@as(u16, @bitCast(sym.version_index)) == @as(u16, @bitCast(elf.Versym.LOCAL))) continue;
603 const vis: elf.STV = @enumFromInt(sym.elfSym(elf_file).st_other);
603604 if (vis == .HIDDEN) continue;
604605 if (file == .shared_object and !sym.isAbs(elf_file)) {
605606 sym.flags.import = true;
src/link/Elf/SharedObject.zig+281-227
......@@ -1,236 +1,316 @@
11path: Path,
22index: File.Index,
33
4header: ?elf.Elf64_Ehdr = null,
5shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .empty,
4parsed: Parsed,
65
7symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty,
8strtab: std.ArrayListUnmanaged(u8) = .empty,
9/// Version symtab contains version strings of the symbols if present.
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty,
11verstrings: std.ArrayListUnmanaged(u32) = .empty,
6symbols: std.ArrayListUnmanaged(Symbol),
7symbols_extra: std.ArrayListUnmanaged(u32),
8symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index),
129
13symbols: std.ArrayListUnmanaged(Symbol) = .empty,
14symbols_extra: std.ArrayListUnmanaged(u32) = .empty,
15symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .empty,
16
17aliases: ?std.ArrayListUnmanaged(u32) = null,
18dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .empty,
10aliases: ?std.ArrayListUnmanaged(u32),
1911
2012needed: bool,
2113alive: bool,
2214
23output_symtab_ctx: Elf.SymtabCtx = .{},
24
25pub fn isSharedObject(path: Path) !bool {
26 const file = try path.root_dir.handle.openFile(path.sub_path, .{});
27 defer file.close();
28 const reader = file.reader();
29 const header = reader.readStruct(elf.Elf64_Ehdr) catch return false;
30 if (!mem.eql(u8, header.e_ident[0..4], "\x7fELF")) return false;
31 if (header.e_ident[elf.EI_VERSION] != 1) return false;
32 if (header.e_type != elf.ET.DYN) return false;
33 return true;
34}
15output_symtab_ctx: Elf.SymtabCtx,
3516
36pub fn deinit(self: *SharedObject, allocator: Allocator) void {
37 allocator.free(self.path.sub_path);
38 self.shdrs.deinit(allocator);
39 self.symtab.deinit(allocator);
40 self.strtab.deinit(allocator);
41 self.versyms.deinit(allocator);
42 self.verstrings.deinit(allocator);
43 self.symbols.deinit(allocator);
44 self.symbols_extra.deinit(allocator);
45 self.symbols_resolver.deinit(allocator);
46 if (self.aliases) |*aliases| aliases.deinit(allocator);
47 self.dynamic_table.deinit(allocator);
17pub fn deinit(so: *SharedObject, gpa: Allocator) void {
18 gpa.free(so.path.sub_path);
19 so.parsed.deinit(gpa);
20 so.symbols.deinit(gpa);
21 so.symbols_extra.deinit(gpa);
22 so.symbols_resolver.deinit(gpa);
23 if (so.aliases) |*aliases| aliases.deinit(gpa);
24 so.* = undefined;
4825}
4926
50pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
51 const comp = elf_file.base.comp;
52 const gpa = comp.gpa;
53 const file_size = (try handle.stat()).size;
27pub const Header = struct {
28 dynamic_table: []const elf.Elf64_Dyn,
29 soname_index: ?u32,
30 verdefnum: ?u32,
5431
55 const header_buffer = try Elf.preadAllAlloc(gpa, handle, 0, @sizeOf(elf.Elf64_Ehdr));
56 defer gpa.free(header_buffer);
57 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
32 sections: []const elf.Elf64_Shdr,
33 dynsym_sect_index: ?u32,
34 versym_sect_index: ?u32,
35 verdef_sect_index: ?u32,
5836
59 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();
60 if (em != self.header.?.e_machine) {
61 return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{
62 @tagName(self.header.?.e_machine),
63 });
37 stat: Stat,
38 strtab: std.ArrayListUnmanaged(u8),
39
40 pub fn deinit(header: *Header, gpa: Allocator) void {
41 gpa.free(header.sections);
42 gpa.free(header.dynamic_table);
43 header.strtab.deinit(gpa);
44 header.* = undefined;
45 }
46
47 pub fn soname(header: Header) ?[]const u8 {
48 const i = header.soname_index orelse return null;
49 return Elf.stringTableLookup(header.strtab.items, i);
50 }
51};
52
53pub const Parsed = struct {
54 stat: Stat,
55 strtab: []const u8,
56 soname_index: ?u32,
57 sections: []const elf.Elf64_Shdr,
58
59 /// Nonlocal symbols only.
60 symtab: []const elf.Elf64_Sym,
61 /// Version symtab contains version strings of the symbols if present.
62 /// Nonlocal symbols only.
63 versyms: []const elf.Versym,
64 /// Nonlocal symbols only.
65 symbols: []const Parsed.Symbol,
66
67 verstrings: []const u32,
68
69 const Symbol = struct {
70 mangled_name: u32,
71 };
72
73 pub fn deinit(p: *Parsed, gpa: Allocator) void {
74 gpa.free(p.strtab);
75 gpa.free(p.symtab);
76 gpa.free(p.versyms);
77 gpa.free(p.symbols);
78 gpa.free(p.verstrings);
79 p.* = undefined;
80 }
81
82 pub fn versionString(p: Parsed, index: elf.Versym) [:0]const u8 {
83 return versionStringLookup(p.strtab, p.verstrings, index);
6484 }
6585
66 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
67 const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
68 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
69 if (file_size < shoff or file_size < shoff + shsize) {
70 return elf_file.failFile(self.index, "corrupted header: section header table extends past the end of file", .{});
86 pub fn soname(p: Parsed) ?[]const u8 {
87 const i = p.soname_index orelse return null;
88 return Elf.stringTableLookup(p.strtab, i);
7189 }
90};
7291
73 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize);
74 defer gpa.free(shdrs_buffer);
75 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
76 try self.shdrs.appendUnalignedSlice(gpa, shdrs);
92pub fn parseHeader(
93 gpa: Allocator,
94 diags: *Diags,
95 file_path: Path,
96 fs_file: std.fs.File,
97 stat: Stat,
98 target: std.Target,
99) !Header {
100 var ehdr: elf.Elf64_Ehdr = undefined;
101 {
102 const buf = mem.asBytes(&ehdr);
103 const amt = try fs_file.preadAll(buf, 0);
104 if (amt != buf.len) return error.UnexpectedEndOfFile;
105 }
106 if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic;
107 if (ehdr.e_ident[elf.EI_VERSION] != 1) return error.BadElfVersion;
108 if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject;
109
110 if (target.toElfMachine() != ehdr.e_machine)
111 return diags.failParse(file_path, "invalid ELF machine type: {s}", .{@tagName(ehdr.e_machine)});
112
113 const shoff = std.math.cast(usize, ehdr.e_shoff) orelse return error.Overflow;
114 const shnum = std.math.cast(u32, ehdr.e_shnum) orelse return error.Overflow;
115
116 const sections = try gpa.alloc(elf.Elf64_Shdr, shnum);
117 errdefer gpa.free(sections);
118 {
119 const buf = mem.sliceAsBytes(sections);
120 const amt = try fs_file.preadAll(buf, shoff);
121 if (amt != buf.len) return error.UnexpectedEndOfFile;
122 }
77123
78124 var dynsym_sect_index: ?u32 = null;
79125 var dynamic_sect_index: ?u32 = null;
80126 var versym_sect_index: ?u32 = null;
81127 var verdef_sect_index: ?u32 = null;
82 for (self.shdrs.items, 0..) |shdr, i| {
83 if (shdr.sh_type != elf.SHT_NOBITS) {
84 if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) {
85 return elf_file.failFile(self.index, "corrupted section header", .{});
86 }
87 }
128 for (sections, 0..) |shdr, i_usize| {
129 const i: u32 = @intCast(i_usize);
88130 switch (shdr.sh_type) {
89 elf.SHT_DYNSYM => dynsym_sect_index = @intCast(i),
90 elf.SHT_DYNAMIC => dynamic_sect_index = @intCast(i),
91 elf.SHT_GNU_VERSYM => versym_sect_index = @intCast(i),
92 elf.SHT_GNU_VERDEF => verdef_sect_index = @intCast(i),
93 else => {},
131 elf.SHT_DYNSYM => dynsym_sect_index = i,
132 elf.SHT_DYNAMIC => dynamic_sect_index = i,
133 elf.SHT_GNU_VERSYM => versym_sect_index = i,
134 elf.SHT_GNU_VERDEF => verdef_sect_index = i,
135 else => continue,
94136 }
95137 }
96138
97 if (dynamic_sect_index) |index| {
98 const shdr = self.shdrs.items[index];
99 const raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
100 defer gpa.free(raw);
101 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn));
102 const dyntab = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num];
103 try self.dynamic_table.appendUnalignedSlice(gpa, dyntab);
139 const dynamic_table: []elf.Elf64_Dyn = if (dynamic_sect_index) |index| dt: {
140 const shdr = sections[index];
141 const n = shdr.sh_size / @sizeOf(elf.Elf64_Dyn);
142 const dynamic_table = try gpa.alloc(elf.Elf64_Dyn, n);
143 errdefer gpa.free(dynamic_table);
144 const buf = mem.sliceAsBytes(dynamic_table);
145 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
146 if (amt != buf.len) return error.UnexpectedEndOfFile;
147 break :dt dynamic_table;
148 } else &.{};
149 errdefer gpa.free(dynamic_table);
150
151 var strtab: std.ArrayListUnmanaged(u8) = .empty;
152 errdefer strtab.deinit(gpa);
153
154 if (dynsym_sect_index) |index| {
155 const dynsym_shdr = sections[index];
156 if (dynsym_shdr.sh_link >= sections.len) return error.BadStringTableIndex;
157 const strtab_shdr = sections[dynsym_shdr.sh_link];
158 const buf = try strtab.addManyAsSlice(gpa, strtab_shdr.sh_size);
159 const amt = try fs_file.preadAll(buf, strtab_shdr.sh_offset);
160 if (amt != buf.len) return error.UnexpectedEndOfFile;
104161 }
105162
106 const symtab = if (dynsym_sect_index) |index| blk: {
107 const shdr = self.shdrs.items[index];
108 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
109 const nsyms = @divExact(buffer.len, @sizeOf(elf.Elf64_Sym));
110 break :blk @as([*]align(1) const elf.Elf64_Sym, @ptrCast(buffer.ptr))[0..nsyms];
111 } else &[0]elf.Elf64_Sym{};
112 defer gpa.free(symtab);
113
114 const strtab = if (dynsym_sect_index) |index| blk: {
115 const symtab_shdr = self.shdrs.items[index];
116 const shdr = self.shdrs.items[symtab_shdr.sh_link];
117 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
118 break :blk buffer;
119 } else &[0]u8{};
120 defer gpa.free(strtab);
163 var soname_index: ?u32 = null;
164 var verdefnum: ?u32 = null;
165 for (dynamic_table) |entry| switch (entry.d_tag) {
166 elf.DT_SONAME => {
167 if (entry.d_val >= strtab.items.len) return error.BadSonameIndex;
168 soname_index = @intCast(entry.d_val);
169 },
170 elf.DT_VERDEFNUM => {
171 verdefnum = @intCast(entry.d_val);
172 },
173 else => continue,
174 };
121175
122 try self.parseVersions(elf_file, handle, .{
123 .symtab = symtab,
124 .verdef_sect_index = verdef_sect_index,
176 return .{
177 .dynamic_table = dynamic_table,
178 .soname_index = soname_index,
179 .verdefnum = verdefnum,
180 .sections = sections,
181 .dynsym_sect_index = dynsym_sect_index,
125182 .versym_sect_index = versym_sect_index,
126 });
127
128 try self.initSymbols(elf_file, .{
129 .symtab = symtab,
183 .verdef_sect_index = verdef_sect_index,
130184 .strtab = strtab,
131 });
185 .stat = stat,
186 };
132187}
133188
134fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct {
135 symtab: []align(1) const elf.Elf64_Sym,
136 verdef_sect_index: ?u32,
137 versym_sect_index: ?u32,
138}) !void {
139 const comp = elf_file.base.comp;
140 const gpa = comp.gpa;
189pub fn parse(
190 gpa: Allocator,
191 /// Moves resources from header. Caller may unconditionally deinit.
192 header: *Header,
193 fs_file: std.fs.File,
194) !Parsed {
195 const symtab = if (header.dynsym_sect_index) |index| st: {
196 const shdr = header.sections[index];
197 const n = shdr.sh_size / @sizeOf(elf.Elf64_Sym);
198 const symtab = try gpa.alloc(elf.Elf64_Sym, n);
199 errdefer gpa.free(symtab);
200 const buf = mem.sliceAsBytes(symtab);
201 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
202 if (amt != buf.len) return error.UnexpectedEndOfFile;
203 break :st symtab;
204 } else &.{};
205 defer gpa.free(symtab);
141206
142 try self.verstrings.resize(gpa, 2);
143 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;
144 self.verstrings.items[elf.VER_NDX_GLOBAL] = 0;
207 var verstrings: std.ArrayListUnmanaged(u32) = .empty;
208 defer verstrings.deinit(gpa);
145209
146 if (opts.verdef_sect_index) |shndx| {
147 const shdr = self.shdrs.items[shndx];
148 const verdefs = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
210 if (header.verdef_sect_index) |shndx| {
211 const shdr = header.sections[shndx];
212 const verdefs = try Elf.preadAllAlloc(gpa, fs_file, shdr.sh_offset, shdr.sh_size);
149213 defer gpa.free(verdefs);
150 const nverdefs = self.verdefNum();
151 try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs);
152214
153 var i: u32 = 0;
154215 var offset: u32 = 0;
155 while (i < nverdefs) : (i += 1) {
156 const verdef = @as(*align(1) const elf.Elf64_Verdef, @ptrCast(verdefs.ptr + offset)).*;
157 defer offset += verdef.vd_next;
158 if (verdef.vd_flags == elf.VER_FLG_BASE) continue; // Skip BASE entry
159 const vda_name = if (verdef.vd_cnt > 0)
160 @as(*align(1) const elf.Elf64_Verdaux, @ptrCast(verdefs.ptr + offset + verdef.vd_aux)).vda_name
161 else
162 0;
163 self.verstrings.items[verdef.vd_ndx] = vda_name;
164 }
165 }
216 while (true) {
217 const verdef = mem.bytesAsValue(elf.Verdef, verdefs[offset..][0..@sizeOf(elf.Verdef)]);
218 if (verdef.ndx == .UNSPECIFIED) return error.VerDefSymbolTooLarge;
219
220 if (verstrings.items.len <= @intFromEnum(verdef.ndx))
221 try verstrings.appendNTimes(gpa, 0, @intFromEnum(verdef.ndx) + 1 - verstrings.items.len);
166222
167 try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
168
169 if (opts.versym_sect_index) |shndx| {
170 const shdr = self.shdrs.items[shndx];
171 const versyms_raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);
172 defer gpa.free(versyms_raw);
173 const nversyms = @divExact(versyms_raw.len, @sizeOf(elf.Elf64_Versym));
174 const versyms = @as([*]align(1) const elf.Elf64_Versym, @ptrCast(versyms_raw.ptr))[0..nversyms];
175 for (versyms) |ver| {
176 const normalized_ver = if (ver & elf.VERSYM_VERSION >= self.verstrings.items.len - 1)
177 elf.VER_NDX_GLOBAL
178 else
179 ver;
180 self.versyms.appendAssumeCapacity(normalized_ver);
223 const aux = mem.bytesAsValue(elf.Verdaux, verdefs[offset + verdef.aux ..][0..@sizeOf(elf.Verdaux)]);
224 verstrings.items[@intFromEnum(verdef.ndx)] = aux.name;
225
226 if (verdef.next == 0) break;
227 offset += verdef.next;
181228 }
182 } else for (0..opts.symtab.len) |_| {
183 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
184229 }
185}
186230
187fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct {
188 symtab: []align(1) const elf.Elf64_Sym,
189 strtab: []const u8,
190}) !void {
191 const gpa = elf_file.base.comp.gpa;
192 const nsyms = opts.symtab.len;
193
194 try self.strtab.appendSlice(gpa, opts.strtab);
195 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
196 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
197 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
198 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
199 self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
200 @memset(self.symbols_resolver.items, 0);
201
202 for (opts.symtab, 0..) |sym, i| {
203 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
204 const name = self.getString(sym.st_name);
205 // We need to garble up the name so that we don't pick this symbol
206 // during symbol resolution. Thank you GNU!
207 const name_off = if (hidden) blk: {
208 const mangled = try std.fmt.allocPrint(gpa, "{s}@{s}", .{
209 name,
210 self.versionString(self.versyms.items[i]),
211 });
212 defer gpa.free(mangled);
213 break :blk try self.addString(gpa, mangled);
214 } else sym.st_name;
215 const out_esym_index: u32 = @intCast(self.symtab.items.len);
216 const out_esym = self.symtab.addOneAssumeCapacity();
217 out_esym.* = sym;
218 out_esym.st_name = name_off;
219 const out_sym_index = self.addSymbolAssumeCapacity();
220 const out_sym = &self.symbols.items[out_sym_index];
221 out_sym.value = @intCast(out_esym.st_value);
222 out_sym.name_offset = name_off;
223 out_sym.ref = .{ .index = 0, .file = 0 };
224 out_sym.esym_index = out_esym_index;
225 out_sym.version_index = self.versyms.items[out_esym_index];
226 out_sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
231 const versyms = if (header.versym_sect_index) |versym_sect_index| vs: {
232 const shdr = header.sections[versym_sect_index];
233 if (shdr.sh_size != symtab.len * @sizeOf(elf.Versym)) return error.BadVerSymSectionSize;
234
235 const versyms = try gpa.alloc(elf.Versym, symtab.len);
236 errdefer gpa.free(versyms);
237 const buf = mem.sliceAsBytes(versyms);
238 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
239 if (amt != buf.len) return error.UnexpectedEndOfFile;
240 break :vs versyms;
241 } else &.{};
242 defer gpa.free(versyms);
243
244 var nonlocal_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty;
245 defer nonlocal_esyms.deinit(gpa);
246
247 var nonlocal_versyms: std.ArrayListUnmanaged(elf.Versym) = .empty;
248 defer nonlocal_versyms.deinit(gpa);
249
250 var nonlocal_symbols: std.ArrayListUnmanaged(Parsed.Symbol) = .empty;
251 defer nonlocal_symbols.deinit(gpa);
252
253 var strtab = header.strtab;
254 header.strtab = .empty;
255 defer strtab.deinit(gpa);
256
257 for (symtab, 0..) |sym, i| {
258 const ver: elf.Versym = if (versyms.len == 0 or sym.st_shndx == elf.SHN_UNDEF)
259 .GLOBAL
260 else
261 .{ .VERSION = versyms[i].VERSION, .HIDDEN = false };
262
263 // https://github.com/ziglang/zig/issues/21678
264 //if (ver == .LOCAL) continue;
265 if (@as(u16, @bitCast(ver)) == 0) continue;
266
267 try nonlocal_esyms.ensureUnusedCapacity(gpa, 1);
268 try nonlocal_versyms.ensureUnusedCapacity(gpa, 1);
269 try nonlocal_symbols.ensureUnusedCapacity(gpa, 1);
270
271 const name = Elf.stringTableLookup(strtab.items, sym.st_name);
272 const is_default = versyms.len == 0 or !versyms[i].HIDDEN;
273 const mangled_name = if (is_default) sym.st_name else mn: {
274 const off: u32 = @intCast(strtab.items.len);
275 const version_string = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
276 try strtab.ensureUnusedCapacity(gpa, name.len + version_string.len + 2);
277 // Reload since the string table might have been resized.
278 const name2 = Elf.stringTableLookup(strtab.items, sym.st_name);
279 const version_string2 = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
280 strtab.appendSliceAssumeCapacity(name2);
281 strtab.appendAssumeCapacity('@');
282 strtab.appendSliceAssumeCapacity(version_string2);
283 strtab.appendAssumeCapacity(0);
284 break :mn off;
285 };
286
287 nonlocal_esyms.appendAssumeCapacity(sym);
288 nonlocal_versyms.appendAssumeCapacity(ver);
289 nonlocal_symbols.appendAssumeCapacity(.{
290 .mangled_name = mangled_name,
291 });
227292 }
293
294 const sections = header.sections;
295 header.sections = &.{};
296 errdefer gpa.free(sections);
297
298 return .{
299 .sections = sections,
300 .stat = header.stat,
301 .soname_index = header.soname_index,
302 .strtab = try strtab.toOwnedSlice(gpa),
303 .symtab = try nonlocal_esyms.toOwnedSlice(gpa),
304 .versyms = try nonlocal_versyms.toOwnedSlice(gpa),
305 .symbols = try nonlocal_symbols.toOwnedSlice(gpa),
306 .verstrings = try verstrings.toOwnedSlice(gpa),
307 };
228308}
229309
230310pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
231311 const gpa = elf_file.base.comp.gpa;
232312
233 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
313 for (self.parsed.symtab, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
234314 const gop = try elf_file.resolver.getOrPut(gpa, .{
235315 .index = @intCast(i),
236316 .file = self.index,
......@@ -253,7 +333,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
253333}
254334
255335pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
256 for (self.symtab.items, 0..) |esym, i| {
336 for (self.parsed.symtab, 0..) |esym, i| {
257337 if (esym.st_shndx != elf.SHN_UNDEF) continue;
258338
259339 const ref = self.resolveSymbol(@intCast(i), elf_file);
......@@ -308,29 +388,21 @@ pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
308388 }
309389}
310390
311pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {
312 const off = self.verstrings.items[index & elf.VERSYM_VERSION];
313 return self.getString(off);
391pub fn versionString(self: SharedObject, index: elf.Versym) [:0]const u8 {
392 return self.parsed.versionString(index);
314393}
315394
316pub fn asFile(self: *SharedObject) File {
317 return .{ .shared_object = self };
395fn versionStringLookup(strtab: []const u8, verstrings: []const u32, index: elf.Versym) [:0]const u8 {
396 const off = verstrings[index.VERSION];
397 return Elf.stringTableLookup(strtab, off);
318398}
319399
320fn verdefNum(self: *SharedObject) u32 {
321 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
322 elf.DT_VERDEFNUM => return @intCast(entry.d_val),
323 else => {},
324 };
325 return 0;
400pub fn asFile(self: *SharedObject) File {
401 return .{ .shared_object = self };
326402}
327403
328404pub fn soname(self: *SharedObject) []const u8 {
329 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {
330 elf.DT_SONAME => return self.getString(@intCast(entry.d_val)),
331 else => {},
332 };
333 return std.fs.path.basename(self.path.sub_path);
405 return self.parsed.soname() orelse self.path.basename();
334406}
335407
336408pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
......@@ -360,7 +432,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
360432 aliases.appendAssumeCapacity(@intCast(index));
361433 }
362434
363 std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
435 mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
364436
365437 self.aliases = aliases.moveToUnmanaged();
366438}
......@@ -384,17 +456,8 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
384456 return aliases.items[start..end];
385457}
386458
387fn addString(self: *SharedObject, allocator: Allocator, str: []const u8) !u32 {
388 const off: u32 = @intCast(self.strtab.items.len);
389 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
390 self.strtab.appendSliceAssumeCapacity(str);
391 self.strtab.appendAssumeCapacity(0);
392 return off;
393}
394
395459pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
396 assert(off < self.strtab.items.len);
397 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
460 return Elf.stringTableLookup(self.parsed.strtab, off);
398461}
399462
400463pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
......@@ -402,25 +465,14 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El
402465 return elf_file.resolver.get(resolv).?;
403466}
404467
405fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index {
406 try self.symbols.ensureUnusedCapacity(allocator, 1);
407 return self.addSymbolAssumeCapacity();
408}
409
410fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
468pub fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
411469 const index: Symbol.Index = @intCast(self.symbols.items.len);
412470 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
413471 return index;
414472}
415473
416pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
417 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
418 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
419 return self.addSymbolExtraAssumeCapacity(extra);
420}
421
422474pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
423 const index = @as(u32, @intCast(self.symbols_extra.items.len));
475 const index: u32 = @intCast(self.symbols_extra.items.len);
424476 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
425477 inline for (fields) |field| {
426478 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
......@@ -465,7 +517,7 @@ pub fn format(
465517 _ = unused_fmt_string;
466518 _ = options;
467519 _ = writer;
468 @compileError("do not format shared objects directly");
520 @compileError("unreachable");
469521}
470522
471523pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
......@@ -509,8 +561,10 @@ const elf = std.elf;
509561const log = std.log.scoped(.elf);
510562const mem = std.mem;
511563const Path = std.Build.Cache.Path;
512
564const Stat = std.Build.Cache.File.Stat;
513565const Allocator = mem.Allocator;
566
514567const Elf = @import("../Elf.zig");
515568const File = @import("file.zig").File;
516569const Symbol = @import("Symbol.zig");
570const Diags = @import("../../link.zig").Diags;
src/link/Elf/Symbol.zig+5-4
......@@ -22,7 +22,7 @@ esym_index: Index = 0,
2222
2323/// Index of the source version symbol this symbol references if any.
2424/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.
25version_index: elf.Elf64_Versym = elf.VER_NDX_LOCAL,
25version_index: elf.Versym = .LOCAL,
2626
2727/// Misc flags for the symbol packaged as packed struct for compression.
2828flags: Flags = .{},
......@@ -87,6 +87,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
8787pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
8888 return switch (symbol.file(elf_file).?) {
8989 .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],
90 .shared_object => |so| so.parsed.symtab[symbol.esym_index],
9091 inline else => |x| x.symtab.items[symbol.esym_index],
9192 };
9293}
......@@ -235,7 +236,7 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
235236 assert(file_ptr == .shared_object);
236237 const shared_object = file_ptr.shared_object;
237238 const esym = symbol.elfSym(elf_file);
238 const shdr = shared_object.shdrs.items[esym.st_shndx];
239 const shdr = shared_object.parsed.sections[esym.st_shndx];
239240 const alignment = @max(1, shdr.sh_addralign);
240241 return if (esym.st_value == 0)
241242 alignment
......@@ -351,8 +352,8 @@ fn formatName(
351352 const elf_file = ctx.elf_file;
352353 const symbol = ctx.symbol;
353354 try writer.writeAll(symbol.name(elf_file));
354 switch (symbol.version_index & elf.VERSYM_VERSION) {
355 elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},
355 switch (symbol.version_index.VERSION) {
356 @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {},
356357 else => {
357358 const file_ptr = symbol.file(elf_file).?;
358359 assert(file_ptr == .shared_object);
src/link/Elf/ZigObject.zig+5-4
......@@ -264,7 +264,7 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
264264 }
265265}
266266
267pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
267pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
268268 // Handle any lazy symbols that were emitted by incremental compilation.
269269 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
270270 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.zcu.?, .tid = tid };
......@@ -623,7 +623,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
623623 global.ref = .{ .index = 0, .file = 0 };
624624 global.esym_index = @intCast(index);
625625 global.file_index = self.index;
626 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
626 global.version_index = if (is_import) .LOCAL else elf_file.default_sym_version;
627627 global.flags.import = is_import;
628628
629629 const idx = self.symbols_resolver.items[i];
......@@ -689,8 +689,9 @@ pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
689689 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
690690 const sym = elf_file.symbol(ref) orelse continue;
691691 const file = sym.file(elf_file).?;
692 if (sym.version_index == elf.VER_NDX_LOCAL) continue;
693 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
692 // https://github.com/ziglang/zig/issues/21678
693 if (@as(u16, @bitCast(sym.version_index)) == @as(u16, @bitCast(elf.Versym.LOCAL))) continue;
694 const vis: elf.STV = @enumFromInt(sym.elfSym(elf_file).st_other);
694695 if (vis == .HIDDEN) continue;
695696 if (file == .shared_object and !sym.isAbs(elf_file)) {
696697 sym.flags.import = true;
src/link/Elf/relocatable.zig+15-19
......@@ -4,22 +4,22 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
44
55 for (comp.objects) |obj| {
66 switch (Compilation.classifyFileExt(obj.path.sub_path)) {
7 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
8 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
9 else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),
7 .object => parseObjectStaticLibReportingFailure(elf_file, obj.path),
8 .static_library => parseArchiveStaticLibReportingFailure(elf_file, obj.path),
9 else => diags.addParseError(obj.path, "unrecognized file extension", .{}),
1010 }
1111 }
1212
1313 for (comp.c_object_table.keys()) |key| {
14 try parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path);
14 parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path);
1515 }
1616
1717 if (module_obj_path) |path| {
18 try parseObjectStaticLibReportingFailure(elf_file, path);
18 parseObjectStaticLibReportingFailure(elf_file, path);
1919 }
2020
2121 if (comp.include_compiler_rt) {
22 try parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
22 parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
2323 }
2424
2525 if (diags.hasErrors()) return error.FlushFailure;
......@@ -154,21 +154,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
154154 const diags = &comp.link_diags;
155155
156156 for (comp.objects) |obj| {
157 if (obj.isObject()) {
158 try elf_file.parseObjectReportingFailure(obj.path);
159 } else {
160 try elf_file.parseLibraryReportingFailure(.{ .path = obj.path }, obj.must_link);
161 }
157 elf_file.parseInputReportingFailure(obj.path, false, obj.must_link);
162158 }
163159
164160 // This is a set of object files emitted by clang in a single `build-exe` invocation.
165161 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
166162 // in this set.
167163 for (comp.c_object_table.keys()) |key| {
168 try elf_file.parseObjectReportingFailure(key.status.success.object_path);
164 elf_file.parseObjectReportingFailure(key.status.success.object_path);
169165 }
170166
171 if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);
167 if (module_obj_path) |path| elf_file.parseObjectReportingFailure(path);
172168
173169 if (diags.hasErrors()) return error.FlushFailure;
174170
......@@ -219,19 +215,19 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
219215 if (diags.hasErrors()) return error.FlushFailure;
220216}
221217
222fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
218fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
219 const diags = &elf_file.base.comp.link_diags;
223220 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
224221 error.LinkFailure => return,
225 error.OutOfMemory => return error.OutOfMemory,
226 else => |e| try elf_file.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
222 else => |e| diags.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
227223 };
228224}
229225
230fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
226fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
227 const diags = &elf_file.base.comp.link_diags;
231228 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
232229 error.LinkFailure => return,
233 error.OutOfMemory => return error.OutOfMemory,
234 else => |e| try elf_file.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
230 else => |e| diags.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
235231 };
236232}
237233
src/link/Elf/synthetic_sections.zig+20-18
......@@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct {
13451345
13461346pub const VerneedSection = struct {
13471347 verneed: std.ArrayListUnmanaged(elf.Elf64_Verneed) = .empty,
1348 vernaux: std.ArrayListUnmanaged(elf.Elf64_Vernaux) = .empty,
1349 index: elf.Elf64_Versym = elf.VER_NDX_GLOBAL + 1,
1348 vernaux: std.ArrayListUnmanaged(elf.Vernaux) = .empty,
1349 index: elf.Versym = .{ .VERSION = elf.Versym.GLOBAL.VERSION + 1, .HIDDEN = false },
13501350
13511351 pub fn deinit(vern: *VerneedSection, allocator: Allocator) void {
13521352 vern.verneed.deinit(allocator);
......@@ -1363,7 +1363,7 @@ pub const VerneedSection = struct {
13631363 /// Index of the defining this symbol version shared object file
13641364 shared_object: File.Index,
13651365 /// Version index
1366 version_index: elf.Elf64_Versym,
1366 version_index: elf.Versym,
13671367
13681368 fn soname(this: @This(), ctx: *Elf) []const u8 {
13691369 const shared_object = ctx.file(this.shared_object).?.shared_object;
......@@ -1376,7 +1376,8 @@ pub const VerneedSection = struct {
13761376 }
13771377
13781378 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
1379 if (lhs.shared_object == rhs.shared_object) return lhs.version_index < rhs.version_index;
1379 if (lhs.shared_object == rhs.shared_object)
1380 return @as(u16, @bitCast(lhs.version_index)) < @as(u16, @bitCast(rhs.version_index));
13801381 return mem.lessThan(u8, lhs.soname(ctx), rhs.soname(ctx));
13811382 }
13821383 };
......@@ -1389,7 +1390,7 @@ pub const VerneedSection = struct {
13891390
13901391 for (dynsyms, 1..) |entry, i| {
13911392 const symbol = elf_file.symbol(entry.ref).?;
1392 if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) {
1393 if (symbol.flags.import and symbol.version_index.VERSION > elf.Versym.GLOBAL.VERSION) {
13931394 const shared_object = symbol.file(elf_file).?.shared_object;
13941395 verneed.appendAssumeCapacity(.{
13951396 .index = i,
......@@ -1404,11 +1405,12 @@ pub const VerneedSection = struct {
14041405 var last = verneed.items[0];
14051406 var last_verneed = try vern.addVerneed(last.soname(elf_file), elf_file);
14061407 var last_vernaux = try vern.addVernaux(last_verneed, last.versionString(elf_file), elf_file);
1407 versyms[last.index] = last_vernaux.vna_other;
1408 versyms[last.index] = @bitCast(last_vernaux.other);
14081409
14091410 for (verneed.items[1..]) |ver| {
14101411 if (ver.shared_object == last.shared_object) {
1411 if (ver.version_index != last.version_index) {
1412 // https://github.com/ziglang/zig/issues/21678
1413 if (@as(u16, @bitCast(ver.version_index)) != @as(u16, @bitCast(last.version_index))) {
14121414 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
14131415 }
14141416 } else {
......@@ -1416,7 +1418,7 @@ pub const VerneedSection = struct {
14161418 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
14171419 }
14181420 last = ver;
1419 versyms[ver.index] = last_vernaux.vna_other;
1421 versyms[ver.index] = @bitCast(last_vernaux.other);
14201422 }
14211423
14221424 // Fixup offsets
......@@ -1428,8 +1430,8 @@ pub const VerneedSection = struct {
14281430 vsym.vn_aux = vernaux_off - verneed_off;
14291431 var inner_off: u32 = 0;
14301432 for (vern.vernaux.items[count..][0..vsym.vn_cnt], 0..) |*vaux, vaux_i| {
1431 if (vaux_i < vsym.vn_cnt - 1) vaux.vna_next = @sizeOf(elf.Elf64_Vernaux);
1432 inner_off += @sizeOf(elf.Elf64_Vernaux);
1433 if (vaux_i < vsym.vn_cnt - 1) vaux.next = @sizeOf(elf.Vernaux);
1434 inner_off += @sizeOf(elf.Vernaux);
14331435 }
14341436 vernaux_off += inner_off;
14351437 verneed_off += @sizeOf(elf.Elf64_Verneed);
......@@ -1456,24 +1458,24 @@ pub const VerneedSection = struct {
14561458 verneed_sym: *elf.Elf64_Verneed,
14571459 version: [:0]const u8,
14581460 elf_file: *Elf,
1459 ) !elf.Elf64_Vernaux {
1461 ) !elf.Vernaux {
14601462 const comp = elf_file.base.comp;
14611463 const gpa = comp.gpa;
14621464 const sym = try vern.vernaux.addOne(gpa);
14631465 sym.* = .{
1464 .vna_hash = HashSection.hasher(version),
1465 .vna_flags = 0,
1466 .vna_other = vern.index,
1467 .vna_name = try elf_file.insertDynString(version),
1468 .vna_next = 0,
1466 .hash = HashSection.hasher(version),
1467 .flags = 0,
1468 .other = @bitCast(vern.index),
1469 .name = try elf_file.insertDynString(version),
1470 .next = 0,
14691471 };
14701472 verneed_sym.vn_cnt += 1;
1471 vern.index += 1;
1473 vern.index.VERSION += 1;
14721474 return sym.*;
14731475 }
14741476
14751477 pub fn size(vern: VerneedSection) usize {
1476 return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Elf64_Vernaux);
1478 return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux);
14771479 }
14781480
14791481 pub fn write(vern: VerneedSection, writer: anytype) !void {
src/link/MachO.zig+8-29
......@@ -396,14 +396,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
396396 }
397397
398398 for (positionals.items) |obj| {
399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
400 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
401 else => |e| try diags.reportParseError(
402 obj.path,
403 "unexpected error: reading input file failed with error {s}",
404 .{@errorName(e)},
405 ),
406 };
399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
400 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
407401 }
408402
409403 var system_libs = std.ArrayList(SystemLib).init(gpa);
......@@ -443,14 +437,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
443437 };
444438
445439 for (system_libs.items) |lib| {
446 self.classifyInputFile(lib.path, lib, false) catch |err| switch (err) {
447 error.UnknownFileType => try diags.reportParseError(lib.path, "unknown file type for an input file", .{}),
448 else => |e| try diags.reportParseError(
449 lib.path,
450 "unexpected error: parsing input file failed with error {s}",
451 .{@errorName(e)},
452 ),
453 };
440 self.classifyInputFile(lib.path, lib, false) catch |err|
441 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});
454442 }
455443
456444 // Finally, link against compiler_rt.
......@@ -460,14 +448,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
460448 break :blk null;
461449 };
462450 if (compiler_rt_path) |path| {
463 self.classifyInputFile(path, .{ .path = path }, false) catch |err| switch (err) {
464 error.UnknownFileType => try diags.reportParseError(path, "unknown file type for an input file", .{}),
465 else => |e| try diags.reportParseError(
466 path,
467 "unexpected error: parsing input file failed with error {s}",
468 .{@errorName(e)},
469 ),
470 };
451 self.classifyInputFile(path, .{ .path = path }, false) catch |err|
452 diags.addParseError(path, "failed to parse input file: {s}", .{@errorName(err)});
471453 }
472454
473455 try self.parseInputFiles();
......@@ -796,7 +778,7 @@ pub fn resolveLibSystem(
796778 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
797779 }
798780
799 try diags.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
781 diags.addMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
800782 return error.MissingLibSystem;
801783 }
802784
......@@ -847,10 +829,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
847829 for (fat_archs) |arch| {
848830 if (arch.tag == cpu_arch) return arch;
849831 }
850 try diags.reportParseError(path, "missing arch in universal file: expected {s}", .{
851 @tagName(cpu_arch),
852 });
853 return error.MissingCpuArch;
832 return diags.failParse(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
854833}
855834
856835pub fn readMachHeader(file: std.fs.File, offset: usize) !macho.mach_header_64 {
src/link/MachO/Archive.zig+1-2
......@@ -29,10 +29,9 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
2929 pos += @sizeOf(ar_hdr);
3030
3131 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
32 try diags.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
32 return diags.failParse(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
3333 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
3434 });
35 return error.MalformedArchive;
3635 }
3736
3837 var hdr_size = try hdr.size();
src/link/MachO/relocatable.zig+4-16
......@@ -29,14 +29,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
2929 }
3030
3131 for (positionals.items) |obj| {
32 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
33 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
34 else => |e| try diags.reportParseError(
35 obj.path,
36 "unexpected error: reading input file failed with error {s}",
37 .{@errorName(e)},
38 ),
39 };
32 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
33 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
4034 }
4135
4236 if (diags.hasErrors()) return error.FlushFailure;
......@@ -95,14 +89,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
9589 }
9690
9791 for (positionals.items) |obj| {
98 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
99 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
100 else => |e| try diags.reportParseError(
101 obj.path,
102 "unexpected error: reading input file failed with error {s}",
103 .{@errorName(e)},
104 ),
105 };
92 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
93 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
10694 }
10795
10896 if (diags.hasErrors()) return error.FlushFailure;