authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-12 14:39:17-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-12 14:39:17-07:00
logf7c588286dfb63af54e3bd77898e4c39b791ec89
treeb8a6c41e3ae10413a19e930bf5c8ab8f27788d13
parent7e530c13b3ef9b61417a610c00fc1d37c11ff7ed
parentde04a8a1ef0ea37df7c09a997f60a3c1138de124
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21681 from ziglang/reduce-flush

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

20 files changed, 806 insertions(+), 740 deletions(-)

lib/compiler/objcopy.zig+5-6
......@@ -832,7 +832,6 @@ fn ElfFile(comptime is_64: bool) type {
832832 const Elf_Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr;
833833 const Elf_Chdr = if (is_64) elf.Elf64_Chdr else elf.Elf32_Chdr;
834834 const Elf_Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym;
835 const Elf_Verdef = if (is_64) elf.Elf64_Verdef else elf.Elf32_Verdef;
836835 const Elf_OffSize = if (is_64) elf.Elf64_Off else elf.Elf32_Off;
837836
838837 return struct {
......@@ -1179,11 +1178,11 @@ fn ElfFile(comptime is_64: bool) type {
11791178 const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len);
11801179 @memcpy(data, src_data);
11811180
1182 const defs = @as([*]Elf_Verdef, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(Elf_Verdef)];
1183 for (defs) |*def| {
1184 if (def.vd_ndx != elf.SHN_UNDEF)
1185 def.vd_ndx = sections_update[src.sh_info].remap_idx;
1186 }
1181 const defs = @as([*]elf.Verdef, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(elf.Verdef)];
1182 for (defs) |*def| switch (def.ndx) {
1183 .LOCAL, .GLOBAL => {},
1184 else => def.ndx = @enumFromInt(sections_update[src.sh_info].remap_idx),
1185 };
11871186
11881187 break :dst_data data;
11891188 },
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/dynamic_library.zig+14-16
......@@ -141,7 +141,7 @@ pub const ElfDynLib = struct {
141141 strings: [*:0]u8,
142142 syms: [*]elf.Sym,
143143 hashtab: [*]posix.Elf_Symndx,
144 versym: ?[*]u16,
144 versym: ?[*]elf.Versym,
145145 verdef: ?*elf.Verdef,
146146 memory: []align(mem.page_size) u8,
147147
......@@ -319,7 +319,7 @@ pub const ElfDynLib = struct {
319319 var maybe_strings: ?[*:0]u8 = null;
320320 var maybe_syms: ?[*]elf.Sym = null;
321321 var maybe_hashtab: ?[*]posix.Elf_Symndx = null;
322 var maybe_versym: ?[*]u16 = null;
322 var maybe_versym: ?[*]elf.Versym = null;
323323 var maybe_verdef: ?*elf.Verdef = null;
324324
325325 {
......@@ -327,11 +327,11 @@ pub const ElfDynLib = struct {
327327 while (dynv[i] != 0) : (i += 2) {
328328 const p = base + dynv[i + 1];
329329 switch (dynv[i]) {
330 elf.DT_STRTAB => maybe_strings = @as([*:0]u8, @ptrFromInt(p)),
331 elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
332 elf.DT_HASH => maybe_hashtab = @as([*]posix.Elf_Symndx, @ptrFromInt(p)),
333 elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
334 elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
330 elf.DT_STRTAB => maybe_strings = @ptrFromInt(p),
331 elf.DT_SYMTAB => maybe_syms = @ptrFromInt(p),
332 elf.DT_HASH => maybe_hashtab = @ptrFromInt(p),
333 elf.DT_VERSYM => maybe_versym = @ptrFromInt(p),
334 elf.DT_VERDEF => maybe_verdef = @ptrFromInt(p),
335335 else => {},
336336 }
337337 }
......@@ -399,18 +399,16 @@ pub const ElfDynLib = struct {
399399 }
400400};
401401
402fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*:0]u8) bool {
402fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, strings: [*:0]u8) bool {
403403 var def = def_arg;
404 const vsym = @as(u32, @bitCast(vsym_arg)) & 0x7fff;
404 const vsym_index = vsym_arg.VERSION;
405405 while (true) {
406 if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
407 break;
408 if (def.vd_next == 0)
409 return false;
410 def = @as(*elf.Verdef, @ptrFromInt(@intFromPtr(def) + def.vd_next));
406 if (0 == (def.flags & elf.VER_FLG_BASE) and @intFromEnum(def.ndx) == vsym_index) break;
407 if (def.next == 0) return false;
408 def = @ptrFromInt(@intFromPtr(def) + def.next);
411409 }
412 const aux = @as(*elf.Verdaux, @ptrFromInt(@intFromPtr(def) + def.vd_aux));
413 return mem.eql(u8, vername, mem.sliceTo(strings + aux.vda_name, 0));
410 const aux: *elf.Verdaux = @ptrFromInt(@intFromPtr(def) + def.aux);
411 return mem.eql(u8, vername, mem.sliceTo(strings + aux.name, 0));
414412}
415413
416414test "ElfDynLib" {
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+14-17
......@@ -34,10 +34,10 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
3434 const dynv = maybe_dynv orelse return 0;
3535 if (base == maxInt(usize)) return 0;
3636
37 var maybe_strings: ?[*]u8 = null;
37 var maybe_strings: ?[*:0]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 {
......@@ -45,11 +45,11 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
4545 while (dynv[i] != 0) : (i += 2) {
4646 const p = base +% dynv[i + 1];
4747 switch (dynv[i]) {
48 elf.DT_STRTAB => maybe_strings = @as([*]u8, @ptrFromInt(p)),
49 elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
50 elf.DT_HASH => maybe_hashtab = @as([*]linux.Elf_Symndx, @ptrFromInt(p)),
51 elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
52 elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
48 elf.DT_STRTAB => maybe_strings = @ptrFromInt(p),
49 elf.DT_SYMTAB => maybe_syms = @ptrFromInt(p),
50 elf.DT_HASH => maybe_hashtab = @ptrFromInt(p),
51 elf.DT_VERSYM => maybe_versym = @ptrFromInt(p),
52 elf.DT_VERDEF => maybe_verdef = @ptrFromInt(p),
5353 else => {},
5454 }
5555 }
......@@ -80,17 +80,14 @@ 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: [*:0]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));
95 return mem.eql(u8, vername, mem.sliceTo(vda_name, 0));
91 const aux: *elf.Verdaux = @ptrFromInt(@intFromPtr(def) + def.aux);
92 return mem.eql(u8, vername, mem.sliceTo(strings + aux.name, 0));
9693}
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+282-227
......@@ -1,236 +1,317 @@
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 = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.Elf64_Dyn)) orelse return error.Overflow;
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 n = std.math.cast(usize, strtab_shdr.sh_size) orelse return error.Overflow;
159 const buf = try strtab.addManyAsSlice(gpa, n);
160 const amt = try fs_file.preadAll(buf, strtab_shdr.sh_offset);
161 if (amt != buf.len) return error.UnexpectedEndOfFile;
104162 }
105163
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);
164 var soname_index: ?u32 = null;
165 var verdefnum: ?u32 = null;
166 for (dynamic_table) |entry| switch (entry.d_tag) {
167 elf.DT_SONAME => {
168 if (entry.d_val >= strtab.items.len) return error.BadSonameIndex;
169 soname_index = @intCast(entry.d_val);
170 },
171 elf.DT_VERDEFNUM => {
172 verdefnum = @intCast(entry.d_val);
173 },
174 else => continue,
175 };
121176
122 try self.parseVersions(elf_file, handle, .{
123 .symtab = symtab,
124 .verdef_sect_index = verdef_sect_index,
177 return .{
178 .dynamic_table = dynamic_table,
179 .soname_index = soname_index,
180 .verdefnum = verdefnum,
181 .sections = sections,
182 .dynsym_sect_index = dynsym_sect_index,
125183 .versym_sect_index = versym_sect_index,
126 });
127
128 try self.initSymbols(elf_file, .{
129 .symtab = symtab,
184 .verdef_sect_index = verdef_sect_index,
130185 .strtab = strtab,
131 });
186 .stat = stat,
187 };
132188}
133189
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;
190pub fn parse(
191 gpa: Allocator,
192 /// Moves resources from header. Caller may unconditionally deinit.
193 header: *Header,
194 fs_file: std.fs.File,
195) !Parsed {
196 const symtab = if (header.dynsym_sect_index) |index| st: {
197 const shdr = header.sections[index];
198 const n = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.Elf64_Sym)) orelse return error.Overflow;
199 const symtab = try gpa.alloc(elf.Elf64_Sym, n);
200 errdefer gpa.free(symtab);
201 const buf = mem.sliceAsBytes(symtab);
202 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
203 if (amt != buf.len) return error.UnexpectedEndOfFile;
204 break :st symtab;
205 } else &.{};
206 defer gpa.free(symtab);
141207
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;
208 var verstrings: std.ArrayListUnmanaged(u32) = .empty;
209 defer verstrings.deinit(gpa);
145210
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);
211 if (header.verdef_sect_index) |shndx| {
212 const shdr = header.sections[shndx];
213 const verdefs = try Elf.preadAllAlloc(gpa, fs_file, shdr.sh_offset, shdr.sh_size);
149214 defer gpa.free(verdefs);
150 const nverdefs = self.verdefNum();
151 try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs);
152215
153 var i: u32 = 0;
154216 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 }
217 while (true) {
218 const verdef = mem.bytesAsValue(elf.Verdef, verdefs[offset..][0..@sizeOf(elf.Verdef)]);
219 if (verdef.ndx == .UNSPECIFIED) return error.VerDefSymbolTooLarge;
220
221 if (verstrings.items.len <= @intFromEnum(verdef.ndx))
222 try verstrings.appendNTimes(gpa, 0, @intFromEnum(verdef.ndx) + 1 - verstrings.items.len);
166223
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);
224 const aux = mem.bytesAsValue(elf.Verdaux, verdefs[offset + verdef.aux ..][0..@sizeOf(elf.Verdaux)]);
225 verstrings.items[@intFromEnum(verdef.ndx)] = aux.name;
226
227 if (verdef.next == 0) break;
228 offset += verdef.next;
181229 }
182 } else for (0..opts.symtab.len) |_| {
183 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
184230 }
185}
186231
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(.{});
232 const versyms = if (header.versym_sect_index) |versym_sect_index| vs: {
233 const shdr = header.sections[versym_sect_index];
234 if (shdr.sh_size != symtab.len * @sizeOf(elf.Versym)) return error.BadVerSymSectionSize;
235
236 const versyms = try gpa.alloc(elf.Versym, symtab.len);
237 errdefer gpa.free(versyms);
238 const buf = mem.sliceAsBytes(versyms);
239 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
240 if (amt != buf.len) return error.UnexpectedEndOfFile;
241 break :vs versyms;
242 } else &.{};
243 defer gpa.free(versyms);
244
245 var nonlocal_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty;
246 defer nonlocal_esyms.deinit(gpa);
247
248 var nonlocal_versyms: std.ArrayListUnmanaged(elf.Versym) = .empty;
249 defer nonlocal_versyms.deinit(gpa);
250
251 var nonlocal_symbols: std.ArrayListUnmanaged(Parsed.Symbol) = .empty;
252 defer nonlocal_symbols.deinit(gpa);
253
254 var strtab = header.strtab;
255 header.strtab = .empty;
256 defer strtab.deinit(gpa);
257
258 for (symtab, 0..) |sym, i| {
259 const ver: elf.Versym = if (versyms.len == 0 or sym.st_shndx == elf.SHN_UNDEF)
260 .GLOBAL
261 else
262 .{ .VERSION = versyms[i].VERSION, .HIDDEN = false };
263
264 // https://github.com/ziglang/zig/issues/21678
265 //if (ver == .LOCAL) continue;
266 if (@as(u16, @bitCast(ver)) == 0) continue;
267
268 try nonlocal_esyms.ensureUnusedCapacity(gpa, 1);
269 try nonlocal_versyms.ensureUnusedCapacity(gpa, 1);
270 try nonlocal_symbols.ensureUnusedCapacity(gpa, 1);
271
272 const name = Elf.stringTableLookup(strtab.items, sym.st_name);
273 const is_default = versyms.len == 0 or !versyms[i].HIDDEN;
274 const mangled_name = if (is_default) sym.st_name else mn: {
275 const off: u32 = @intCast(strtab.items.len);
276 const version_string = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
277 try strtab.ensureUnusedCapacity(gpa, name.len + version_string.len + 2);
278 // Reload since the string table might have been resized.
279 const name2 = Elf.stringTableLookup(strtab.items, sym.st_name);
280 const version_string2 = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
281 strtab.appendSliceAssumeCapacity(name2);
282 strtab.appendAssumeCapacity('@');
283 strtab.appendSliceAssumeCapacity(version_string2);
284 strtab.appendAssumeCapacity(0);
285 break :mn off;
286 };
287
288 nonlocal_esyms.appendAssumeCapacity(sym);
289 nonlocal_versyms.appendAssumeCapacity(ver);
290 nonlocal_symbols.appendAssumeCapacity(.{
291 .mangled_name = mangled_name,
292 });
227293 }
294
295 const sections = header.sections;
296 header.sections = &.{};
297 errdefer gpa.free(sections);
298
299 return .{
300 .sections = sections,
301 .stat = header.stat,
302 .soname_index = header.soname_index,
303 .strtab = try strtab.toOwnedSlice(gpa),
304 .symtab = try nonlocal_esyms.toOwnedSlice(gpa),
305 .versyms = try nonlocal_versyms.toOwnedSlice(gpa),
306 .symbols = try nonlocal_symbols.toOwnedSlice(gpa),
307 .verstrings = try verstrings.toOwnedSlice(gpa),
308 };
228309}
229310
230311pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
231312 const gpa = elf_file.base.comp.gpa;
232313
233 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
314 for (self.parsed.symtab, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
234315 const gop = try elf_file.resolver.getOrPut(gpa, .{
235316 .index = @intCast(i),
236317 .file = self.index,
......@@ -253,7 +334,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
253334}
254335
255336pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
256 for (self.symtab.items, 0..) |esym, i| {
337 for (self.parsed.symtab, 0..) |esym, i| {
257338 if (esym.st_shndx != elf.SHN_UNDEF) continue;
258339
259340 const ref = self.resolveSymbol(@intCast(i), elf_file);
......@@ -308,29 +389,21 @@ pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
308389 }
309390}
310391
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);
392pub fn versionString(self: SharedObject, index: elf.Versym) [:0]const u8 {
393 return self.parsed.versionString(index);
314394}
315395
316pub fn asFile(self: *SharedObject) File {
317 return .{ .shared_object = self };
396fn versionStringLookup(strtab: []const u8, verstrings: []const u32, index: elf.Versym) [:0]const u8 {
397 const off = verstrings[index.VERSION];
398 return Elf.stringTableLookup(strtab, off);
318399}
319400
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;
401pub fn asFile(self: *SharedObject) File {
402 return .{ .shared_object = self };
326403}
327404
328405pub 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);
406 return self.parsed.soname() orelse self.path.basename();
334407}
335408
336409pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
......@@ -360,7 +433,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
360433 aliases.appendAssumeCapacity(@intCast(index));
361434 }
362435
363 std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
436 mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
364437
365438 self.aliases = aliases.moveToUnmanaged();
366439}
......@@ -384,17 +457,8 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
384457 return aliases.items[start..end];
385458}
386459
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
395460pub 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);
461 return Elf.stringTableLookup(self.parsed.strtab, off);
398462}
399463
400464pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
......@@ -402,25 +466,14 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El
402466 return elf_file.resolver.get(resolv).?;
403467}
404468
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 {
469pub fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
411470 const index: Symbol.Index = @intCast(self.symbols.items.len);
412471 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
413472 return index;
414473}
415474
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
422475pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
423 const index = @as(u32, @intCast(self.symbols_extra.items.len));
476 const index: u32 = @intCast(self.symbols_extra.items.len);
424477 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
425478 inline for (fields) |field| {
426479 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
......@@ -465,7 +518,7 @@ pub fn format(
465518 _ = unused_fmt_string;
466519 _ = options;
467520 _ = writer;
468 @compileError("do not format shared objects directly");
521 @compileError("unreachable");
469522}
470523
471524pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
......@@ -509,8 +562,10 @@ const elf = std.elf;
509562const log = std.log.scoped(.elf);
510563const mem = std.mem;
511564const Path = std.Build.Cache.Path;
512
565const Stat = std.Build.Cache.File.Stat;
513566const Allocator = mem.Allocator;
567
514568const Elf = @import("../Elf.zig");
515569const File = @import("file.zig").File;
516570const Symbol = @import("Symbol.zig");
571const 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;