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

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

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

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

lib/std/Build/Cache.zig+8
...@@ -150,6 +150,14 @@ pub const File = struct {...@@ -150,6 +150,14 @@ pub const File = struct {
150 inode: fs.File.INode,150 inode: fs.File.INode,
151 size: u64,151 size: u64,
152 mtime: i128,152 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 }
153 };161 };
154162
155 pub fn deinit(self: *File, gpa: Allocator) void {163 pub fn deinit(self: *File, gpa: Allocator) void {
lib/std/elf.zig+137-164
...@@ -258,17 +258,26 @@ pub const DF_1_SINGLETON = 0x02000000;...@@ -258,17 +258,26 @@ pub const DF_1_SINGLETON = 0x02000000;
258pub const DF_1_STUB = 0x04000000;258pub const DF_1_STUB = 0x04000000;
259pub const DF_1_PIE = 0x08000000;259pub const DF_1_PIE = 0x08000000;
260260
261pub const VERSYM_HIDDEN = 0x8000;261pub const Versym = packed struct(u16) {
262pub const VERSYM_VERSION = 0x7fff;262 VERSION: u15,
263263 HIDDEN: bool,
264/// Symbol is local264
265pub const VER_NDX_LOCAL = 0;265 pub const LOCAL: Versym = @bitCast(@intFromEnum(VER_NDX.LOCAL));
266/// Symbol is global266 pub const GLOBAL: Versym = @bitCast(@intFromEnum(VER_NDX.GLOBAL));
267pub const VER_NDX_GLOBAL = 1;267};
268/// Beginning of reserved entries268
269pub const VER_NDX_LORESERVE = 0xff00;269pub const VER_NDX = enum(u16) {
270/// Symbol is to be eliminated270 /// Symbol is local
271pub const VER_NDX_ELIMINATE = 0xff01;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
273/// Version definition of the file itself282/// Version definition of the file itself
274pub const VER_FLG_BASE = 1;283pub const VER_FLG_BASE = 1;
...@@ -698,12 +707,9 @@ pub const EI_PAD = 9;...@@ -698,12 +707,9 @@ pub const EI_PAD = 9;
698707
699pub const EI_NIDENT = 16;708pub const EI_NIDENT = 16;
700709
701pub const Elf32_Half = u16;710pub const Half = u16;
702pub const Elf64_Half = u16;711pub const Word = u32;
703pub const Elf32_Word = u32;712pub const Sword = i32;
704pub const Elf32_Sword = i32;
705pub const Elf64_Word = u32;
706pub const Elf64_Sword = i32;
707pub const Elf32_Xword = u64;713pub const Elf32_Xword = u64;
708pub const Elf32_Sxword = i64;714pub const Elf32_Sxword = i64;
709pub const Elf64_Xword = u64;715pub const Elf64_Xword = u64;
...@@ -714,53 +720,51 @@ pub const Elf32_Off = u32;...@@ -714,53 +720,51 @@ pub const Elf32_Off = u32;
714pub const Elf64_Off = u64;720pub const Elf64_Off = u64;
715pub const Elf32_Section = u16;721pub const Elf32_Section = u16;
716pub const Elf64_Section = u16;722pub const Elf64_Section = u16;
717pub const Elf32_Versym = Elf32_Half;
718pub const Elf64_Versym = Elf64_Half;
719pub const Elf32_Ehdr = extern struct {723pub const Elf32_Ehdr = extern struct {
720 e_ident: [EI_NIDENT]u8,724 e_ident: [EI_NIDENT]u8,
721 e_type: ET,725 e_type: ET,
722 e_machine: EM,726 e_machine: EM,
723 e_version: Elf32_Word,727 e_version: Word,
724 e_entry: Elf32_Addr,728 e_entry: Elf32_Addr,
725 e_phoff: Elf32_Off,729 e_phoff: Elf32_Off,
726 e_shoff: Elf32_Off,730 e_shoff: Elf32_Off,
727 e_flags: Elf32_Word,731 e_flags: Word,
728 e_ehsize: Elf32_Half,732 e_ehsize: Half,
729 e_phentsize: Elf32_Half,733 e_phentsize: Half,
730 e_phnum: Elf32_Half,734 e_phnum: Half,
731 e_shentsize: Elf32_Half,735 e_shentsize: Half,
732 e_shnum: Elf32_Half,736 e_shnum: Half,
733 e_shstrndx: Elf32_Half,737 e_shstrndx: Half,
734};738};
735pub const Elf64_Ehdr = extern struct {739pub const Elf64_Ehdr = extern struct {
736 e_ident: [EI_NIDENT]u8,740 e_ident: [EI_NIDENT]u8,
737 e_type: ET,741 e_type: ET,
738 e_machine: EM,742 e_machine: EM,
739 e_version: Elf64_Word,743 e_version: Word,
740 e_entry: Elf64_Addr,744 e_entry: Elf64_Addr,
741 e_phoff: Elf64_Off,745 e_phoff: Elf64_Off,
742 e_shoff: Elf64_Off,746 e_shoff: Elf64_Off,
743 e_flags: Elf64_Word,747 e_flags: Word,
744 e_ehsize: Elf64_Half,748 e_ehsize: Half,
745 e_phentsize: Elf64_Half,749 e_phentsize: Half,
746 e_phnum: Elf64_Half,750 e_phnum: Half,
747 e_shentsize: Elf64_Half,751 e_shentsize: Half,
748 e_shnum: Elf64_Half,752 e_shnum: Half,
749 e_shstrndx: Elf64_Half,753 e_shstrndx: Half,
750};754};
751pub const Elf32_Phdr = extern struct {755pub const Elf32_Phdr = extern struct {
752 p_type: Elf32_Word,756 p_type: Word,
753 p_offset: Elf32_Off,757 p_offset: Elf32_Off,
754 p_vaddr: Elf32_Addr,758 p_vaddr: Elf32_Addr,
755 p_paddr: Elf32_Addr,759 p_paddr: Elf32_Addr,
756 p_filesz: Elf32_Word,760 p_filesz: Word,
757 p_memsz: Elf32_Word,761 p_memsz: Word,
758 p_flags: Elf32_Word,762 p_flags: Word,
759 p_align: Elf32_Word,763 p_align: Word,
760};764};
761pub const Elf64_Phdr = extern struct {765pub const Elf64_Phdr = extern struct {
762 p_type: Elf64_Word,766 p_type: Word,
763 p_flags: Elf64_Word,767 p_flags: Word,
764 p_offset: Elf64_Off,768 p_offset: Elf64_Off,
765 p_vaddr: Elf64_Addr,769 p_vaddr: Elf64_Addr,
766 p_paddr: Elf64_Addr,770 p_paddr: Elf64_Addr,
...@@ -769,44 +773,44 @@ pub const Elf64_Phdr = extern struct {...@@ -769,44 +773,44 @@ pub const Elf64_Phdr = extern struct {
769 p_align: Elf64_Xword,773 p_align: Elf64_Xword,
770};774};
771pub const Elf32_Shdr = extern struct {775pub const Elf32_Shdr = extern struct {
772 sh_name: Elf32_Word,776 sh_name: Word,
773 sh_type: Elf32_Word,777 sh_type: Word,
774 sh_flags: Elf32_Word,778 sh_flags: Word,
775 sh_addr: Elf32_Addr,779 sh_addr: Elf32_Addr,
776 sh_offset: Elf32_Off,780 sh_offset: Elf32_Off,
777 sh_size: Elf32_Word,781 sh_size: Word,
778 sh_link: Elf32_Word,782 sh_link: Word,
779 sh_info: Elf32_Word,783 sh_info: Word,
780 sh_addralign: Elf32_Word,784 sh_addralign: Word,
781 sh_entsize: Elf32_Word,785 sh_entsize: Word,
782};786};
783pub const Elf64_Shdr = extern struct {787pub const Elf64_Shdr = extern struct {
784 sh_name: Elf64_Word,788 sh_name: Word,
785 sh_type: Elf64_Word,789 sh_type: Word,
786 sh_flags: Elf64_Xword,790 sh_flags: Elf64_Xword,
787 sh_addr: Elf64_Addr,791 sh_addr: Elf64_Addr,
788 sh_offset: Elf64_Off,792 sh_offset: Elf64_Off,
789 sh_size: Elf64_Xword,793 sh_size: Elf64_Xword,
790 sh_link: Elf64_Word,794 sh_link: Word,
791 sh_info: Elf64_Word,795 sh_info: Word,
792 sh_addralign: Elf64_Xword,796 sh_addralign: Elf64_Xword,
793 sh_entsize: Elf64_Xword,797 sh_entsize: Elf64_Xword,
794};798};
795pub const Elf32_Chdr = extern struct {799pub const Elf32_Chdr = extern struct {
796 ch_type: COMPRESS,800 ch_type: COMPRESS,
797 ch_size: Elf32_Word,801 ch_size: Word,
798 ch_addralign: Elf32_Word,802 ch_addralign: Word,
799};803};
800pub const Elf64_Chdr = extern struct {804pub const Elf64_Chdr = extern struct {
801 ch_type: COMPRESS,805 ch_type: COMPRESS,
802 ch_reserved: Elf64_Word = 0,806 ch_reserved: Word = 0,
803 ch_size: Elf64_Xword,807 ch_size: Elf64_Xword,
804 ch_addralign: Elf64_Xword,808 ch_addralign: Elf64_Xword,
805};809};
806pub const Elf32_Sym = extern struct {810pub const Elf32_Sym = extern struct {
807 st_name: Elf32_Word,811 st_name: Word,
808 st_value: Elf32_Addr,812 st_value: Elf32_Addr,
809 st_size: Elf32_Word,813 st_size: Word,
810 st_info: u8,814 st_info: u8,
811 st_other: u8,815 st_other: u8,
812 st_shndx: Elf32_Section,816 st_shndx: Elf32_Section,
...@@ -819,7 +823,7 @@ pub const Elf32_Sym = extern struct {...@@ -819,7 +823,7 @@ pub const Elf32_Sym = extern struct {
819 }823 }
820};824};
821pub const Elf64_Sym = extern struct {825pub const Elf64_Sym = extern struct {
822 st_name: Elf64_Word,826 st_name: Word,
823 st_info: u8,827 st_info: u8,
824 st_other: u8,828 st_other: u8,
825 st_shndx: Elf64_Section,829 st_shndx: Elf64_Section,
...@@ -834,16 +838,16 @@ pub const Elf64_Sym = extern struct {...@@ -834,16 +838,16 @@ pub const Elf64_Sym = extern struct {
834 }838 }
835};839};
836pub const Elf32_Syminfo = extern struct {840pub const Elf32_Syminfo = extern struct {
837 si_boundto: Elf32_Half,841 si_boundto: Half,
838 si_flags: Elf32_Half,842 si_flags: Half,
839};843};
840pub const Elf64_Syminfo = extern struct {844pub const Elf64_Syminfo = extern struct {
841 si_boundto: Elf64_Half,845 si_boundto: Half,
842 si_flags: Elf64_Half,846 si_flags: Half,
843};847};
844pub const Elf32_Rel = extern struct {848pub const Elf32_Rel = extern struct {
845 r_offset: Elf32_Addr,849 r_offset: Elf32_Addr,
846 r_info: Elf32_Word,850 r_info: Word,
847851
848 pub inline fn r_sym(self: @This()) u24 {852 pub inline fn r_sym(self: @This()) u24 {
849 return @truncate(self.r_info >> 8);853 return @truncate(self.r_info >> 8);
...@@ -865,8 +869,8 @@ pub const Elf64_Rel = extern struct {...@@ -865,8 +869,8 @@ pub const Elf64_Rel = extern struct {
865};869};
866pub const Elf32_Rela = extern struct {870pub const Elf32_Rela = extern struct {
867 r_offset: Elf32_Addr,871 r_offset: Elf32_Addr,
868 r_info: Elf32_Word,872 r_info: Word,
869 r_addend: Elf32_Sword,873 r_addend: Sword,
870874
871 pub inline fn r_sym(self: @This()) u24 {875 pub inline fn r_sym(self: @This()) u24 {
872 return @truncate(self.r_info >> 8);876 return @truncate(self.r_info >> 8);
...@@ -887,69 +891,49 @@ pub const Elf64_Rela = extern struct {...@@ -887,69 +891,49 @@ pub const Elf64_Rela = extern struct {
887 return @truncate(self.r_info);891 return @truncate(self.r_info);
888 }892 }
889};893};
890pub const Elf32_Relr = Elf32_Word;894pub const Elf32_Relr = Word;
891pub const Elf64_Relr = Elf64_Xword;895pub const Elf64_Relr = Elf64_Xword;
892pub const Elf32_Dyn = extern struct {896pub const Elf32_Dyn = extern struct {
893 d_tag: Elf32_Sword,897 d_tag: Sword,
894 d_val: Elf32_Addr,898 d_val: Elf32_Addr,
895};899};
896pub const Elf64_Dyn = extern struct {900pub const Elf64_Dyn = extern struct {
897 d_tag: Elf64_Sxword,901 d_tag: Elf64_Sxword,
898 d_val: Elf64_Addr,902 d_val: Elf64_Addr,
899};903};
900pub const Elf32_Verdef = extern struct {904pub const Verdef = extern struct {
901 vd_version: Elf32_Half,905 version: Half,
902 vd_flags: Elf32_Half,906 flags: Half,
903 vd_ndx: Elf32_Half,907 ndx: VER_NDX,
904 vd_cnt: Elf32_Half,908 cnt: Half,
905 vd_hash: Elf32_Word,909 hash: Word,
906 vd_aux: Elf32_Word,910 aux: Word,
907 vd_next: Elf32_Word,911 next: 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,
917};912};
918pub const Elf32_Verdaux = extern struct {913pub const Verdaux = extern struct {
919 vda_name: Elf32_Word,914 name: Word,
920 vda_next: Elf32_Word,915 next: Word,
921};
922pub const Elf64_Verdaux = extern struct {
923 vda_name: Elf64_Word,
924 vda_next: Elf64_Word,
925};916};
926pub const Elf32_Verneed = extern struct {917pub const Elf32_Verneed = extern struct {
927 vn_version: Elf32_Half,918 vn_version: Half,
928 vn_cnt: Elf32_Half,919 vn_cnt: Half,
929 vn_file: Elf32_Word,920 vn_file: Word,
930 vn_aux: Elf32_Word,921 vn_aux: Word,
931 vn_next: Elf32_Word,922 vn_next: Word,
932};923};
933pub const Elf64_Verneed = extern struct {924pub const Elf64_Verneed = extern struct {
934 vn_version: Elf64_Half,925 vn_version: Half,
935 vn_cnt: Elf64_Half,926 vn_cnt: Half,
936 vn_file: Elf64_Word,927 vn_file: Word,
937 vn_aux: Elf64_Word,928 vn_aux: Word,
938 vn_next: Elf64_Word,929 vn_next: 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,
946};930};
947pub const Elf64_Vernaux = extern struct {931pub const Vernaux = extern struct {
948 vna_hash: Elf64_Word,932 hash: Word,
949 vna_flags: Elf64_Half,933 flags: Half,
950 vna_other: Elf64_Half,934 other: Half,
951 vna_name: Elf64_Word,935 name: Word,
952 vna_next: Elf64_Word,936 next: Word,
953};937};
954pub const Elf32_auxv_t = extern struct {938pub const Elf32_auxv_t = extern struct {
955 a_type: u32,939 a_type: u32,
...@@ -964,81 +948,81 @@ pub const Elf64_auxv_t = extern struct {...@@ -964,81 +948,81 @@ pub const Elf64_auxv_t = extern struct {
964 },948 },
965};949};
966pub const Elf32_Nhdr = extern struct {950pub const Elf32_Nhdr = extern struct {
967 n_namesz: Elf32_Word,951 n_namesz: Word,
968 n_descsz: Elf32_Word,952 n_descsz: Word,
969 n_type: Elf32_Word,953 n_type: Word,
970};954};
971pub const Elf64_Nhdr = extern struct {955pub const Elf64_Nhdr = extern struct {
972 n_namesz: Elf64_Word,956 n_namesz: Word,
973 n_descsz: Elf64_Word,957 n_descsz: Word,
974 n_type: Elf64_Word,958 n_type: Word,
975};959};
976pub const Elf32_Move = extern struct {960pub const Elf32_Move = extern struct {
977 m_value: Elf32_Xword,961 m_value: Elf32_Xword,
978 m_info: Elf32_Word,962 m_info: Word,
979 m_poffset: Elf32_Word,963 m_poffset: Word,
980 m_repeat: Elf32_Half,964 m_repeat: Half,
981 m_stride: Elf32_Half,965 m_stride: Half,
982};966};
983pub const Elf64_Move = extern struct {967pub const Elf64_Move = extern struct {
984 m_value: Elf64_Xword,968 m_value: Elf64_Xword,
985 m_info: Elf64_Xword,969 m_info: Elf64_Xword,
986 m_poffset: Elf64_Xword,970 m_poffset: Elf64_Xword,
987 m_repeat: Elf64_Half,971 m_repeat: Half,
988 m_stride: Elf64_Half,972 m_stride: Half,
989};973};
990pub const Elf32_gptab = extern union {974pub const Elf32_gptab = extern union {
991 gt_header: extern struct {975 gt_header: extern struct {
992 gt_current_g_value: Elf32_Word,976 gt_current_g_value: Word,
993 gt_unused: Elf32_Word,977 gt_unused: Word,
994 },978 },
995 gt_entry: extern struct {979 gt_entry: extern struct {
996 gt_g_value: Elf32_Word,980 gt_g_value: Word,
997 gt_bytes: Elf32_Word,981 gt_bytes: Word,
998 },982 },
999};983};
1000pub const Elf32_RegInfo = extern struct {984pub const Elf32_RegInfo = extern struct {
1001 ri_gprmask: Elf32_Word,985 ri_gprmask: Word,
1002 ri_cprmask: [4]Elf32_Word,986 ri_cprmask: [4]Word,
1003 ri_gp_value: Elf32_Sword,987 ri_gp_value: Sword,
1004};988};
1005pub const Elf_Options = extern struct {989pub const Elf_Options = extern struct {
1006 kind: u8,990 kind: u8,
1007 size: u8,991 size: u8,
1008 section: Elf32_Section,992 section: Elf32_Section,
1009 info: Elf32_Word,993 info: Word,
1010};994};
1011pub const Elf_Options_Hw = extern struct {995pub const Elf_Options_Hw = extern struct {
1012 hwp_flags1: Elf32_Word,996 hwp_flags1: Word,
1013 hwp_flags2: Elf32_Word,997 hwp_flags2: Word,
1014};998};
1015pub const Elf32_Lib = extern struct {999pub const Elf32_Lib = extern struct {
1016 l_name: Elf32_Word,1000 l_name: Word,
1017 l_time_stamp: Elf32_Word,1001 l_time_stamp: Word,
1018 l_checksum: Elf32_Word,1002 l_checksum: Word,
1019 l_version: Elf32_Word,1003 l_version: Word,
1020 l_flags: Elf32_Word,1004 l_flags: Word,
1021};1005};
1022pub const Elf64_Lib = extern struct {1006pub const Elf64_Lib = extern struct {
1023 l_name: Elf64_Word,1007 l_name: Word,
1024 l_time_stamp: Elf64_Word,1008 l_time_stamp: Word,
1025 l_checksum: Elf64_Word,1009 l_checksum: Word,
1026 l_version: Elf64_Word,1010 l_version: Word,
1027 l_flags: Elf64_Word,1011 l_flags: Word,
1028};1012};
1029pub const Elf32_Conflict = Elf32_Addr;1013pub const Elf32_Conflict = Elf32_Addr;
1030pub const Elf_MIPS_ABIFlags_v0 = extern struct {1014pub const Elf_MIPS_ABIFlags_v0 = extern struct {
1031 version: Elf32_Half,1015 version: Half,
1032 isa_level: u8,1016 isa_level: u8,
1033 isa_rev: u8,1017 isa_rev: u8,
1034 gpr_size: u8,1018 gpr_size: u8,
1035 cpr1_size: u8,1019 cpr1_size: u8,
1036 cpr2_size: u8,1020 cpr2_size: u8,
1037 fp_abi: u8,1021 fp_abi: u8,
1038 isa_ext: Elf32_Word,1022 isa_ext: Word,
1039 ases: Elf32_Word,1023 ases: Word,
1040 flags1: Elf32_Word,1024 flags1: Word,
1041 flags2: Elf32_Word,1025 flags2: Word,
1042};1026};
10431027
1044comptime {1028comptime {
...@@ -1102,22 +1086,11 @@ pub const Sym = switch (@sizeOf(usize)) {...@@ -1102,22 +1086,11 @@ pub const Sym = switch (@sizeOf(usize)) {
1102 8 => Elf64_Sym,1086 8 => Elf64_Sym,
1103 else => @compileError("expected pointer size of 32 or 64"),1087 else => @compileError("expected pointer size of 32 or 64"),
1104};1088};
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};
1115pub const Addr = switch (@sizeOf(usize)) {1089pub const Addr = switch (@sizeOf(usize)) {
1116 4 => Elf32_Addr,1090 4 => Elf32_Addr,
1117 8 => Elf64_Addr,1091 8 => Elf64_Addr,
1118 else => @compileError("expected pointer size of 32 or 64"),1092 else => @compileError("expected pointer size of 32 or 64"),
1119};1093};
1120pub const Half = u16;
11211094
1122pub const OSABI = enum(u8) {1095pub const OSABI = enum(u8) {
1123 /// UNIX System V ABI1096 /// UNIX System V ABI
lib/std/os/linux/vdso.zig+9-11
...@@ -37,7 +37,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -37,7 +37,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
37 var maybe_strings: ?[*]u8 = null;37 var maybe_strings: ?[*]u8 = null;
38 var maybe_syms: ?[*]elf.Sym = null;38 var maybe_syms: ?[*]elf.Sym = null;
39 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;39 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
40 var maybe_versym: ?[*]u16 = null;40 var maybe_versym: ?[*]elf.Versym = null;
41 var maybe_verdef: ?*elf.Verdef = null;41 var maybe_verdef: ?*elf.Verdef = null;
4242
43 {43 {
...@@ -48,7 +48,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -48,7 +48,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
48 elf.DT_STRTAB => maybe_strings = @as([*]u8, @ptrFromInt(p)),48 elf.DT_STRTAB => maybe_strings = @as([*]u8, @ptrFromInt(p)),
49 elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @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)),50 elf.DT_HASH => maybe_hashtab = @as([*]linux.Elf_Symndx, @ptrFromInt(p)),
51 elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),51 elf.DT_VERSYM => maybe_versym = @as([*]elf.Versym, @ptrFromInt(p)),
52 elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),52 elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
53 else => {},53 else => {},
54 }54 }
...@@ -80,17 +80,15 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -80,17 +80,15 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
80 return 0;80 return 0;
81}81}
8282
83fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {83fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, strings: [*]u8) bool {
84 var def = def_arg;84 var def = def_arg;
85 const vsym = @as(u32, @bitCast(vsym_arg)) & 0x7fff;85 const vsym_index = vsym_arg.VERSION;
86 while (true) {86 while (true) {
87 if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)87 if (0 == (def.flags & elf.VER_FLG_BASE) and @intFromEnum(def.ndx) == vsym_index) break;
88 break;88 if (def.next == 0) return false;
89 if (def.vd_next == 0)89 def = @ptrFromInt(@intFromPtr(def) + def.next);
90 return false;
91 def = @as(*elf.Verdef, @ptrFromInt(@intFromPtr(def) + def.vd_next));
92 }90 }
93 const aux = @as(*elf.Verdaux, @ptrFromInt(@intFromPtr(def) + def.vd_aux));91 const aux: *elf.Verdaux = @ptrFromInt(@intFromPtr(def) + def.aux);
94 const vda_name = @as([*:0]u8, @ptrCast(strings + aux.vda_name));92 const vda_name: [*:0]u8 = @ptrCast(strings + aux.name);
95 return mem.eql(u8, vername, mem.sliceTo(vda_name, 0));93 return mem.eql(u8, vername, mem.sliceTo(vda_name, 0));
96}94}
src/Compilation.zig+2
...@@ -1002,6 +1002,7 @@ const CacheUse = union(CacheMode) {...@@ -1002,6 +1002,7 @@ const CacheUse = union(CacheMode) {
1002pub const LinkObject = struct {1002pub const LinkObject = struct {
1003 path: Path,1003 path: Path,
1004 must_link: bool = false,1004 must_link: bool = false,
1005 needed: bool = false,
1005 // When the library is passed via a positional argument, it will be1006 // When the library is passed via a positional argument, it will be
1006 // added as a full path. If it's `-l<lib>`, then just the basename.1007 // added as a full path. If it's `-l<lib>`, then just the basename.
1007 //1008 //
...@@ -2561,6 +2562,7 @@ fn addNonIncrementalStuffToCacheManifest(...@@ -2561,6 +2562,7 @@ fn addNonIncrementalStuffToCacheManifest(
2561 for (comp.objects) |obj| {2562 for (comp.objects) |obj| {
2562 _ = try man.addFilePath(obj.path, null);2563 _ = try man.addFilePath(obj.path, null);
2563 man.hash.add(obj.must_link);2564 man.hash.add(obj.must_link);
2565 man.hash.add(obj.needed);
2564 man.hash.add(obj.loption);2566 man.hash.add(obj.loption);
2565 }2567 }
25662568
src/link.zig+83-27
...@@ -207,23 +207,19 @@ pub const Diags = struct {...@@ -207,23 +207,19 @@ pub const Diags = struct {
207 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {207 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
208 @branchHint(.cold);208 @branchHint(.cold);
209 const gpa = diags.gpa;209 const gpa = diags.gpa;
210 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
210 diags.mutex.lock();211 diags.mutex.lock();
211 defer diags.mutex.unlock();212 defer diags.mutex.unlock();
212 diags.msgs.ensureUnusedCapacity(gpa, 1) catch |err| switch (err) {213 addErrorLockedFallible(diags, eu_main_msg) catch |err| switch (err) {
213 error.OutOfMemory => {214 error.OutOfMemory => diags.setAllocFailureLocked(),
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 },
225 };215 };
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 });
227 }223 }
228224
229 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {225 pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
...@@ -242,7 +238,7 @@ pub const Diags = struct {...@@ -242,7 +238,7 @@ pub const Diags = struct {
242 const err = diags.msgs.addOneAssumeCapacity();238 const err = diags.msgs.addOneAssumeCapacity();
243 err.* = .{239 err.* = .{
244 .msg = undefined,240 .msg = undefined,
245 .notes = try gpa.alloc(Diags.Msg, note_count),241 .notes = try gpa.alloc(Msg, note_count),
246 };242 };
247 return .{243 return .{
248 .diags = diags,244 .diags = diags,
...@@ -250,34 +246,93 @@ pub const Diags = struct {...@@ -250,34 +246,93 @@ pub const Diags = struct {
250 };246 };
251 }247 }
252248
253 pub fn reportMissingLibraryError(249 pub fn addMissingLibraryError(
254 diags: *Diags,250 diags: *Diags,
255 checked_paths: []const []const u8,251 checked_paths: []const []const u8,
256 comptime format: []const u8,252 comptime format: []const u8,
257 args: anytype,253 args: anytype,
258 ) error{OutOfMemory}!void {254 ) void {
259 @branchHint(.cold);255 @branchHint(.cold);
260 var err = try diags.addErrorWithNotes(checked_paths.len);256 const gpa = diags.gpa;
261 try err.addMsg(format, args);257 const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
262 for (checked_paths) |path| {258 diags.mutex.lock();
263 try err.addNote("tried {s}", .{path});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}) };
264 }278 }
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 };
265 }299 }
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(
268 diags: *Diags,318 diags: *Diags,
269 path: Path,319 path: Path,
270 comptime format: []const u8,320 comptime format: []const u8,
271 args: anytype,321 args: anytype,
272 ) error{OutOfMemory}!void {322 ) error{LinkFailure} {
273 @branchHint(.cold);323 @branchHint(.cold);
274 var err = try diags.addErrorWithNotes(1);324 addParseError(diags, path, format, args);
275 try err.addMsg(format, args);325 return error.LinkFailure;
276 try err.addNote("while parsing {}", .{path});
277 }326 }
278327
279 pub fn setAllocFailure(diags: *Diags) void {328 pub fn setAllocFailure(diags: *Diags) void {
280 @branchHint(.cold);329 @branchHint(.cold);
330 diags.mutex.lock();
331 defer diags.mutex.unlock();
332 setAllocFailureLocked(diags);
333 }
334
335 fn setAllocFailureLocked(diags: *Diags) void {
281 log.debug("memory allocation failure", .{});336 log.debug("memory allocation failure", .{});
282 diags.flags.alloc_failure_occurred = true;337 diags.flags.alloc_failure_occurred = true;
283 }338 }
...@@ -727,7 +782,8 @@ pub const File = struct {...@@ -727,7 +782,8 @@ pub const File = struct {
727 FailedToEmit,782 FailedToEmit,
728 FileSystem,783 FileSystem,
729 FilesOpenedWithWrongFlags,784 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`.
731 FlushFailure,787 FlushFailure,
732 /// Indicates an error will be present in `Compilation.link_errors`.788 /// Indicates an error will be present in `Compilation.link_errors`.
733 LinkFailure,789 LinkFailure,
src/link/Elf.zig+191-175
...@@ -46,7 +46,7 @@ file_handles: std.ArrayListUnmanaged(File.Handle) = .empty,...@@ -46,7 +46,7 @@ file_handles: std.ArrayListUnmanaged(File.Handle) = .empty,
46zig_object_index: ?File.Index = null,46zig_object_index: ?File.Index = null,
47linker_defined_index: ?File.Index = null,47linker_defined_index: ?File.Index = null,
48objects: std.ArrayListUnmanaged(File.Index) = .empty,48objects: std.ArrayListUnmanaged(File.Index) = .empty,
49shared_objects: std.ArrayListUnmanaged(File.Index) = .empty,49shared_objects: std.StringArrayHashMapUnmanaged(File.Index) = .empty,
5050
51/// List of all output sections and their associated metadata.51/// List of all output sections and their associated metadata.
52sections: std.MultiArrayList(Section) = .{},52sections: std.MultiArrayList(Section) = .{},
...@@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{},...@@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{},
62section_indexes: SectionIndexes = .{},62section_indexes: SectionIndexes = .{},
6363
64page_size: u32,64page_size: u32,
65default_sym_version: elf.Elf64_Versym,65default_sym_version: elf.Versym,
6666
67/// .shstrtab buffer67/// .shstrtab buffer
68shstrtab: std.ArrayListUnmanaged(u8) = .empty,68shstrtab: std.ArrayListUnmanaged(u8) = .empty,
...@@ -75,7 +75,7 @@ dynsym: DynsymSection = .{},...@@ -75,7 +75,7 @@ dynsym: DynsymSection = .{},
75/// .dynstrtab buffer75/// .dynstrtab buffer
76dynstrtab: std.ArrayListUnmanaged(u8) = .empty,76dynstrtab: std.ArrayListUnmanaged(u8) = .empty,
77/// Version symbol table. Only populated and emitted when linking dynamically.77/// Version symbol table. Only populated and emitted when linking dynamically.
78versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty,78versym: std.ArrayListUnmanaged(elf.Versym) = .empty,
79/// .verneed section79/// .verneed section
80verneed: VerneedSection = .{},80verneed: VerneedSection = .{},
81/// .got section81/// .got section
...@@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,...@@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,
114merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,114merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,
115comment_merge_section_index: ?Merge.Section.Index = null,115comment_merge_section_index: ?Merge.Section.Index = null,
116116
117first_eflags: ?elf.Elf64_Word = null,117first_eflags: ?elf.Word = null,
118118
119const SectionIndexes = struct {119const SectionIndexes = struct {
120 copy_rel: ?u32 = null,120 copy_rel: ?u32 = null,
...@@ -265,10 +265,7 @@ pub fn createEmpty(...@@ -265,10 +265,7 @@ pub fn createEmpty(
265 };265 };
266266
267 const is_dyn_lib = output_mode == .Lib and link_mode == .dynamic;267 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)268 const default_sym_version: elf.Versym = if (is_dyn_lib or comp.config.rdynamic) .GLOBAL else .LOCAL;
269 elf.VER_NDX_GLOBAL
270 else
271 elf.VER_NDX_LOCAL;
272269
273 // If using LLD to link, this code should produce an object file so that it270 // If using LLD to link, this code should produce an object file so that it
274 // can be passed to LLD.271 // can be passed to LLD.
...@@ -794,58 +791,51 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -794,58 +791,51 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
794 // --verbose-link791 // --verbose-link
795 if (comp.verbose_link) try self.dumpArgv(comp);792 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);
798 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);795 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
799 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);796 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
800797
801 const csu = try comp.getCrtPaths(arena);798 const csu = try comp.getCrtPaths(arena);
802799
803 // csu prelude800 // csu prelude
804 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);801 if (csu.crt0) |path| parseObjectReportingFailure(self, path);
805 if (csu.crti) |path| try parseObjectReportingFailure(self, path);802 if (csu.crti) |path| parseObjectReportingFailure(self, path);
806 if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path);803 if (csu.crtbegin) |path| parseObjectReportingFailure(self, path);
807804
808 for (comp.objects) |obj| {805 for (comp.objects) |obj| {
809 if (obj.isObject()) {806 parseInputReportingFailure(self, obj.path, obj.needed, obj.must_link);
810 try parseObjectReportingFailure(self, obj.path);
811 } else {
812 try parseLibraryReportingFailure(self, .{ .path = obj.path }, obj.must_link);
813 }
814 }807 }
815808
816 // This is a set of object files emitted by clang in a single `build-exe` invocation.809 // This is a set of object files emitted by clang in a single `build-exe` invocation.
817 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up810 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
818 // in this set.811 // in this set.
819 for (comp.c_object_table.keys()) |key| {812 for (comp.c_object_table.keys()) |key| {
820 try parseObjectReportingFailure(self, key.status.success.object_path);813 parseObjectReportingFailure(self, key.status.success.object_path);
821 }814 }
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.?);818 if (comp.config.any_sanitize_thread) parseCrtFileReportingFailure(self, comp.tsan_lib.?);
826 if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);819 if (comp.config.any_fuzz) parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
827820
828 // libc821 // libc
829 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {822 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);
831 }824 }
832825
833 for (comp.system_libs.values()) |lib_info| {826 for (comp.system_libs.values()) |lib_info| {
834 try self.parseLibraryReportingFailure(.{827 parseInputReportingFailure(self, lib_info.path.?, lib_info.needed, false);
835 .needed = lib_info.needed,
836 .path = lib_info.path.?,
837 }, false);
838 }828 }
839829
840 // libc++ dep830 // libc++ dep
841 if (comp.config.link_libcpp) {831 if (comp.config.link_libcpp) {
842 try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);832 parseInputReportingFailure(self, comp.libcxxabi_static_lib.?.full_object_path, false, false);
843 try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);833 parseInputReportingFailure(self, comp.libcxx_static_lib.?.full_object_path, false, false);
844 }834 }
845835
846 // libunwind dep836 // libunwind dep
847 if (comp.config.link_libunwind) {837 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);
849 }839 }
850840
851 // libc dep841 // libc dep
...@@ -869,17 +859,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -869,17 +859,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
869 if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))859 if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))
870 break :success;860 break :success;
871861
872 try diags.reportMissingLibraryError(862 diags.addMissingLibraryError(
873 checked_paths.items,863 checked_paths.items,
874 "missing system library: '{s}' was not found",864 "missing system library: '{s}' was not found",
875 .{lib_name},865 .{lib_name},
876 );866 );
877
878 continue;867 continue;
879 }868 }
880869
881 const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));870 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);
883 }872 }
884 } else if (target.isGnuLibC()) {873 } else if (target.isGnuLibC()) {
885 for (glibc.libs) |lib| {874 for (glibc.libs) |lib| {
...@@ -890,17 +879,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -890,17 +879,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
890 const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{879 const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
891 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,880 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
892 }));881 }));
893 try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);882 parseInputReportingFailure(self, lib_path, false, false);
894 }883 }
895 try self.parseLibraryReportingFailure(.{884 parseInputReportingFailure(self, try comp.get_libc_crt_file(arena, "libc_nonshared.a"), false, false);
896 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
897 }, false);
898 } else if (target.isMusl()) {885 } else if (target.isMusl()) {
899 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {886 const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
900 .static => "libc.a",887 .static => "libc.a",
901 .dynamic => "libc.so",888 .dynamic => "libc.so",
902 });889 });
903 try self.parseLibraryReportingFailure(.{ .path = path }, false);890 parseInputReportingFailure(self, path, false, false);
904 } else {891 } else {
905 diags.flags.missing_libc = true;892 diags.flags.missing_libc = true;
906 }893 }
...@@ -912,35 +899,17 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -912,35 +899,17 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
912 // to be after the shared libraries, so they are picked up from the shared899 // to be after the shared libraries, so they are picked up from the shared
913 // libraries, not libcompiler_rt.900 // libraries, not libcompiler_rt.
914 if (comp.compiler_rt_lib) |crt_file| {901 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);
916 } else if (comp.compiler_rt_obj) |crt_file| {903 } 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);
918 }905 }
919906
920 // csu postlude907 // csu postlude
921 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);908 if (csu.crtend) |path| parseObjectReportingFailure(self, path);
922 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);909 if (csu.crtn) |path| parseObjectReportingFailure(self, path);
923910
924 if (diags.hasErrors()) return error.FlushFailure;911 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
944 // If we haven't already, create a linker-generated input file comprising of913 // If we haven't already, create a linker-generated input file comprising of
945 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.914 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
946 if (self.linker_defined_index == null) {915 if (self.linker_defined_index == null) {
...@@ -1372,42 +1341,51 @@ pub const ParseError = error{...@@ -1372,42 +1341,51 @@ pub const ParseError = error{
1372 UnknownFileType,1341 UnknownFileType,
1373} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;1342} || 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 {1344fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) void {
1376 if (crt_file.isObject()) {1345 parseInputReportingFailure(self, crt_file.full_object_path, false, false);
1377 try parseObjectReportingFailure(self, crt_file.full_object_path);
1378 } else {
1379 try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
1380 }
1381}1346}
13821347
1383pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {1348pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_link: bool) void {
1384 self.parseObject(path) catch |err| switch (err) {1349 const gpa = self.base.comp.gpa;
1385 error.LinkFailure => return, // already reported1350 const diags = &self.base.comp.link_diags;
1386 error.OutOfMemory => return error.OutOfMemory,1351 const target = self.getTarget();
1387 else => |e| try self.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),1352
1388 };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 }
1389}1379}
13901380
1391pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool) error{OutOfMemory}!void {1381pub fn parseObjectReportingFailure(self: *Elf, path: Path) void {
1392 self.parseLibrary(lib, must_link) catch |err| switch (err) {1382 const diags = &self.base.comp.link_diags;
1383 self.parseObject(path) catch |err| switch (err) {
1393 error.LinkFailure => return, // already reported1384 error.LinkFailure => return, // already reported
1394 error.OutOfMemory => return error.OutOfMemory,1385 else => |e| diags.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),
1395 else => |e| try self.addParseError(lib.path, "unable to parse library: {s}", .{@errorName(e)}),
1396 };1386 };
1397}1387}
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
1411fn parseObject(self: *Elf, path: Path) ParseError!void {1389fn parseObject(self: *Elf, path: Path) ParseError!void {
1412 const tracy = trace(@src());1390 const tracy = trace(@src());
1413 defer tracy.end();1391 defer tracy.end();
...@@ -1457,28 +1435,80 @@ fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {...@@ -1457,28 +1435,80 @@ fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
1457 }1435 }
1458}1436}
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 {
1461 const tracy = trace(@src());1446 const tracy = trace(@src());
1462 defer tracy.end();1447 defer tracy.end();
14631448
1464 const gpa = self.base.comp.gpa;
1465 const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});1449 const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
1466 defer handle.close();1450 defer handle.close();
14671451
1468 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1452 const stat = Stat.fromFs(try handle.stat());
1469 self.files.set(index, .{ .shared_object = .{1453 var header = try SharedObject.parseHeader(gpa, diags, lib.path, handle, stat, target);
1470 .path = .{1454 defer header.deinit(gpa);
1471 .root_dir = lib.path.root_dir,1455
1472 .sub_path = try gpa.dupe(u8, lib.path.sub_path),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 = .{},
1473 },1491 },
1474 .index = index,1492 });
1475 .needed = lib.needed,1493 const so = fileLookup(files.*, index).?.shared_object;
1476 .alive = lib.needed,
1477 } });
1478 try self.shared_objects.append(gpa, index);
14791494
1480 const shared_object = self.file(index).?.shared_object;1495 // TODO: save this work for later
1481 try shared_object.parse(self, handle);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 }
1482}1512}
14831513
1484fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {1514fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
...@@ -1537,7 +1567,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1537,7 +1567,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1537 }1567 }
1538 }1568 }
15391569
1540 try diags.reportMissingLibraryError(1570 diags.addMissingLibraryError(
1541 checked_paths.items,1571 checked_paths.items,
1542 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",1572 "missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
1543 .{ @as(Path, lib.path), script_arg.path },1573 .{ @as(Path, lib.path), script_arg.path },
...@@ -1546,26 +1576,16 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1546,26 +1576,16 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1546 }1576 }
15471577
1548 const full_path = Path.initCwd(test_path.items);1578 const full_path = Path.initCwd(test_path.items);
1549 self.parseLibrary(.{1579 parseInputReportingFailure(self, full_path, script_arg.needed, false);
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 };
1560 }1580 }
1561}1581}
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 {
1564 if (self.first_eflags == null) {1584 if (self.first_eflags == null) {
1565 self.first_eflags = e_flags;1585 self.first_eflags = e_flags;
1566 return; // there isn't anything to conflict with yet1586 return; // there isn't anything to conflict with yet
1567 }1587 }
1568 const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;1588 const self_eflags: *elf.Word = &self.first_eflags.?;
15691589
1570 switch (self.getTarget().cpu.arch) {1590 switch (self.getTarget().cpu.arch) {
1571 .riscv64 => {1591 .riscv64 => {
...@@ -1641,11 +1661,14 @@ fn accessLibPath(...@@ -1641,11 +1661,14 @@ fn accessLibPath(
1641/// 5. Remove references to dead objects/shared objects1661/// 5. Remove references to dead objects/shared objects
1642/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1662/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1643pub fn resolveSymbols(self: *Elf) !void {1663pub fn resolveSymbols(self: *Elf) !void {
1664 // This function mutates `shared_objects`.
1665 const shared_objects = &self.shared_objects;
1666
1644 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1667 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1645 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);1668 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1646 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1669 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1647 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);1670 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);
1649 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);1672 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
16501673
1651 // Mark live objects.1674 // Mark live objects.
...@@ -1662,11 +1685,14 @@ pub fn resolveSymbols(self: *Elf) !void {...@@ -1662,11 +1685,14 @@ pub fn resolveSymbols(self: *Elf) !void {
1662 _ = self.objects.orderedRemove(i);1685 _ = self.objects.orderedRemove(i);
1663 } else i += 1;1686 } else i += 1;
1664 }1687 }
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.
1665 i = 0;1691 i = 0;
1666 while (i < self.shared_objects.items.len) {1692 while (i < shared_objects.values().len) {
1667 const index = self.shared_objects.items[i];1693 const index = shared_objects.values()[i];
1668 if (!self.file(index).?.isAlive()) {1694 if (!self.file(index).?.isAlive()) {
1669 _ = self.shared_objects.orderedRemove(i);1695 _ = shared_objects.orderedRemoveAt(i);
1670 } else i += 1;1696 } else i += 1;
1671 }1697 }
16721698
...@@ -1687,7 +1713,7 @@ pub fn resolveSymbols(self: *Elf) !void {...@@ -1687,7 +1713,7 @@ pub fn resolveSymbols(self: *Elf) !void {
1687 // Re-resolve the symbols.1713 // Re-resolve the symbols.
1688 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);1714 if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
1689 for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);1715 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);
1691 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);1717 if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
1692}1718}
16931719
...@@ -1696,12 +1722,13 @@ pub fn resolveSymbols(self: *Elf) !void {...@@ -1696,12 +1722,13 @@ pub fn resolveSymbols(self: *Elf) !void {
1696/// This routine will prune unneeded objects extracted from archives and1722/// This routine will prune unneeded objects extracted from archives and
1697/// unneeded shared objects.1723/// unneeded shared objects.
1698fn markLive(self: *Elf) void {1724fn markLive(self: *Elf) void {
1725 const shared_objects = self.shared_objects.values();
1699 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);1726 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
1700 for (self.objects.items) |index| {1727 for (self.objects.items) |index| {
1701 const file_ptr = self.file(index).?;1728 const file_ptr = self.file(index).?;
1702 if (file_ptr.isAlive()) file_ptr.markLive(self);1729 if (file_ptr.isAlive()) file_ptr.markLive(self);
1703 }1730 }
1704 for (self.shared_objects.items) |index| {1731 for (shared_objects) |index| {
1705 const file_ptr = self.file(index).?;1732 const file_ptr = self.file(index).?;
1706 if (file_ptr.isAlive()) file_ptr.markLive(self);1733 if (file_ptr.isAlive()) file_ptr.markLive(self);
1707 }1734 }
...@@ -1716,6 +1743,7 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {...@@ -1716,6 +1743,7 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {
1716}1743}
17171744
1718fn markImportsExports(self: *Elf) void {1745fn markImportsExports(self: *Elf) void {
1746 const shared_objects = self.shared_objects.values();
1719 if (self.zigObjectPtr()) |zo| {1747 if (self.zigObjectPtr()) |zo| {
1720 zo.markImportsExports(self);1748 zo.markImportsExports(self);
1721 }1749 }
...@@ -1723,7 +1751,7 @@ fn markImportsExports(self: *Elf) void {...@@ -1723,7 +1751,7 @@ fn markImportsExports(self: *Elf) void {
1723 self.file(index).?.object.markImportsExports(self);1751 self.file(index).?.object.markImportsExports(self);
1724 }1752 }
1725 if (!self.isEffectivelyDynLib()) {1753 if (!self.isEffectivelyDynLib()) {
1726 for (self.shared_objects.items) |index| {1754 for (shared_objects) |index| {
1727 self.file(index).?.shared_object.markImportExports(self);1755 self.file(index).?.shared_object.markImportExports(self);
1728 }1756 }
1729 }1757 }
...@@ -1744,6 +1772,7 @@ fn claimUnresolved(self: *Elf) void {...@@ -1744,6 +1772,7 @@ fn claimUnresolved(self: *Elf) void {
1744/// alloc sections.1772/// alloc sections.
1745fn scanRelocs(self: *Elf) !void {1773fn scanRelocs(self: *Elf) !void {
1746 const gpa = self.base.comp.gpa;1774 const gpa = self.base.comp.gpa;
1775 const shared_objects = self.shared_objects.values();
17471776
1748 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);1777 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
1749 defer {1778 defer {
...@@ -1787,7 +1816,7 @@ fn scanRelocs(self: *Elf) !void {...@@ -1787,7 +1816,7 @@ fn scanRelocs(self: *Elf) !void {
1787 for (self.objects.items) |index| {1816 for (self.objects.items) |index| {
1788 try self.file(index).?.createSymbolIndirection(self);1817 try self.file(index).?.createSymbolIndirection(self);
1789 }1818 }
1790 for (self.shared_objects.items) |index| {1819 for (shared_objects) |index| {
1791 try self.file(index).?.createSymbolIndirection(self);1820 try self.file(index).?.createSymbolIndirection(self);
1792 }1821 }
1793 if (self.linkerDefinedPtr()) |obj| {1822 if (self.linkerDefinedPtr()) |obj| {
...@@ -1905,10 +1934,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1905,10 +1934,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1905 // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.1934 // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.
1906 const id_symlink_basename = "lld.id";1935 const id_symlink_basename = "lld.id";
19071936
1908 var man: Cache.Manifest = undefined;1937 var man: std.Build.Cache.Manifest = undefined;
1909 defer if (!self.base.disable_lld_caching) man.deinit();1938 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
1913 if (!self.base.disable_lld_caching) {1942 if (!self.base.disable_lld_caching) {
1914 man = comp.cache_parent.obtain();1943 man = comp.cache_parent.obtain();
...@@ -1988,7 +2017,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1988,7 +2017,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1988 digest = man.final();2017 digest = man.final();
19892018
1990 var prev_digest_buf: [digest.len]u8 = undefined;2019 var prev_digest_buf: [digest.len]u8 = undefined;
1991 const prev_digest: []u8 = Cache.readSmallFile(2020 const prev_digest: []u8 = std.Build.Cache.readSmallFile(
1992 directory.handle,2021 directory.handle,
1993 id_symlink_basename,2022 id_symlink_basename,
1994 &prev_digest_buf,2023 &prev_digest_buf,
...@@ -2442,7 +2471,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2442,7 +2471,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2442 if (!self.base.disable_lld_caching) {2471 if (!self.base.disable_lld_caching) {
2443 // Update the file with the digest. If it fails we can continue; it only2472 // Update the file with the digest. If it fails we can continue; it only
2444 // means that the next invocation will have an unnecessary cache miss.2473 // 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| {
2446 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});2475 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
2447 };2476 };
2448 // Again failure here only means an unnecessary cache miss.2477 // Again failure here only means an unnecessary cache miss.
...@@ -2899,6 +2928,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2899,6 +2928,7 @@ fn initSyntheticSections(self: *Elf) !void {
2899 const comp = self.base.comp;2928 const comp = self.base.comp;
2900 const target = self.getTarget();2929 const target = self.getTarget();
2901 const ptr_size = self.ptrWidthBytes();2930 const ptr_size = self.ptrWidthBytes();
2931 const shared_objects = self.shared_objects.values();
29022932
2903 const needs_eh_frame = blk: {2933 const needs_eh_frame = blk: {
2904 if (self.zigObjectPtr()) |zo|2934 if (self.zigObjectPtr()) |zo|
...@@ -3023,7 +3053,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3023,7 +3053,7 @@ fn initSyntheticSections(self: *Elf) !void {
3023 });3053 });
3024 }3054 }
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) {
3027 if (self.section_indexes.dynstrtab == null) {3057 if (self.section_indexes.dynstrtab == null) {
3028 self.section_indexes.dynstrtab = try self.addSection(.{3058 self.section_indexes.dynstrtab = try self.addSection(.{
3029 .name = try self.insertShString(".dynstr"),3059 .name = try self.insertShString(".dynstr"),
...@@ -3072,7 +3102,7 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3072,7 +3102,7 @@ fn initSyntheticSections(self: *Elf) !void {
30723102
3073 const needs_versions = for (self.dynsym.entries.items) |entry| {3103 const needs_versions = for (self.dynsym.entries.items) |entry| {
3074 const sym = self.symbol(entry.ref).?;3104 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;
3076 } else false;3106 } else false;
3077 if (needs_versions) {3107 if (needs_versions) {
3078 if (self.section_indexes.versym == null) {3108 if (self.section_indexes.versym == null) {
...@@ -3080,8 +3110,8 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -3080,8 +3110,8 @@ fn initSyntheticSections(self: *Elf) !void {
3080 .name = try self.insertShString(".gnu.version"),3110 .name = try self.insertShString(".gnu.version"),
3081 .flags = elf.SHF_ALLOC,3111 .flags = elf.SHF_ALLOC,
3082 .type = elf.SHT_GNU_VERSYM,3112 .type = elf.SHT_GNU_VERSYM,
3083 .addralign = @alignOf(elf.Elf64_Versym),3113 .addralign = @alignOf(elf.Versym),
3084 .entsize = @sizeOf(elf.Elf64_Versym),3114 .entsize = @sizeOf(elf.Versym),
3085 });3115 });
3086 }3116 }
3087 if (self.section_indexes.verneed == null) {3117 if (self.section_indexes.verneed == null) {
...@@ -3259,7 +3289,9 @@ fn sortInitFini(self: *Elf) !void {...@@ -3259,7 +3289,9 @@ fn sortInitFini(self: *Elf) !void {
3259fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {3289fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
3260 if (self.section_indexes.dynamic == null) return;3290 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| {
3263 const shared_object = self.file(index).?.shared_object;3295 const shared_object = self.file(index).?.shared_object;
3264 if (!shared_object.alive) continue;3296 if (!shared_object.alive) continue;
3265 try self.dynamic.addNeeded(shared_object, self);3297 try self.dynamic.addNeeded(shared_object, self);
...@@ -3283,7 +3315,7 @@ fn setVersionSymtab(self: *Elf) !void {...@@ -3283,7 +3315,7 @@ fn setVersionSymtab(self: *Elf) !void {
3283 const gpa = self.base.comp.gpa;3315 const gpa = self.base.comp.gpa;
3284 if (self.section_indexes.versym == null) return;3316 if (self.section_indexes.versym == null) return;
3285 try self.versym.resize(gpa, self.dynsym.count());3317 try self.versym.resize(gpa, self.dynsym.count());
3286 self.versym.items[0] = elf.VER_NDX_LOCAL;3318 self.versym.items[0] = .LOCAL;
3287 for (self.dynsym.entries.items, 1..) |entry, i| {3319 for (self.dynsym.entries.items, 1..) |entry, i| {
3288 const sym = self.symbol(entry.ref).?;3320 const sym = self.symbol(entry.ref).?;
3289 self.versym.items[i] = sym.version_index;3321 self.versym.items[i] = sym.version_index;
...@@ -3653,7 +3685,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3653,7 +3685,7 @@ fn updateSectionSizes(self: *Elf) !void {
3653 }3685 }
36543686
3655 if (self.section_indexes.versym) |index| {3687 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);
3657 }3689 }
36583690
3659 if (self.section_indexes.verneed) |index| {3691 if (self.section_indexes.verneed) |index| {
...@@ -4055,13 +4087,15 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4055,13 +4087,15 @@ pub fn updateSymtabSize(self: *Elf) !void {
4055 var strsize: u32 = 0;4087 var strsize: u32 = 0;
40564088
4057 const gpa = self.base.comp.gpa;4089 const gpa = self.base.comp.gpa;
4090 const shared_objects = self.shared_objects.values();
4091
4058 var files = std.ArrayList(File.Index).init(gpa);4092 var files = std.ArrayList(File.Index).init(gpa);
4059 defer files.deinit();4093 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
4062 if (self.zig_object_index) |index| files.appendAssumeCapacity(index);4096 if (self.zig_object_index) |index| files.appendAssumeCapacity(index);
4063 for (self.objects.items) |index| files.appendAssumeCapacity(index);4097 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);
4065 if (self.linker_defined_index) |index| files.appendAssumeCapacity(index);4099 if (self.linker_defined_index) |index| files.appendAssumeCapacity(index);
40664100
4067 // Section symbols4101 // Section symbols
...@@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void {...@@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void {
42844318
4285pub fn writeSymtab(self: *Elf) !void {4319pub fn writeSymtab(self: *Elf) !void {
4286 const gpa = self.base.comp.gpa;4320 const gpa = self.base.comp.gpa;
4321 const shared_objects = self.shared_objects.values();
4322
4287 const slice = self.sections.slice();4323 const slice = self.sections.slice();
4288 const symtab_shdr = slice.items(.shdr)[self.section_indexes.symtab.?];4324 const symtab_shdr = slice.items(.shdr)[self.section_indexes.symtab.?];
4289 const strtab_shdr = slice.items(.shdr)[self.section_indexes.strtab.?];4325 const strtab_shdr = slice.items(.shdr)[self.section_indexes.strtab.?];
...@@ -4335,7 +4371,7 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -4335,7 +4371,7 @@ pub fn writeSymtab(self: *Elf) !void {
4335 file_ptr.writeSymtab(self);4371 file_ptr.writeSymtab(self);
4336 }4372 }
43374373
4338 for (self.shared_objects.items) |index| {4374 for (shared_objects) |index| {
4339 const file_ptr = self.file(index).?;4375 const file_ptr = self.file(index).?;
4340 file_ptr.writeSymtab(self);4376 file_ptr.writeSymtab(self);
4341 }4377 }
...@@ -4368,8 +4404,8 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -4368,8 +4404,8 @@ pub fn writeSymtab(self: *Elf) !void {
4368 .st_info = sym.st_info,4404 .st_info = sym.st_info,
4369 .st_other = sym.st_other,4405 .st_other = sym.st_other,
4370 .st_shndx = sym.st_shndx,4406 .st_shndx = sym.st_shndx,
4371 .st_value = @as(u32, @intCast(sym.st_value)),4407 .st_value = @intCast(sym.st_value),
4372 .st_size = @as(u32, @intCast(sym.st_size)),4408 .st_size = @intCast(sym.st_size),
4373 };4409 };
4374 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);4410 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
4375 }4411 }
...@@ -4925,18 +4961,6 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {...@@ -4925,18 +4961,6 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
4925 });4961 });
4926}4962}
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
4940pub fn addFileError(4964pub fn addFileError(
4941 self: *Elf,4965 self: *Elf,
4942 file_index: File.Index,4966 file_index: File.Index,
...@@ -4959,16 +4983,6 @@ pub fn failFile(...@@ -4959,16 +4983,6 @@ pub fn failFile(
4959 return error.LinkFailure;4983 return error.LinkFailure;
4960}4984}
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
4972const FormatShdrCtx = struct {4986const FormatShdrCtx = struct {
4973 elf_file: *Elf,4987 elf_file: *Elf,
4974 shdr: elf.Elf64_Shdr,4988 shdr: elf.Elf64_Shdr,
...@@ -5113,6 +5127,8 @@ fn fmtDumpState(...@@ -5113,6 +5127,8 @@ fn fmtDumpState(
5113 _ = unused_fmt_string;5127 _ = unused_fmt_string;
5114 _ = options;5128 _ = options;
51155129
5130 const shared_objects = self.shared_objects.values();
5131
5116 if (self.zigObjectPtr()) |zig_object| {5132 if (self.zigObjectPtr()) |zig_object| {
5117 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });5133 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
5118 try writer.print("{}{}", .{5134 try writer.print("{}{}", .{
...@@ -5136,11 +5152,11 @@ fn fmtDumpState(...@@ -5136,11 +5152,11 @@ fn fmtDumpState(
5136 });5152 });
5137 }5153 }
51385154
5139 for (self.shared_objects.items) |index| {5155 for (shared_objects) |index| {
5140 const shared_object = self.file(index).?.shared_object;5156 const shared_object = self.file(index).?.shared_object;
5141 try writer.print("shared_object({d}) : ", .{index});5157 try writer.print("shared_object({d}) : {} : needed({})", .{
5142 try writer.print("{}", .{shared_object.path});5158 index, shared_object.path, shared_object.needed,
5143 try writer.print(" : needed({})", .{shared_object.needed});5159 });
5144 if (!shared_object.alive) try writer.writeAll(" : [*]");5160 if (!shared_object.alive) try writer.writeAll(" : [*]");
5145 try writer.writeByte('\n');5161 try writer.writeByte('\n');
5146 try writer.print("{}\n", .{shared_object.fmtSymtab(self)});5162 try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
...@@ -5204,10 +5220,7 @@ pub fn preadAllAlloc(allocator: Allocator, handle: fs.File, offset: u64, size: u...@@ -5204,10 +5220,7 @@ pub fn preadAllAlloc(allocator: Allocator, handle: fs.File, offset: u64, size: u
5204}5220}
52055221
5206/// Binary search5222/// Binary search
5207pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {5223pub fn bsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
5208 if (!@hasDecl(@TypeOf(predicate), "predicate"))
5209 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
5210
5211 var min: usize = 0;5224 var min: usize = 0;
5212 var max: usize = haystack.len;5225 var max: usize = haystack.len;
5213 while (min < max) {5226 while (min < max) {
...@@ -5223,10 +5236,7 @@ pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp...@@ -5223,10 +5236,7 @@ pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp
5223}5236}
52245237
5225/// Linear search5238/// Linear search
5226pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {5239pub fn lsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
5227 if (!@hasDecl(@TypeOf(predicate), "predicate"))
5228 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
5229
5230 var i: usize = 0;5240 var i: usize = 0;
5231 while (i < haystack.len) : (i += 1) {5241 while (i < haystack.len) : (i += 1) {
5232 if (predicate.predicate(haystack[i])) break;5242 if (predicate.predicate(haystack[i])) break;
...@@ -5569,6 +5579,11 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {...@@ -5569,6 +5579,11 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
5569 }5579 }
5570}5580}
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
5572const std = @import("std");5587const std = @import("std");
5573const build_options = @import("build_options");5588const build_options = @import("build_options");
5574const builtin = @import("builtin");5589const builtin = @import("builtin");
...@@ -5581,8 +5596,9 @@ const state_log = std.log.scoped(.link_state);...@@ -5581,8 +5596,9 @@ const state_log = std.log.scoped(.link_state);
5581const math = std.math;5596const math = std.math;
5582const mem = std.mem;5597const mem = std.mem;
5583const Allocator = std.mem.Allocator;5598const Allocator = std.mem.Allocator;
5584const Cache = std.Build.Cache;
5585const Hash = std.hash.Wyhash;5599const Hash = std.hash.Wyhash;
5600const Path = std.Build.Cache.Path;
5601const Stat = std.Build.Cache.File.Stat;
55865602
5587const codegen = @import("../codegen.zig");5603const codegen = @import("../codegen.zig");
5588const dev = @import("../dev.zig");5604const dev = @import("../dev.zig");
...@@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig");...@@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig");
5601const Air = @import("../Air.zig");5617const Air = @import("../Air.zig");
5602const Archive = @import("Elf/Archive.zig");5618const Archive = @import("Elf/Archive.zig");
5603const AtomList = @import("Elf/AtomList.zig");5619const AtomList = @import("Elf/AtomList.zig");
5604const Path = Cache.Path;
5605const Compilation = @import("../Compilation.zig");5620const Compilation = @import("../Compilation.zig");
5606const ComdatGroupSection = synthetic_sections.ComdatGroupSection;5621const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
5607const CopyRelSection = synthetic_sections.CopyRelSection;5622const CopyRelSection = synthetic_sections.CopyRelSection;
5623const Diags = @import("../link.zig").Diags;
5608const DynamicSection = synthetic_sections.DynamicSection;5624const DynamicSection = synthetic_sections.DynamicSection;
5609const DynsymSection = synthetic_sections.DynsymSection;5625const DynsymSection = synthetic_sections.DynsymSection;
5610const Dwarf = @import("Dwarf.zig");5626const Dwarf = @import("Dwarf.zig");
src/link/Elf/Archive.zig+2-10
...@@ -1,15 +1,6 @@...@@ -1,15 +1,6 @@
1objects: std.ArrayListUnmanaged(Object) = .empty,1objects: std.ArrayListUnmanaged(Object) = .empty,
2strtab: std.ArrayListUnmanaged(u8) = .empty,2strtab: 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
13pub fn deinit(self: *Archive, allocator: Allocator) void {4pub fn deinit(self: *Archive, allocator: Allocator) void {
14 self.objects.deinit(allocator);5 self.objects.deinit(allocator);
15 self.strtab.deinit(allocator);6 self.strtab.deinit(allocator);
...@@ -18,6 +9,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {...@@ -18,6 +9,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
18pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {9pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
19 const comp = elf_file.base.comp;10 const comp = elf_file.base.comp;
20 const gpa = comp.gpa;11 const gpa = comp.gpa;
12 const diags = &comp.link_diags;
21 const handle = elf_file.fileHandle(handle_index);13 const handle = elf_file.fileHandle(handle_index);
22 const size = (try handle.stat()).size;14 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...@@ -35,7 +27,7 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
35 pos += @sizeOf(elf.ar_hdr);27 pos += @sizeOf(elf.ar_hdr);
3628
37 if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {29 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}", .{
39 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),31 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
40 });32 });
41 }33 }
src/link/Elf/Atom.zig+1
...@@ -592,6 +592,7 @@ fn reportUndefined(...@@ -592,6 +592,7 @@ fn reportUndefined(
592 const file_ptr = self.file(elf_file).?;592 const file_ptr = self.file(elf_file).?;
593 const rel_esym = switch (file_ptr) {593 const rel_esym = switch (file_ptr) {
594 .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),594 .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),
595 .shared_object => |so| so.parsed.symtab[rel.r_sym()],
595 inline else => |x| x.symtab.items[rel.r_sym()],596 inline else => |x| x.symtab.items[rel.r_sym()],
596 };597 };
597 const esym = sym.elfSym(elf_file);598 const esym = sym.elfSym(elf_file);
src/link/Elf/LdScript.zig+4-2
...@@ -21,6 +21,8 @@ pub const Error = error{...@@ -21,6 +21,8 @@ pub const Error = error{
21pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {21pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
22 const comp = elf_file.base.comp;22 const comp = elf_file.base.comp;
23 const gpa = comp.gpa;23 const gpa = comp.gpa;
24 const diags = &comp.link_diags;
25
24 var tokenizer = Tokenizer{ .source = data };26 var tokenizer = Tokenizer{ .source = data };
25 var tokens = std.ArrayList(Token).init(gpa);27 var tokens = std.ArrayList(Token).init(gpa);
26 defer tokens.deinit();28 defer tokens.deinit();
...@@ -37,7 +39,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -37,7 +39,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
37 try line_col.append(.{ .line = line, .column = column });39 try line_col.append(.{ .line = line, .column = column });
38 switch (tok.id) {40 switch (tok.id) {
39 .invalid => {41 .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})", .{
41 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,43 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
42 });44 });
43 },45 },
...@@ -61,7 +63,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -61,7 +63,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
61 const last_token_id = parser.it.pos - 1;63 const last_token_id = parser.it.pos - 1;
62 const last_token = parser.it.get(last_token_id);64 const last_token = parser.it.get(last_token_id);
63 const lcol = line_col.items[last_token_id];65 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})", .{
65 @tagName(last_token.id),67 @tagName(last_token.id),
66 last_token.get(data),68 last_token.get(data),
67 lcol.line,69 lcol.line,
src/link/Elf/Object.zig+5-4
...@@ -310,7 +310,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {...@@ -310,7 +310,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
310 sym_ptr.name_offset = sym.st_name;310 sym_ptr.name_offset = sym.st_name;
311 sym_ptr.esym_index = @intCast(i);311 sym_ptr.esym_index = @intCast(i);
312 sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});312 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;
314 sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;314 sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
315 if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {315 if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
316 sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };316 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 {...@@ -536,7 +536,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
536 sym.ref = .{ .index = 0, .file = 0 };536 sym.ref = .{ .index = 0, .file = 0 };
537 sym.esym_index = esym_index;537 sym.esym_index = esym_index;
538 sym.file_index = self.index;538 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;
540 sym.flags.import = is_import;540 sym.flags.import = is_import;
541541
542 const idx = self.symbols_resolver.items[i];542 const idx = self.symbols_resolver.items[i];
...@@ -598,8 +598,9 @@ pub fn markImportsExports(self: *Object, elf_file: *Elf) void {...@@ -598,8 +598,9 @@ pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
598 const ref = self.resolveSymbol(@intCast(idx), elf_file);598 const ref = self.resolveSymbol(@intCast(idx), elf_file);
599 const sym = elf_file.symbol(ref) orelse continue;599 const sym = elf_file.symbol(ref) orelse continue;
600 const file = sym.file(elf_file).?;600 const file = sym.file(elf_file).?;
601 if (sym.version_index == elf.VER_NDX_LOCAL) continue;601 // https://github.com/ziglang/zig/issues/21678
602 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));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);
603 if (vis == .HIDDEN) continue;604 if (vis == .HIDDEN) continue;
604 if (file == .shared_object and !sym.isAbs(elf_file)) {605 if (file == .shared_object and !sym.isAbs(elf_file)) {
605 sym.flags.import = true;606 sym.flags.import = true;
src/link/Elf/SharedObject.zig+281-227
...@@ -1,236 +1,316 @@...@@ -1,236 +1,316 @@
1path: Path,1path: Path,
2index: File.Index,2index: File.Index,
33
4header: ?elf.Elf64_Ehdr = null,4parsed: Parsed,
5shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .empty,
65
7symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty,6symbols: std.ArrayListUnmanaged(Symbol),
8strtab: std.ArrayListUnmanaged(u8) = .empty,7symbols_extra: std.ArrayListUnmanaged(u32),
9/// Version symtab contains version strings of the symbols if present.8symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index),
10versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty,
11verstrings: std.ArrayListUnmanaged(u32) = .empty,
129
13symbols: std.ArrayListUnmanaged(Symbol) = .empty,10aliases: ?std.ArrayListUnmanaged(u32),
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,
1911
20needed: bool,12needed: bool,
21alive: bool,13alive: bool,
2214
23output_symtab_ctx: Elf.SymtabCtx = .{},15output_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}
3516
36pub fn deinit(self: *SharedObject, allocator: Allocator) void {17pub fn deinit(so: *SharedObject, gpa: Allocator) void {
37 allocator.free(self.path.sub_path);18 gpa.free(so.path.sub_path);
38 self.shdrs.deinit(allocator);19 so.parsed.deinit(gpa);
39 self.symtab.deinit(allocator);20 so.symbols.deinit(gpa);
40 self.strtab.deinit(allocator);21 so.symbols_extra.deinit(gpa);
41 self.versyms.deinit(allocator);22 so.symbols_resolver.deinit(gpa);
42 self.verstrings.deinit(allocator);23 if (so.aliases) |*aliases| aliases.deinit(gpa);
43 self.symbols.deinit(allocator);24 so.* = undefined;
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);
48}25}
4926
50pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {27pub const Header = struct {
51 const comp = elf_file.base.comp;28 dynamic_table: []const elf.Elf64_Dyn,
52 const gpa = comp.gpa;29 soname_index: ?u32,
53 const file_size = (try handle.stat()).size;30 verdefnum: ?u32,
5431
55 const header_buffer = try Elf.preadAllAlloc(gpa, handle, 0, @sizeOf(elf.Elf64_Ehdr));32 sections: []const elf.Elf64_Shdr,
56 defer gpa.free(header_buffer);33 dynsym_sect_index: ?u32,
57 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;34 versym_sect_index: ?u32,
35 verdef_sect_index: ?u32,
5836
59 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();37 stat: Stat,
60 if (em != self.header.?.e_machine) {38 strtab: std.ArrayListUnmanaged(u8),
61 return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{39
62 @tagName(self.header.?.e_machine),40 pub fn deinit(header: *Header, gpa: Allocator) void {
63 });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);
64 }84 }
6585
66 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;86 pub fn soname(p: Parsed) ?[]const u8 {
67 const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;87 const i = p.soname_index orelse return null;
68 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);88 return Elf.stringTableLookup(p.strtab, i);
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", .{});
71 }89 }
90};
7291
73 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize);92pub fn parseHeader(
74 defer gpa.free(shdrs_buffer);93 gpa: Allocator,
75 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];94 diags: *Diags,
76 try self.shdrs.appendUnalignedSlice(gpa, shdrs);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
78 var dynsym_sect_index: ?u32 = null;124 var dynsym_sect_index: ?u32 = null;
79 var dynamic_sect_index: ?u32 = null;125 var dynamic_sect_index: ?u32 = null;
80 var versym_sect_index: ?u32 = null;126 var versym_sect_index: ?u32 = null;
81 var verdef_sect_index: ?u32 = null;127 var verdef_sect_index: ?u32 = null;
82 for (self.shdrs.items, 0..) |shdr, i| {128 for (sections, 0..) |shdr, i_usize| {
83 if (shdr.sh_type != elf.SHT_NOBITS) {129 const i: u32 = @intCast(i_usize);
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 }
88 switch (shdr.sh_type) {130 switch (shdr.sh_type) {
89 elf.SHT_DYNSYM => dynsym_sect_index = @intCast(i),131 elf.SHT_DYNSYM => dynsym_sect_index = i,
90 elf.SHT_DYNAMIC => dynamic_sect_index = @intCast(i),132 elf.SHT_DYNAMIC => dynamic_sect_index = i,
91 elf.SHT_GNU_VERSYM => versym_sect_index = @intCast(i),133 elf.SHT_GNU_VERSYM => versym_sect_index = i,
92 elf.SHT_GNU_VERDEF => verdef_sect_index = @intCast(i),134 elf.SHT_GNU_VERDEF => verdef_sect_index = i,
93 else => {},135 else => continue,
94 }136 }
95 }137 }
96138
97 if (dynamic_sect_index) |index| {139 const dynamic_table: []elf.Elf64_Dyn = if (dynamic_sect_index) |index| dt: {
98 const shdr = self.shdrs.items[index];140 const shdr = sections[index];
99 const raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);141 const n = shdr.sh_size / @sizeOf(elf.Elf64_Dyn);
100 defer gpa.free(raw);142 const dynamic_table = try gpa.alloc(elf.Elf64_Dyn, n);
101 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Dyn));143 errdefer gpa.free(dynamic_table);
102 const dyntab = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(raw.ptr))[0..num];144 const buf = mem.sliceAsBytes(dynamic_table);
103 try self.dynamic_table.appendUnalignedSlice(gpa, dyntab);145 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
146 if (amt != buf.len) return error.UnexpectedEndOfFile;
147 break :dt dynamic_table;
148 } else &.{};
149 errdefer gpa.free(dynamic_table);
150
151 var strtab: std.ArrayListUnmanaged(u8) = .empty;
152 errdefer strtab.deinit(gpa);
153
154 if (dynsym_sect_index) |index| {
155 const dynsym_shdr = sections[index];
156 if (dynsym_shdr.sh_link >= sections.len) return error.BadStringTableIndex;
157 const strtab_shdr = sections[dynsym_shdr.sh_link];
158 const buf = try strtab.addManyAsSlice(gpa, strtab_shdr.sh_size);
159 const amt = try fs_file.preadAll(buf, strtab_shdr.sh_offset);
160 if (amt != buf.len) return error.UnexpectedEndOfFile;
104 }161 }
105162
106 const symtab = if (dynsym_sect_index) |index| blk: {163 var soname_index: ?u32 = null;
107 const shdr = self.shdrs.items[index];164 var verdefnum: ?u32 = null;
108 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);165 for (dynamic_table) |entry| switch (entry.d_tag) {
109 const nsyms = @divExact(buffer.len, @sizeOf(elf.Elf64_Sym));166 elf.DT_SONAME => {
110 break :blk @as([*]align(1) const elf.Elf64_Sym, @ptrCast(buffer.ptr))[0..nsyms];167 if (entry.d_val >= strtab.items.len) return error.BadSonameIndex;
111 } else &[0]elf.Elf64_Sym{};168 soname_index = @intCast(entry.d_val);
112 defer gpa.free(symtab);169 },
113170 elf.DT_VERDEFNUM => {
114 const strtab = if (dynsym_sect_index) |index| blk: {171 verdefnum = @intCast(entry.d_val);
115 const symtab_shdr = self.shdrs.items[index];172 },
116 const shdr = self.shdrs.items[symtab_shdr.sh_link];173 else => continue,
117 const buffer = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);174 };
118 break :blk buffer;
119 } else &[0]u8{};
120 defer gpa.free(strtab);
121175
122 try self.parseVersions(elf_file, handle, .{176 return .{
123 .symtab = symtab,177 .dynamic_table = dynamic_table,
124 .verdef_sect_index = verdef_sect_index,178 .soname_index = soname_index,
179 .verdefnum = verdefnum,
180 .sections = sections,
181 .dynsym_sect_index = dynsym_sect_index,
125 .versym_sect_index = versym_sect_index,182 .versym_sect_index = versym_sect_index,
126 });183 .verdef_sect_index = verdef_sect_index,
127
128 try self.initSymbols(elf_file, .{
129 .symtab = symtab,
130 .strtab = strtab,184 .strtab = strtab,
131 });185 .stat = stat,
186 };
132}187}
133188
134fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct {189pub fn parse(
135 symtab: []align(1) const elf.Elf64_Sym,190 gpa: Allocator,
136 verdef_sect_index: ?u32,191 /// Moves resources from header. Caller may unconditionally deinit.
137 versym_sect_index: ?u32,192 header: *Header,
138}) !void {193 fs_file: std.fs.File,
139 const comp = elf_file.base.comp;194) !Parsed {
140 const gpa = comp.gpa;195 const symtab = if (header.dynsym_sect_index) |index| st: {
196 const shdr = header.sections[index];
197 const n = shdr.sh_size / @sizeOf(elf.Elf64_Sym);
198 const symtab = try gpa.alloc(elf.Elf64_Sym, n);
199 errdefer gpa.free(symtab);
200 const buf = mem.sliceAsBytes(symtab);
201 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
202 if (amt != buf.len) return error.UnexpectedEndOfFile;
203 break :st symtab;
204 } else &.{};
205 defer gpa.free(symtab);
141206
142 try self.verstrings.resize(gpa, 2);207 var verstrings: std.ArrayListUnmanaged(u32) = .empty;
143 self.verstrings.items[elf.VER_NDX_LOCAL] = 0;208 defer verstrings.deinit(gpa);
144 self.verstrings.items[elf.VER_NDX_GLOBAL] = 0;
145209
146 if (opts.verdef_sect_index) |shndx| {210 if (header.verdef_sect_index) |shndx| {
147 const shdr = self.shdrs.items[shndx];211 const shdr = header.sections[shndx];
148 const verdefs = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);212 const verdefs = try Elf.preadAllAlloc(gpa, fs_file, shdr.sh_offset, shdr.sh_size);
149 defer gpa.free(verdefs);213 defer gpa.free(verdefs);
150 const nverdefs = self.verdefNum();
151 try self.verstrings.resize(gpa, self.verstrings.items.len + nverdefs);
152214
153 var i: u32 = 0;
154 var offset: u32 = 0;215 var offset: u32 = 0;
155 while (i < nverdefs) : (i += 1) {216 while (true) {
156 const verdef = @as(*align(1) const elf.Elf64_Verdef, @ptrCast(verdefs.ptr + offset)).*;217 const verdef = mem.bytesAsValue(elf.Verdef, verdefs[offset..][0..@sizeOf(elf.Verdef)]);
157 defer offset += verdef.vd_next;218 if (verdef.ndx == .UNSPECIFIED) return error.VerDefSymbolTooLarge;
158 if (verdef.vd_flags == elf.VER_FLG_BASE) continue; // Skip BASE entry219
159 const vda_name = if (verdef.vd_cnt > 0)220 if (verstrings.items.len <= @intFromEnum(verdef.ndx))
160 @as(*align(1) const elf.Elf64_Verdaux, @ptrCast(verdefs.ptr + offset + verdef.vd_aux)).vda_name221 try verstrings.appendNTimes(gpa, 0, @intFromEnum(verdef.ndx) + 1 - verstrings.items.len);
161 else
162 0;
163 self.verstrings.items[verdef.vd_ndx] = vda_name;
164 }
165 }
166222
167 try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len);223 const aux = mem.bytesAsValue(elf.Verdaux, verdefs[offset + verdef.aux ..][0..@sizeOf(elf.Verdaux)]);
168224 verstrings.items[@intFromEnum(verdef.ndx)] = aux.name;
169 if (opts.versym_sect_index) |shndx| {225
170 const shdr = self.shdrs.items[shndx];226 if (verdef.next == 0) break;
171 const versyms_raw = try Elf.preadAllAlloc(gpa, handle, shdr.sh_offset, shdr.sh_size);227 offset += verdef.next;
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);
181 }228 }
182 } else for (0..opts.symtab.len) |_| {
183 self.versyms.appendAssumeCapacity(elf.VER_NDX_GLOBAL);
184 }229 }
185}
186230
187fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct {231 const versyms = if (header.versym_sect_index) |versym_sect_index| vs: {
188 symtab: []align(1) const elf.Elf64_Sym,232 const shdr = header.sections[versym_sect_index];
189 strtab: []const u8,233 if (shdr.sh_size != symtab.len * @sizeOf(elf.Versym)) return error.BadVerSymSectionSize;
190}) !void {234
191 const gpa = elf_file.base.comp.gpa;235 const versyms = try gpa.alloc(elf.Versym, symtab.len);
192 const nsyms = opts.symtab.len;236 errdefer gpa.free(versyms);
193237 const buf = mem.sliceAsBytes(versyms);
194 try self.strtab.appendSlice(gpa, opts.strtab);238 const amt = try fs_file.preadAll(buf, shdr.sh_offset);
195 try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);239 if (amt != buf.len) return error.UnexpectedEndOfFile;
196 try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);240 break :vs versyms;
197 try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));241 } else &.{};
198 try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);242 defer gpa.free(versyms);
199 self.symbols_resolver.resize(gpa, nsyms) catch unreachable;243
200 @memset(self.symbols_resolver.items, 0);244 var nonlocal_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty;
201245 defer nonlocal_esyms.deinit(gpa);
202 for (opts.symtab, 0..) |sym, i| {246
203 const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;247 var nonlocal_versyms: std.ArrayListUnmanaged(elf.Versym) = .empty;
204 const name = self.getString(sym.st_name);248 defer nonlocal_versyms.deinit(gpa);
205 // We need to garble up the name so that we don't pick this symbol249
206 // during symbol resolution. Thank you GNU!250 var nonlocal_symbols: std.ArrayListUnmanaged(Parsed.Symbol) = .empty;
207 const name_off = if (hidden) blk: {251 defer nonlocal_symbols.deinit(gpa);
208 const mangled = try std.fmt.allocPrint(gpa, "{s}@{s}", .{252
209 name,253 var strtab = header.strtab;
210 self.versionString(self.versyms.items[i]),254 header.strtab = .empty;
211 });255 defer strtab.deinit(gpa);
212 defer gpa.free(mangled);256
213 break :blk try self.addString(gpa, mangled);257 for (symtab, 0..) |sym, i| {
214 } else sym.st_name;258 const ver: elf.Versym = if (versyms.len == 0 or sym.st_shndx == elf.SHN_UNDEF)
215 const out_esym_index: u32 = @intCast(self.symtab.items.len);259 .GLOBAL
216 const out_esym = self.symtab.addOneAssumeCapacity();260 else
217 out_esym.* = sym;261 .{ .VERSION = versyms[i].VERSION, .HIDDEN = false };
218 out_esym.st_name = name_off;262
219 const out_sym_index = self.addSymbolAssumeCapacity();263 // https://github.com/ziglang/zig/issues/21678
220 const out_sym = &self.symbols.items[out_sym_index];264 //if (ver == .LOCAL) continue;
221 out_sym.value = @intCast(out_esym.st_value);265 if (@as(u16, @bitCast(ver)) == 0) continue;
222 out_sym.name_offset = name_off;266
223 out_sym.ref = .{ .index = 0, .file = 0 };267 try nonlocal_esyms.ensureUnusedCapacity(gpa, 1);
224 out_sym.esym_index = out_esym_index;268 try nonlocal_versyms.ensureUnusedCapacity(gpa, 1);
225 out_sym.version_index = self.versyms.items[out_esym_index];269 try nonlocal_symbols.ensureUnusedCapacity(gpa, 1);
226 out_sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});270
271 const name = Elf.stringTableLookup(strtab.items, sym.st_name);
272 const is_default = versyms.len == 0 or !versyms[i].HIDDEN;
273 const mangled_name = if (is_default) sym.st_name else mn: {
274 const off: u32 = @intCast(strtab.items.len);
275 const version_string = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
276 try strtab.ensureUnusedCapacity(gpa, name.len + version_string.len + 2);
277 // Reload since the string table might have been resized.
278 const name2 = Elf.stringTableLookup(strtab.items, sym.st_name);
279 const version_string2 = versionStringLookup(strtab.items, verstrings.items, versyms[i]);
280 strtab.appendSliceAssumeCapacity(name2);
281 strtab.appendAssumeCapacity('@');
282 strtab.appendSliceAssumeCapacity(version_string2);
283 strtab.appendAssumeCapacity(0);
284 break :mn off;
285 };
286
287 nonlocal_esyms.appendAssumeCapacity(sym);
288 nonlocal_versyms.appendAssumeCapacity(ver);
289 nonlocal_symbols.appendAssumeCapacity(.{
290 .mangled_name = mangled_name,
291 });
227 }292 }
293
294 const sections = header.sections;
295 header.sections = &.{};
296 errdefer gpa.free(sections);
297
298 return .{
299 .sections = sections,
300 .stat = header.stat,
301 .soname_index = header.soname_index,
302 .strtab = try strtab.toOwnedSlice(gpa),
303 .symtab = try nonlocal_esyms.toOwnedSlice(gpa),
304 .versyms = try nonlocal_versyms.toOwnedSlice(gpa),
305 .symbols = try nonlocal_symbols.toOwnedSlice(gpa),
306 .verstrings = try verstrings.toOwnedSlice(gpa),
307 };
228}308}
229309
230pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {310pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
231 const gpa = elf_file.base.comp.gpa;311 const gpa = elf_file.base.comp.gpa;
232312
233 for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {313 for (self.parsed.symtab, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
234 const gop = try elf_file.resolver.getOrPut(gpa, .{314 const gop = try elf_file.resolver.getOrPut(gpa, .{
235 .index = @intCast(i),315 .index = @intCast(i),
236 .file = self.index,316 .file = self.index,
...@@ -253,7 +333,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {...@@ -253,7 +333,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
253}333}
254334
255pub fn markLive(self: *SharedObject, elf_file: *Elf) void {335pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
256 for (self.symtab.items, 0..) |esym, i| {336 for (self.parsed.symtab, 0..) |esym, i| {
257 if (esym.st_shndx != elf.SHN_UNDEF) continue;337 if (esym.st_shndx != elf.SHN_UNDEF) continue;
258338
259 const ref = self.resolveSymbol(@intCast(i), elf_file);339 const ref = self.resolveSymbol(@intCast(i), elf_file);
...@@ -308,29 +388,21 @@ pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {...@@ -308,29 +388,21 @@ pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
308 }388 }
309}389}
310390
311pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 {391pub fn versionString(self: SharedObject, index: elf.Versym) [:0]const u8 {
312 const off = self.verstrings.items[index & elf.VERSYM_VERSION];392 return self.parsed.versionString(index);
313 return self.getString(off);
314}393}
315394
316pub fn asFile(self: *SharedObject) File {395fn versionStringLookup(strtab: []const u8, verstrings: []const u32, index: elf.Versym) [:0]const u8 {
317 return .{ .shared_object = self };396 const off = verstrings[index.VERSION];
397 return Elf.stringTableLookup(strtab, off);
318}398}
319399
320fn verdefNum(self: *SharedObject) u32 {400pub fn asFile(self: *SharedObject) File {
321 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {401 return .{ .shared_object = self };
322 elf.DT_VERDEFNUM => return @intCast(entry.d_val),
323 else => {},
324 };
325 return 0;
326}402}
327403
328pub fn soname(self: *SharedObject) []const u8 {404pub fn soname(self: *SharedObject) []const u8 {
329 for (self.dynamic_table.items) |entry| switch (entry.d_tag) {405 return self.parsed.soname() orelse self.path.basename();
330 elf.DT_SONAME => return self.getString(@intCast(entry.d_val)),
331 else => {},
332 };
333 return std.fs.path.basename(self.path.sub_path);
334}406}
335407
336pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {408pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
...@@ -360,7 +432,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {...@@ -360,7 +432,7 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
360 aliases.appendAssumeCapacity(@intCast(index));432 aliases.appendAssumeCapacity(@intCast(index));
361 }433 }
362434
363 std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);435 mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
364436
365 self.aliases = aliases.moveToUnmanaged();437 self.aliases = aliases.moveToUnmanaged();
366}438}
...@@ -384,17 +456,8 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3...@@ -384,17 +456,8 @@ pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u3
384 return aliases.items[start..end];456 return aliases.items[start..end];
385}457}
386458
387fn addString(self: *SharedObject, allocator: Allocator, str: []const u8) !u32 {
388 const off: u32 = @intCast(self.strtab.items.len);
389 try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
390 self.strtab.appendSliceAssumeCapacity(str);
391 self.strtab.appendAssumeCapacity(0);
392 return off;
393}
394
395pub fn getString(self: SharedObject, off: u32) [:0]const u8 {459pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
396 assert(off < self.strtab.items.len);460 return Elf.stringTableLookup(self.parsed.strtab, off);
397 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
398}461}
399462
400pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {463pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
...@@ -402,25 +465,14 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El...@@ -402,25 +465,14 @@ pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) El
402 return elf_file.resolver.get(resolv).?;465 return elf_file.resolver.get(resolv).?;
403}466}
404467
405fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index {468pub fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
406 try self.symbols.ensureUnusedCapacity(allocator, 1);
407 return self.addSymbolAssumeCapacity();
408}
409
410fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
411 const index: Symbol.Index = @intCast(self.symbols.items.len);469 const index: Symbol.Index = @intCast(self.symbols.items.len);
412 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });470 self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
413 return index;471 return index;
414}472}
415473
416pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
417 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
418 try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
419 return self.addSymbolExtraAssumeCapacity(extra);
420}
421
422pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {474pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
423 const index = @as(u32, @intCast(self.symbols_extra.items.len));475 const index: u32 = @intCast(self.symbols_extra.items.len);
424 const fields = @typeInfo(Symbol.Extra).@"struct".fields;476 const fields = @typeInfo(Symbol.Extra).@"struct".fields;
425 inline for (fields) |field| {477 inline for (fields) |field| {
426 self.symbols_extra.appendAssumeCapacity(switch (field.type) {478 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
...@@ -465,7 +517,7 @@ pub fn format(...@@ -465,7 +517,7 @@ pub fn format(
465 _ = unused_fmt_string;517 _ = unused_fmt_string;
466 _ = options;518 _ = options;
467 _ = writer;519 _ = writer;
468 @compileError("do not format shared objects directly");520 @compileError("unreachable");
469}521}
470522
471pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {523pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
...@@ -509,8 +561,10 @@ const elf = std.elf;...@@ -509,8 +561,10 @@ const elf = std.elf;
509const log = std.log.scoped(.elf);561const log = std.log.scoped(.elf);
510const mem = std.mem;562const mem = std.mem;
511const Path = std.Build.Cache.Path;563const Path = std.Build.Cache.Path;
512564const Stat = std.Build.Cache.File.Stat;
513const Allocator = mem.Allocator;565const Allocator = mem.Allocator;
566
514const Elf = @import("../Elf.zig");567const Elf = @import("../Elf.zig");
515const File = @import("file.zig").File;568const File = @import("file.zig").File;
516const Symbol = @import("Symbol.zig");569const Symbol = @import("Symbol.zig");
570const Diags = @import("../../link.zig").Diags;
src/link/Elf/Symbol.zig+5-4
...@@ -22,7 +22,7 @@ esym_index: Index = 0,...@@ -22,7 +22,7 @@ esym_index: Index = 0,
2222
23/// Index of the source version symbol this symbol references if any.23/// Index of the source version symbol this symbol references if any.
24/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.24/// 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
27/// Misc flags for the symbol packaged as packed struct for compression.27/// Misc flags for the symbol packaged as packed struct for compression.
28flags: Flags = .{},28flags: Flags = .{},
...@@ -87,6 +87,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -87,6 +87,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
87pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {87pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
88 return switch (symbol.file(elf_file).?) {88 return switch (symbol.file(elf_file).?) {
89 .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],89 .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],
90 .shared_object => |so| so.parsed.symtab[symbol.esym_index],
90 inline else => |x| x.symtab.items[symbol.esym_index],91 inline else => |x| x.symtab.items[symbol.esym_index],
91 };92 };
92}93}
...@@ -235,7 +236,7 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {...@@ -235,7 +236,7 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
235 assert(file_ptr == .shared_object);236 assert(file_ptr == .shared_object);
236 const shared_object = file_ptr.shared_object;237 const shared_object = file_ptr.shared_object;
237 const esym = symbol.elfSym(elf_file);238 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];
239 const alignment = @max(1, shdr.sh_addralign);240 const alignment = @max(1, shdr.sh_addralign);
240 return if (esym.st_value == 0)241 return if (esym.st_value == 0)
241 alignment242 alignment
...@@ -351,8 +352,8 @@ fn formatName(...@@ -351,8 +352,8 @@ fn formatName(
351 const elf_file = ctx.elf_file;352 const elf_file = ctx.elf_file;
352 const symbol = ctx.symbol;353 const symbol = ctx.symbol;
353 try writer.writeAll(symbol.name(elf_file));354 try writer.writeAll(symbol.name(elf_file));
354 switch (symbol.version_index & elf.VERSYM_VERSION) {355 switch (symbol.version_index.VERSION) {
355 elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},356 @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {},
356 else => {357 else => {
357 const file_ptr = symbol.file(elf_file).?;358 const file_ptr = symbol.file(elf_file).?;
358 assert(file_ptr == .shared_object);359 assert(file_ptr == .shared_object);
src/link/Elf/ZigObject.zig+5-4
...@@ -264,7 +264,7 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {...@@ -264,7 +264,7 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
264 }264 }
265}265}
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 {
268 // Handle any lazy symbols that were emitted by incremental compilation.268 // Handle any lazy symbols that were emitted by incremental compilation.
269 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {269 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
270 const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.zcu.?, .tid = tid };270 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 {...@@ -623,7 +623,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
623 global.ref = .{ .index = 0, .file = 0 };623 global.ref = .{ .index = 0, .file = 0 };
624 global.esym_index = @intCast(index);624 global.esym_index = @intCast(index);
625 global.file_index = self.index;625 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;
627 global.flags.import = is_import;627 global.flags.import = is_import;
628628
629 const idx = self.symbols_resolver.items[i];629 const idx = self.symbols_resolver.items[i];
...@@ -689,8 +689,9 @@ pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {...@@ -689,8 +689,9 @@ pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
689 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);689 const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
690 const sym = elf_file.symbol(ref) orelse continue;690 const sym = elf_file.symbol(ref) orelse continue;
691 const file = sym.file(elf_file).?;691 const file = sym.file(elf_file).?;
692 if (sym.version_index == elf.VER_NDX_LOCAL) continue;692 // https://github.com/ziglang/zig/issues/21678
693 const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));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);
694 if (vis == .HIDDEN) continue;695 if (vis == .HIDDEN) continue;
695 if (file == .shared_object and !sym.isAbs(elf_file)) {696 if (file == .shared_object and !sym.isAbs(elf_file)) {
696 sym.flags.import = true;697 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...@@ -4,22 +4,22 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
44
5 for (comp.objects) |obj| {5 for (comp.objects) |obj| {
6 switch (Compilation.classifyFileExt(obj.path.sub_path)) {6 switch (Compilation.classifyFileExt(obj.path.sub_path)) {
7 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),7 .object => parseObjectStaticLibReportingFailure(elf_file, obj.path),
8 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),8 .static_library => parseArchiveStaticLibReportingFailure(elf_file, obj.path),
9 else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),9 else => diags.addParseError(obj.path, "unrecognized file extension", .{}),
10 }10 }
11 }11 }
1212
13 for (comp.c_object_table.keys()) |key| {13 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);
15 }15 }
1616
17 if (module_obj_path) |path| {17 if (module_obj_path) |path| {
18 try parseObjectStaticLibReportingFailure(elf_file, path);18 parseObjectStaticLibReportingFailure(elf_file, path);
19 }19 }
2020
21 if (comp.include_compiler_rt) {21 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);
23 }23 }
2424
25 if (diags.hasErrors()) return error.FlushFailure;25 if (diags.hasErrors()) return error.FlushFailure;
...@@ -154,21 +154,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l...@@ -154,21 +154,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
154 const diags = &comp.link_diags;154 const diags = &comp.link_diags;
155155
156 for (comp.objects) |obj| {156 for (comp.objects) |obj| {
157 if (obj.isObject()) {157 elf_file.parseInputReportingFailure(obj.path, false, obj.must_link);
158 try elf_file.parseObjectReportingFailure(obj.path);
159 } else {
160 try elf_file.parseLibraryReportingFailure(.{ .path = obj.path }, obj.must_link);
161 }
162 }158 }
163159
164 // This is a set of object files emitted by clang in a single `build-exe` invocation.160 // This is a set of object files emitted by clang in a single `build-exe` invocation.
165 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up161 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
166 // in this set.162 // in this set.
167 for (comp.c_object_table.keys()) |key| {163 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);
169 }165 }
170166
171 if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);167 if (module_obj_path) |path| elf_file.parseObjectReportingFailure(path);
172168
173 if (diags.hasErrors()) return error.FlushFailure;169 if (diags.hasErrors()) return error.FlushFailure;
174170
...@@ -219,19 +215,19 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l...@@ -219,19 +215,19 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
219 if (diags.hasErrors()) return error.FlushFailure;215 if (diags.hasErrors()) return error.FlushFailure;
220}216}
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;
223 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {220 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
224 error.LinkFailure => return,221 error.LinkFailure => return,
225 error.OutOfMemory => return error.OutOfMemory,222 else => |e| diags.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
226 else => |e| try elf_file.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
227 };223 };
228}224}
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;
231 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {228 parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
232 error.LinkFailure => return,229 error.LinkFailure => return,
233 error.OutOfMemory => return error.OutOfMemory,230 else => |e| diags.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
234 else => |e| try elf_file.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
235 };231 };
236}232}
237233
src/link/Elf/synthetic_sections.zig+20-18
...@@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct {...@@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct {
13451345
1346pub const VerneedSection = struct {1346pub const VerneedSection = struct {
1347 verneed: std.ArrayListUnmanaged(elf.Elf64_Verneed) = .empty,1347 verneed: std.ArrayListUnmanaged(elf.Elf64_Verneed) = .empty,
1348 vernaux: std.ArrayListUnmanaged(elf.Elf64_Vernaux) = .empty,1348 vernaux: std.ArrayListUnmanaged(elf.Vernaux) = .empty,
1349 index: elf.Elf64_Versym = elf.VER_NDX_GLOBAL + 1,1349 index: elf.Versym = .{ .VERSION = elf.Versym.GLOBAL.VERSION + 1, .HIDDEN = false },
13501350
1351 pub fn deinit(vern: *VerneedSection, allocator: Allocator) void {1351 pub fn deinit(vern: *VerneedSection, allocator: Allocator) void {
1352 vern.verneed.deinit(allocator);1352 vern.verneed.deinit(allocator);
...@@ -1363,7 +1363,7 @@ pub const VerneedSection = struct {...@@ -1363,7 +1363,7 @@ pub const VerneedSection = struct {
1363 /// Index of the defining this symbol version shared object file1363 /// Index of the defining this symbol version shared object file
1364 shared_object: File.Index,1364 shared_object: File.Index,
1365 /// Version index1365 /// Version index
1366 version_index: elf.Elf64_Versym,1366 version_index: elf.Versym,
13671367
1368 fn soname(this: @This(), ctx: *Elf) []const u8 {1368 fn soname(this: @This(), ctx: *Elf) []const u8 {
1369 const shared_object = ctx.file(this.shared_object).?.shared_object;1369 const shared_object = ctx.file(this.shared_object).?.shared_object;
...@@ -1376,7 +1376,8 @@ pub const VerneedSection = struct {...@@ -1376,7 +1376,8 @@ pub const VerneedSection = struct {
1376 }1376 }
13771377
1378 pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {1378 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));
1380 return mem.lessThan(u8, lhs.soname(ctx), rhs.soname(ctx));1381 return mem.lessThan(u8, lhs.soname(ctx), rhs.soname(ctx));
1381 }1382 }
1382 };1383 };
...@@ -1389,7 +1390,7 @@ pub const VerneedSection = struct {...@@ -1389,7 +1390,7 @@ pub const VerneedSection = struct {
13891390
1390 for (dynsyms, 1..) |entry, i| {1391 for (dynsyms, 1..) |entry, i| {
1391 const symbol = elf_file.symbol(entry.ref).?;1392 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) {
1393 const shared_object = symbol.file(elf_file).?.shared_object;1394 const shared_object = symbol.file(elf_file).?.shared_object;
1394 verneed.appendAssumeCapacity(.{1395 verneed.appendAssumeCapacity(.{
1395 .index = i,1396 .index = i,
...@@ -1404,11 +1405,12 @@ pub const VerneedSection = struct {...@@ -1404,11 +1405,12 @@ pub const VerneedSection = struct {
1404 var last = verneed.items[0];1405 var last = verneed.items[0];
1405 var last_verneed = try vern.addVerneed(last.soname(elf_file), elf_file);1406 var last_verneed = try vern.addVerneed(last.soname(elf_file), elf_file);
1406 var last_vernaux = try vern.addVernaux(last_verneed, last.versionString(elf_file), elf_file);1407 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
1409 for (verneed.items[1..]) |ver| {1410 for (verneed.items[1..]) |ver| {
1410 if (ver.shared_object == last.shared_object) {1411 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))) {
1412 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);1414 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
1413 }1415 }
1414 } else {1416 } else {
...@@ -1416,7 +1418,7 @@ pub const VerneedSection = struct {...@@ -1416,7 +1418,7 @@ pub const VerneedSection = struct {
1416 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);1418 last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
1417 }1419 }
1418 last = ver;1420 last = ver;
1419 versyms[ver.index] = last_vernaux.vna_other;1421 versyms[ver.index] = @bitCast(last_vernaux.other);
1420 }1422 }
14211423
1422 // Fixup offsets1424 // Fixup offsets
...@@ -1428,8 +1430,8 @@ pub const VerneedSection = struct {...@@ -1428,8 +1430,8 @@ pub const VerneedSection = struct {
1428 vsym.vn_aux = vernaux_off - verneed_off;1430 vsym.vn_aux = vernaux_off - verneed_off;
1429 var inner_off: u32 = 0;1431 var inner_off: u32 = 0;
1430 for (vern.vernaux.items[count..][0..vsym.vn_cnt], 0..) |*vaux, vaux_i| {1432 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);1433 if (vaux_i < vsym.vn_cnt - 1) vaux.next = @sizeOf(elf.Vernaux);
1432 inner_off += @sizeOf(elf.Elf64_Vernaux);1434 inner_off += @sizeOf(elf.Vernaux);
1433 }1435 }
1434 vernaux_off += inner_off;1436 vernaux_off += inner_off;
1435 verneed_off += @sizeOf(elf.Elf64_Verneed);1437 verneed_off += @sizeOf(elf.Elf64_Verneed);
...@@ -1456,24 +1458,24 @@ pub const VerneedSection = struct {...@@ -1456,24 +1458,24 @@ pub const VerneedSection = struct {
1456 verneed_sym: *elf.Elf64_Verneed,1458 verneed_sym: *elf.Elf64_Verneed,
1457 version: [:0]const u8,1459 version: [:0]const u8,
1458 elf_file: *Elf,1460 elf_file: *Elf,
1459 ) !elf.Elf64_Vernaux {1461 ) !elf.Vernaux {
1460 const comp = elf_file.base.comp;1462 const comp = elf_file.base.comp;
1461 const gpa = comp.gpa;1463 const gpa = comp.gpa;
1462 const sym = try vern.vernaux.addOne(gpa);1464 const sym = try vern.vernaux.addOne(gpa);
1463 sym.* = .{1465 sym.* = .{
1464 .vna_hash = HashSection.hasher(version),1466 .hash = HashSection.hasher(version),
1465 .vna_flags = 0,1467 .flags = 0,
1466 .vna_other = vern.index,1468 .other = @bitCast(vern.index),
1467 .vna_name = try elf_file.insertDynString(version),1469 .name = try elf_file.insertDynString(version),
1468 .vna_next = 0,1470 .next = 0,
1469 };1471 };
1470 verneed_sym.vn_cnt += 1;1472 verneed_sym.vn_cnt += 1;
1471 vern.index += 1;1473 vern.index.VERSION += 1;
1472 return sym.*;1474 return sym.*;
1473 }1475 }
14741476
1475 pub fn size(vern: VerneedSection) usize {1477 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);
1477 }1479 }
14781480
1479 pub fn write(vern: VerneedSection, writer: anytype) !void {1481 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...@@ -396,14 +396,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
396 }396 }
397397
398 for (positionals.items) |obj| {398 for (positionals.items) |obj| {
399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {399 self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
400 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),400 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
401 else => |e| try diags.reportParseError(
402 obj.path,
403 "unexpected error: reading input file failed with error {s}",
404 .{@errorName(e)},
405 ),
406 };
407 }401 }
408402
409 var system_libs = std.ArrayList(SystemLib).init(gpa);403 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...@@ -443,14 +437,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
443 };437 };
444438
445 for (system_libs.items) |lib| {439 for (system_libs.items) |lib| {
446 self.classifyInputFile(lib.path, lib, false) catch |err| switch (err) {440 self.classifyInputFile(lib.path, lib, false) catch |err|
447 error.UnknownFileType => try diags.reportParseError(lib.path, "unknown file type for an input file", .{}),441 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});
448 else => |e| try diags.reportParseError(
449 lib.path,
450 "unexpected error: parsing input file failed with error {s}",
451 .{@errorName(e)},
452 ),
453 };
454 }442 }
455443
456 // Finally, link against compiler_rt.444 // Finally, link against compiler_rt.
...@@ -460,14 +448,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -460,14 +448,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
460 break :blk null;448 break :blk null;
461 };449 };
462 if (compiler_rt_path) |path| {450 if (compiler_rt_path) |path| {
463 self.classifyInputFile(path, .{ .path = path }, false) catch |err| switch (err) {451 self.classifyInputFile(path, .{ .path = path }, false) catch |err|
464 error.UnknownFileType => try diags.reportParseError(path, "unknown file type for an input file", .{}),452 diags.addParseError(path, "failed to parse input file: {s}", .{@errorName(err)});
465 else => |e| try diags.reportParseError(
466 path,
467 "unexpected error: parsing input file failed with error {s}",
468 .{@errorName(e)},
469 ),
470 };
471 }453 }
472454
473 try self.parseInputFiles();455 try self.parseInputFiles();
...@@ -796,7 +778,7 @@ pub fn resolveLibSystem(...@@ -796,7 +778,7 @@ pub fn resolveLibSystem(
796 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;778 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
797 }779 }
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", .{});
800 return error.MissingLibSystem;782 return error.MissingLibSystem;
801 }783 }
802784
...@@ -847,10 +829,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {...@@ -847,10 +829,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
847 for (fat_archs) |arch| {829 for (fat_archs) |arch| {
848 if (arch.tag == cpu_arch) return arch;830 if (arch.tag == cpu_arch) return arch;
849 }831 }
850 try diags.reportParseError(path, "missing arch in universal file: expected {s}", .{832 return diags.failParse(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
851 @tagName(cpu_arch),
852 });
853 return error.MissingCpuArch;
854}833}
855834
856pub fn readMachHeader(file: std.fs.File, offset: usize) !macho.mach_header_64 {835pub 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...@@ -29,10 +29,9 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
29 pos += @sizeOf(ar_hdr);29 pos += @sizeOf(ar_hdr);
3030
31 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {31 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}'", .{
33 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),33 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
34 });34 });
35 return error.MalformedArchive;
36 }35 }
3736
38 var hdr_size = try hdr.size();37 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...@@ -29,14 +29,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
29 }29 }
3030
31 for (positionals.items) |obj| {31 for (positionals.items) |obj| {
32 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {32 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
33 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),33 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
34 else => |e| try diags.reportParseError(
35 obj.path,
36 "unexpected error: reading input file failed with error {s}",
37 .{@errorName(e)},
38 ),
39 };
40 }34 }
4135
42 if (diags.hasErrors()) return error.FlushFailure;36 if (diags.hasErrors()) return error.FlushFailure;
...@@ -95,14 +89,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -95,14 +89,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
95 }89 }
9690
97 for (positionals.items) |obj| {91 for (positionals.items) |obj| {
98 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {92 macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
99 error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),93 diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
100 else => |e| try diags.reportParseError(
101 obj.path,
102 "unexpected error: reading input file failed with error {s}",
103 .{@errorName(e)},
104 ),
105 };
106 }94 }
10795
108 if (diags.hasErrors()) return error.FlushFailure;96 if (diags.hasErrors()) return error.FlushFailure;