| author | |
| committer | |
| log | 1ba3fc90bef145310e09026e7e9e09623117a800 |
| tree | a7f86838e8fae04336e5254b10c373416548a7ad |
| parent | 7e530c13b3ef9b61417a610c00fc1d37c11ff7ed |
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 | }; |
| 154 | 162 | ||
| 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; |
| 258 | pub const DF_1_STUB = 0x04000000; | 258 | pub const DF_1_STUB = 0x04000000; |
| 259 | pub const DF_1_PIE = 0x08000000; | 259 | pub const DF_1_PIE = 0x08000000; |
| 260 | 260 | ||
| 261 | pub const VERSYM_HIDDEN = 0x8000; | 261 | pub const Versym = packed struct(u16) { |
| 262 | pub const VERSYM_VERSION = 0x7fff; | 262 | VERSION: u15, |
| 263 | 263 | HIDDEN: bool, | |
| 264 | /// Symbol is local | 264 | |
| 265 | pub const VER_NDX_LOCAL = 0; | 265 | pub const LOCAL: Versym = @bitCast(@intFromEnum(VER_NDX.LOCAL)); |
| 266 | /// Symbol is global | 266 | pub const GLOBAL: Versym = @bitCast(@intFromEnum(VER_NDX.GLOBAL)); |
| 267 | pub const VER_NDX_GLOBAL = 1; | 267 | }; |
| 268 | /// Beginning of reserved entries | 268 | |
| 269 | pub const VER_NDX_LORESERVE = 0xff00; | 269 | pub const VER_NDX = enum(u16) { |
| 270 | /// Symbol is to be eliminated | 270 | /// Symbol is local |
| 271 | pub 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 | }; | ||
| 272 | 281 | ||
| 273 | /// Version definition of the file itself | 282 | /// Version definition of the file itself |
| 274 | pub const VER_FLG_BASE = 1; | 283 | pub const VER_FLG_BASE = 1; |
| ... | @@ -698,12 +707,9 @@ pub const EI_PAD = 9; | ... | @@ -698,12 +707,9 @@ pub const EI_PAD = 9; |
| 698 | 707 | ||
| 699 | pub const EI_NIDENT = 16; | 708 | pub const EI_NIDENT = 16; |
| 700 | 709 | ||
| 701 | pub const Elf32_Half = u16; | 710 | pub const Half = u16; |
| 702 | pub const Elf64_Half = u16; | 711 | pub const Word = u32; |
| 703 | pub const Elf32_Word = u32; | 712 | pub const Sword = i32; |
| 704 | pub const Elf32_Sword = i32; | ||
| 705 | pub const Elf64_Word = u32; | ||
| 706 | pub const Elf64_Sword = i32; | ||
| 707 | pub const Elf32_Xword = u64; | 713 | pub const Elf32_Xword = u64; |
| 708 | pub const Elf32_Sxword = i64; | 714 | pub const Elf32_Sxword = i64; |
| 709 | pub const Elf64_Xword = u64; | 715 | pub const Elf64_Xword = u64; |
| ... | @@ -714,53 +720,51 @@ pub const Elf32_Off = u32; | ... | @@ -714,53 +720,51 @@ pub const Elf32_Off = u32; |
| 714 | pub const Elf64_Off = u64; | 720 | pub const Elf64_Off = u64; |
| 715 | pub const Elf32_Section = u16; | 721 | pub const Elf32_Section = u16; |
| 716 | pub const Elf64_Section = u16; | 722 | pub const Elf64_Section = u16; |
| 717 | pub const Elf32_Versym = Elf32_Half; | ||
| 718 | pub const Elf64_Versym = Elf64_Half; | ||
| 719 | pub const Elf32_Ehdr = extern struct { | 723 | pub 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 | }; |
| 735 | pub const Elf64_Ehdr = extern struct { | 739 | pub 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 | }; |
| 751 | pub const Elf32_Phdr = extern struct { | 755 | pub 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 | }; |
| 761 | pub const Elf64_Phdr = extern struct { | 765 | pub 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 | }; |
| 771 | pub const Elf32_Shdr = extern struct { | 775 | pub 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 | }; |
| 783 | pub const Elf64_Shdr = extern struct { | 787 | pub 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 | }; |
| 795 | pub const Elf32_Chdr = extern struct { | 799 | pub 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 | }; |
| 800 | pub const Elf64_Chdr = extern struct { | 804 | pub 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 | }; |
| 806 | pub const Elf32_Sym = extern struct { | 810 | pub 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 | }; |
| 821 | pub const Elf64_Sym = extern struct { | 825 | pub 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 | }; |
| 836 | pub const Elf32_Syminfo = extern struct { | 840 | pub 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 | }; |
| 840 | pub const Elf64_Syminfo = extern struct { | 844 | pub 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 | }; |
| 844 | pub const Elf32_Rel = extern struct { | 848 | pub const Elf32_Rel = extern struct { |
| 845 | r_offset: Elf32_Addr, | 849 | r_offset: Elf32_Addr, |
| 846 | r_info: Elf32_Word, | 850 | r_info: Word, |
| 847 | 851 | ||
| 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 | }; |
| 866 | pub const Elf32_Rela = extern struct { | 870 | pub 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, |
| 870 | 874 | ||
| 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 | }; |
| 890 | pub const Elf32_Relr = Elf32_Word; | 894 | pub const Elf32_Relr = Word; |
| 891 | pub const Elf64_Relr = Elf64_Xword; | 895 | pub const Elf64_Relr = Elf64_Xword; |
| 892 | pub const Elf32_Dyn = extern struct { | 896 | pub 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 | }; |
| 896 | pub const Elf64_Dyn = extern struct { | 900 | pub 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 | }; |
| 900 | pub const Elf32_Verdef = extern struct { | 904 | pub 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 | }; | ||
| 909 | pub 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 | }; |
| 918 | pub const Elf32_Verdaux = extern struct { | 913 | pub const Verdaux = extern struct { |
| 919 | vda_name: Elf32_Word, | 914 | name: Word, |
| 920 | vda_next: Elf32_Word, | 915 | next: Word, |
| 921 | }; | ||
| 922 | pub const Elf64_Verdaux = extern struct { | ||
| 923 | vda_name: Elf64_Word, | ||
| 924 | vda_next: Elf64_Word, | ||
| 925 | }; | 916 | }; |
| 926 | pub const Elf32_Verneed = extern struct { | 917 | pub 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 | }; |
| 933 | pub const Elf64_Verneed = extern struct { | 924 | pub 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 | }; | ||
| 940 | pub 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 | }; |
| 947 | pub const Elf64_Vernaux = extern struct { | 931 | pub 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 | }; |
| 954 | pub const Elf32_auxv_t = extern struct { | 938 | pub 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 | }; |
| 966 | pub const Elf32_Nhdr = extern struct { | 950 | pub 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 | }; |
| 971 | pub const Elf64_Nhdr = extern struct { | 955 | pub 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 | }; |
| 976 | pub const Elf32_Move = extern struct { | 960 | pub 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 | }; |
| 983 | pub const Elf64_Move = extern struct { | 967 | pub 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 | }; |
| 990 | pub const Elf32_gptab = extern union { | 974 | pub 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 | }; |
| 1000 | pub const Elf32_RegInfo = extern struct { | 984 | pub 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 | }; |
| 1005 | pub const Elf_Options = extern struct { | 989 | pub 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 | }; |
| 1011 | pub const Elf_Options_Hw = extern struct { | 995 | pub 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 | }; |
| 1015 | pub const Elf32_Lib = extern struct { | 999 | pub 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 | }; |
| 1022 | pub const Elf64_Lib = extern struct { | 1006 | pub 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 | }; |
| 1029 | pub const Elf32_Conflict = Elf32_Addr; | 1013 | pub const Elf32_Conflict = Elf32_Addr; |
| 1030 | pub const Elf_MIPS_ABIFlags_v0 = extern struct { | 1014 | pub 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 | }; |
| 1043 | 1027 | ||
| 1044 | comptime { | 1028 | comptime { |
| ... | @@ -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 | }; |
| 1105 | pub const Verdef = switch (@sizeOf(usize)) { | ||
| 1106 | 4 => Elf32_Verdef, | ||
| 1107 | 8 => Elf64_Verdef, | ||
| 1108 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 1109 | }; | ||
| 1110 | pub const Verdaux = switch (@sizeOf(usize)) { | ||
| 1111 | 4 => Elf32_Verdaux, | ||
| 1112 | 8 => Elf64_Verdaux, | ||
| 1113 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 1114 | }; | ||
| 1115 | pub const Addr = switch (@sizeOf(usize)) { | 1089 | pub 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 | }; |
| 1120 | pub const Half = u16; | ||
| 1121 | 1094 | ||
| 1122 | pub const OSABI = enum(u8) { | 1095 | pub const OSABI = enum(u8) { |
| 1123 | /// UNIX System V ABI | 1096 | /// 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; |
| 42 | 42 | ||
| 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 | } |
| 82 | 82 | ||
| 83 | fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool { | 83 | fn 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) { |
| 1002 | pub const LinkObject = struct { | 1002 | pub 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 be | 1006 | // 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 | } |
| 2566 | 2568 |
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 | } |
| 228 | 224 | ||
| 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 | } |
| 252 | 248 | ||
| 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 | } |
| 266 | 300 | ||
| 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 | } |
| 278 | 327 | ||
| 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, |
| 46 | zig_object_index: ?File.Index = null, | 46 | zig_object_index: ?File.Index = null, |
| 47 | linker_defined_index: ?File.Index = null, | 47 | linker_defined_index: ?File.Index = null, |
| 48 | objects: std.ArrayListUnmanaged(File.Index) = .empty, | 48 | objects: std.ArrayListUnmanaged(File.Index) = .empty, |
| 49 | shared_objects: std.ArrayListUnmanaged(File.Index) = .empty, | 49 | shared_objects: std.StringArrayHashMapUnmanaged(File.Index) = .empty, |
| 50 | 50 | ||
| 51 | /// List of all output sections and their associated metadata. | 51 | /// List of all output sections and their associated metadata. |
| 52 | sections: std.MultiArrayList(Section) = .{}, | 52 | sections: std.MultiArrayList(Section) = .{}, |
| ... | @@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{}, | ... | @@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{}, |
| 62 | section_indexes: SectionIndexes = .{}, | 62 | section_indexes: SectionIndexes = .{}, |
| 63 | 63 | ||
| 64 | page_size: u32, | 64 | page_size: u32, |
| 65 | default_sym_version: elf.Elf64_Versym, | 65 | default_sym_version: elf.Versym, |
| 66 | 66 | ||
| 67 | /// .shstrtab buffer | 67 | /// .shstrtab buffer |
| 68 | shstrtab: std.ArrayListUnmanaged(u8) = .empty, | 68 | shstrtab: std.ArrayListUnmanaged(u8) = .empty, |
| ... | @@ -75,7 +75,7 @@ dynsym: DynsymSection = .{}, | ... | @@ -75,7 +75,7 @@ dynsym: DynsymSection = .{}, |
| 75 | /// .dynstrtab buffer | 75 | /// .dynstrtab buffer |
| 76 | dynstrtab: std.ArrayListUnmanaged(u8) = .empty, | 76 | dynstrtab: 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. |
| 78 | versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty, | 78 | versym: std.ArrayListUnmanaged(elf.Versym) = .empty, |
| 79 | /// .verneed section | 79 | /// .verneed section |
| 80 | verneed: VerneedSection = .{}, | 80 | verneed: VerneedSection = .{}, |
| 81 | /// .got section | 81 | /// .got section |
| ... | @@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty, | ... | @@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty, |
| 114 | merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, | 114 | merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, |
| 115 | comment_merge_section_index: ?Merge.Section.Index = null, | 115 | comment_merge_section_index: ?Merge.Section.Index = null, |
| 116 | 116 | ||
| 117 | first_eflags: ?elf.Elf64_Word = null, | 117 | first_eflags: ?elf.Word = null, |
| 118 | 118 | ||
| 119 | const SectionIndexes = struct { | 119 | const 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 | }; |
| 266 | 266 | ||
| 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; | ||
| 272 | 269 | ||
| 273 | // If using LLD to link, this code should produce an object file so that it | 270 | // 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-link | 791 | // --verbose-link |
| 795 | if (comp.verbose_link) try self.dumpArgv(comp); | 792 | if (comp.verbose_link) try self.dumpArgv(comp); |
| 796 | 793 | ||
| 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); |
| 800 | 797 | ||
| 801 | const csu = try comp.getCrtPaths(arena); | 798 | const csu = try comp.getCrtPaths(arena); |
| 802 | 799 | ||
| 803 | // csu prelude | 800 | // 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); |
| 807 | 804 | ||
| 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 | } |
| 815 | 808 | ||
| 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 up | 810 | // 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 | } |
| 822 | 815 | ||
| 823 | if (module_obj_path) |path| try parseObjectReportingFailure(self, path); | 816 | if (module_obj_path) |path| parseObjectReportingFailure(self, path); |
| 824 | 817 | ||
| 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.?); |
| 827 | 820 | ||
| 828 | // libc | 821 | // 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 | } |
| 832 | 825 | ||
| 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 | } |
| 839 | 829 | ||
| 840 | // libc++ dep | 830 | // 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 | } |
| 845 | 835 | ||
| 846 | // libunwind dep | 836 | // 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 | } |
| 850 | 840 | ||
| 851 | // libc dep | 841 | // 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; |
| 871 | 861 | ||
| 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 | } |
| 880 | 869 | ||
| 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 shared | 899 | // 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 | } |
| 919 | 906 | ||
| 920 | // csu postlude | 907 | // 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); |
| 923 | 910 | ||
| 924 | if (diags.hasErrors()) return error.FlushFailure; | 911 | if (diags.hasErrors()) return error.FlushFailure; |
| 925 | 912 | ||
| 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 of | 913 | // 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; |
| 1374 | 1343 | ||
| 1375 | fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) error{OutOfMemory}!void { | 1344 | fn 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 | } |
| 1382 | 1347 | ||
| 1383 | pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void { | 1348 | pub 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 reported | 1350 | 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 | } |
| 1390 | 1380 | ||
| 1391 | pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool) error{OutOfMemory}!void { | 1381 | pub 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 reported | 1384 | 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 | } |
| 1398 | 1388 | ||
| 1399 | fn 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 | |||
| 1411 | fn parseObject(self: *Elf, path: Path) ParseError!void { | 1389 | fn 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 | } |
| 1459 | 1437 | ||
| 1460 | fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void { | 1438 | fn 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(); |
| 1463 | 1448 | ||
| 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(); |
| 1467 | 1451 | ||
| 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); | ||
| 1479 | 1494 | ||
| 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 | } |
| 1483 | 1513 | ||
| 1484 | fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { | 1514 | fn 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 | } |
| 1539 | 1569 | ||
| 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 | } |
| 1547 | 1577 | ||
| 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 | } |
| 1562 | 1582 | ||
| 1563 | pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void { | 1583 | pub 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 yet | 1586 | 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.?; |
| 1569 | 1589 | ||
| 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 objects | 1661 | /// 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. |
| 1643 | pub fn resolveSymbols(self: *Elf) !void { | 1663 | pub 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); |
| 1650 | 1673 | ||
| 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 | } |
| 1672 | 1698 | ||
| ... | @@ -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 | } |
| 1693 | 1719 | ||
| ... | @@ -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 and | 1722 | /// This routine will prune unneeded objects extracted from archives and |
| 1697 | /// unneeded shared objects. | 1723 | /// unneeded shared objects. |
| 1698 | fn markLive(self: *Elf) void { | 1724 | fn 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 | } |
| 1717 | 1744 | ||
| 1718 | fn markImportsExports(self: *Elf) void { | 1745 | fn 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. |
| 1745 | fn scanRelocs(self: *Elf) !void { | 1773 | fn 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(); | ||
| 1747 | 1776 | ||
| 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"; |
| 1907 | 1936 | ||
| 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(); |
| 1910 | 1939 | ||
| 1911 | var digest: [Cache.hex_digest_len]u8 = undefined; | 1940 | var digest: [std.Build.Cache.hex_digest_len]u8 = undefined; |
| 1912 | 1941 | ||
| 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(); |
| 1989 | 2018 | ||
| 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 only | 2472 | // 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(); | ||
| 2902 | 2932 | ||
| 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 | } |
| 3025 | 3055 | ||
| 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 { |
| 3072 | 3102 | ||
| 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 { |
| 3259 | fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { | 3289 | fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { |
| 3260 | if (self.section_indexes.dynamic == null) return; | 3290 | if (self.section_indexes.dynamic == null) return; |
| 3261 | 3291 | ||
| 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 | } |
| 3654 | 3686 | ||
| 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 | } |
| 3658 | 3690 | ||
| 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; |
| 4056 | 4088 | ||
| 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); |
| 4061 | 4095 | ||
| 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); |
| 4066 | 4100 | ||
| 4067 | // Section symbols | 4101 | // Section symbols |
| ... | @@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void { | ... | @@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void { |
| 4284 | 4318 | ||
| 4285 | pub fn writeSymtab(self: *Elf) !void { | 4319 | pub 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 | } |
| 4337 | 4373 | ||
| 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 | } |
| 4927 | 4963 | ||
| 4928 | pub 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 | |||
| 4940 | pub fn addFileError( | 4964 | pub 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 | } |
| 4961 | 4985 | ||
| 4962 | pub 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 | |||
| 4972 | const FormatShdrCtx = struct { | 4986 | const 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; |
| 5115 | 5129 | ||
| 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 | } |
| 5138 | 5154 | ||
| 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 | } |
| 5205 | 5221 | ||
| 5206 | /// Binary search | 5222 | /// Binary search |
| 5207 | pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { | 5223 | pub 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 | } |
| 5224 | 5237 | ||
| 5225 | /// Linear search | 5238 | /// Linear search |
| 5226 | pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize { | 5239 | pub 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 | } |
| 5571 | 5581 | ||
| 5582 | pub 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 | |||
| 5572 | const std = @import("std"); | 5587 | const std = @import("std"); |
| 5573 | const build_options = @import("build_options"); | 5588 | const build_options = @import("build_options"); |
| 5574 | const builtin = @import("builtin"); | 5589 | const 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); |
| 5581 | const math = std.math; | 5596 | const math = std.math; |
| 5582 | const mem = std.mem; | 5597 | const mem = std.mem; |
| 5583 | const Allocator = std.mem.Allocator; | 5598 | const Allocator = std.mem.Allocator; |
| 5584 | const Cache = std.Build.Cache; | ||
| 5585 | const Hash = std.hash.Wyhash; | 5599 | const Hash = std.hash.Wyhash; |
| 5600 | const Path = std.Build.Cache.Path; | ||
| 5601 | const Stat = std.Build.Cache.File.Stat; | ||
| 5586 | 5602 | ||
| 5587 | const codegen = @import("../codegen.zig"); | 5603 | const codegen = @import("../codegen.zig"); |
| 5588 | const dev = @import("../dev.zig"); | 5604 | const dev = @import("../dev.zig"); |
| ... | @@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig"); | ... | @@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig"); |
| 5601 | const Air = @import("../Air.zig"); | 5617 | const Air = @import("../Air.zig"); |
| 5602 | const Archive = @import("Elf/Archive.zig"); | 5618 | const Archive = @import("Elf/Archive.zig"); |
| 5603 | const AtomList = @import("Elf/AtomList.zig"); | 5619 | const AtomList = @import("Elf/AtomList.zig"); |
| 5604 | const Path = Cache.Path; | ||
| 5605 | const Compilation = @import("../Compilation.zig"); | 5620 | const Compilation = @import("../Compilation.zig"); |
| 5606 | const ComdatGroupSection = synthetic_sections.ComdatGroupSection; | 5621 | const ComdatGroupSection = synthetic_sections.ComdatGroupSection; |
| 5607 | const CopyRelSection = synthetic_sections.CopyRelSection; | 5622 | const CopyRelSection = synthetic_sections.CopyRelSection; |
| 5623 | const Diags = @import("../link.zig").Diags; | ||
| 5608 | const DynamicSection = synthetic_sections.DynamicSection; | 5624 | const DynamicSection = synthetic_sections.DynamicSection; |
| 5609 | const DynsymSection = synthetic_sections.DynsymSection; | 5625 | const DynsymSection = synthetic_sections.DynsymSection; |
| 5610 | const Dwarf = @import("Dwarf.zig"); | 5626 | const Dwarf = @import("Dwarf.zig"); |
src/link/Elf/Archive.zig+2-10| ... | @@ -1,15 +1,6 @@ | ... | @@ -1,15 +1,6 @@ |
| 1 | objects: std.ArrayListUnmanaged(Object) = .empty, | 1 | objects: std.ArrayListUnmanaged(Object) = .empty, |
| 2 | strtab: std.ArrayListUnmanaged(u8) = .empty, | 2 | strtab: std.ArrayListUnmanaged(u8) = .empty, |
| 3 | 3 | ||
| 4 | pub 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 | |||
| 13 | pub fn deinit(self: *Archive, allocator: Allocator) void { | 4 | pub 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 { |
| 18 | pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void { | 9 | pub 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; |
| 23 | 15 | ||
| ... | @@ -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); |
| 36 | 28 | ||
| 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{ |
| 21 | pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void { | 21 | pub 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; |
| 541 | 541 | ||
| 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 @@ |
| 1 | path: Path, | 1 | path: Path, |
| 2 | index: File.Index, | 2 | index: File.Index, |
| 3 | 3 | ||
| 4 | header: ?elf.Elf64_Ehdr = null, | 4 | parsed: Parsed, |
| 5 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .empty, | ||
| 6 | 5 | ||
| 7 | symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty, | 6 | symbols: std.ArrayListUnmanaged(Symbol), |
| 8 | strtab: std.ArrayListUnmanaged(u8) = .empty, | 7 | symbols_extra: std.ArrayListUnmanaged(u32), |
| 9 | /// Version symtab contains version strings of the symbols if present. | 8 | symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index), |
| 10 | versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty, | ||
| 11 | verstrings: std.ArrayListUnmanaged(u32) = .empty, | ||
| 12 | 9 | ||
| 13 | symbols: std.ArrayListUnmanaged(Symbol) = .empty, | 10 | aliases: ?std.ArrayListUnmanaged(u32), |
| 14 | symbols_extra: std.ArrayListUnmanaged(u32) = .empty, | ||
| 15 | symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .empty, | ||
| 16 | |||
| 17 | aliases: ?std.ArrayListUnmanaged(u32) = null, | ||
| 18 | dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .empty, | ||
| 19 | 11 | ||
| 20 | needed: bool, | 12 | needed: bool, |
| 21 | alive: bool, | 13 | alive: bool, |
| 22 | 14 | ||
| 23 | output_symtab_ctx: Elf.SymtabCtx = .{}, | 15 | output_symtab_ctx: Elf.SymtabCtx, |
| 24 | |||
| 25 | pub 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 | } | ||
| 35 | 16 | ||
| 36 | pub fn deinit(self: *SharedObject, allocator: Allocator) void { | 17 | pub 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 | } |
| 49 | 26 | ||
| 50 | pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { | 27 | pub 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, |
| 54 | 31 | ||
| 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, | ||
| 58 | 36 | ||
| 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 | |||
| 53 | pub 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 | } |
| 65 | 85 | ||
| 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 | }; | ||
| 72 | 91 | ||
| 73 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize); | 92 | pub 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 | } | ||
| 77 | 123 | ||
| 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 | } |
| 96 | 138 | ||
| 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 | } |
| 105 | 162 | ||
| 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 | }, |
| 113 | 170 | 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); | ||
| 121 | 175 | ||
| 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 | } |
| 133 | 188 | ||
| 134 | fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts: struct { | 189 | pub 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); | ||
| 141 | 206 | ||
| 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; | ||
| 145 | 209 | ||
| 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); | ||
| 152 | 214 | ||
| 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 entry | 219 | |
| 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_name | 221 | 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 | } | ||
| 166 | 222 | ||
| 167 | try self.versyms.ensureTotalCapacityPrecise(gpa, opts.symtab.len); | 223 | const aux = mem.bytesAsValue(elf.Verdaux, verdefs[offset + verdef.aux ..][0..@sizeOf(elf.Verdaux)]); |
| 168 | 224 | 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 | } | ||
| 186 | 230 | ||
| 187 | fn 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); |
| 193 | 237 | 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; |
| 201 | 245 | 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 symbol | 249 | |
| 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 | } |
| 229 | 309 | ||
| 230 | pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void { | 310 | pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void { |
| 231 | const gpa = elf_file.base.comp.gpa; | 311 | const gpa = elf_file.base.comp.gpa; |
| 232 | 312 | ||
| 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 | } |
| 254 | 334 | ||
| 255 | pub fn markLive(self: *SharedObject, elf_file: *Elf) void { | 335 | pub 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; |
| 258 | 338 | ||
| 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 | } |
| 310 | 390 | ||
| 311 | pub fn versionString(self: SharedObject, index: elf.Elf64_Versym) [:0]const u8 { | 391 | pub 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 | } |
| 315 | 394 | ||
| 316 | pub fn asFile(self: *SharedObject) File { | 395 | fn 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 | } |
| 319 | 399 | ||
| 320 | fn verdefNum(self: *SharedObject) u32 { | 400 | pub 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 | } |
| 327 | 403 | ||
| 328 | pub fn soname(self: *SharedObject) []const u8 { | 404 | pub 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 | } |
| 335 | 407 | ||
| 336 | pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void { | 408 | pub 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 | } |
| 362 | 434 | ||
| 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); |
| 364 | 436 | ||
| 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 | } |
| 386 | 458 | ||
| 387 | fn 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 | |||
| 395 | pub fn getString(self: SharedObject, off: u32) [:0]const u8 { | 459 | pub 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 | } |
| 399 | 462 | ||
| 400 | pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref { | 463 | pub 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 | } |
| 404 | 467 | ||
| 405 | fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index { | 468 | pub fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index { |
| 406 | try self.symbols.ensureUnusedCapacity(allocator, 1); | ||
| 407 | return self.addSymbolAssumeCapacity(); | ||
| 408 | } | ||
| 409 | |||
| 410 | fn 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 | } |
| 415 | 473 | ||
| 416 | pub 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 | |||
| 422 | pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 { | 474 | pub 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 | } |
| 470 | 522 | ||
| 471 | pub fn fmtSymtab(self: SharedObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) { | 523 | pub 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; |
| 509 | const log = std.log.scoped(.elf); | 561 | const log = std.log.scoped(.elf); |
| 510 | const mem = std.mem; | 562 | const mem = std.mem; |
| 511 | const Path = std.Build.Cache.Path; | 563 | const Path = std.Build.Cache.Path; |
| 512 | 564 | const Stat = std.Build.Cache.File.Stat; | |
| 513 | const Allocator = mem.Allocator; | 565 | const Allocator = mem.Allocator; |
| 566 | |||
| 514 | const Elf = @import("../Elf.zig"); | 567 | const Elf = @import("../Elf.zig"); |
| 515 | const File = @import("file.zig").File; | 568 | const File = @import("file.zig").File; |
| 516 | const Symbol = @import("Symbol.zig"); | 569 | const Symbol = @import("Symbol.zig"); |
| 570 | const 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, |
| 22 | 22 | ||
| 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. |
| 25 | version_index: elf.Elf64_Versym = elf.VER_NDX_LOCAL, | 25 | version_index: elf.Versym = .LOCAL, |
| 26 | 26 | ||
| 27 | /// Misc flags for the symbol packaged as packed struct for compression. | 27 | /// Misc flags for the symbol packaged as packed struct for compression. |
| 28 | flags: Flags = .{}, | 28 | flags: 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 { |
| 87 | pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { | 87 | pub 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 | alignment | 242 | 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 | } |
| 266 | 266 | ||
| 267 | pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { | 267 | pub 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; |
| 628 | 628 | ||
| 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 |
| 4 | 4 | ||
| 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 | } |
| 12 | 12 | ||
| 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 | } |
| 16 | 16 | ||
| 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 | } |
| 20 | 20 | ||
| 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 | } |
| 24 | 24 | ||
| 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; |
| 155 | 155 | ||
| 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 | } |
| 163 | 159 | ||
| 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 up | 161 | // 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 | } |
| 170 | 166 | ||
| 171 | if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path); | 167 | if (module_obj_path) |path| elf_file.parseObjectReportingFailure(path); |
| 172 | 168 | ||
| 173 | if (diags.hasErrors()) return error.FlushFailure; | 169 | if (diags.hasErrors()) return error.FlushFailure; |
| 174 | 170 | ||
| ... | @@ -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 | } |
| 221 | 217 | ||
| 222 | fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void { | 218 | fn 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 | } |
| 229 | 225 | ||
| 230 | fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void { | 226 | fn 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 | } |
| 237 | 233 |
src/link/Elf/synthetic_sections.zig+20-18| ... | @@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct { | ... | @@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct { |
| 1345 | 1345 | ||
| 1346 | pub const VerneedSection = struct { | 1346 | pub 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 }, |
| 1350 | 1350 | ||
| 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 file | 1363 | /// Index of the defining this symbol version shared object file |
| 1364 | shared_object: File.Index, | 1364 | shared_object: File.Index, |
| 1365 | /// Version index | 1365 | /// Version index |
| 1366 | version_index: elf.Elf64_Versym, | 1366 | version_index: elf.Versym, |
| 1367 | 1367 | ||
| 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 | } |
| 1377 | 1377 | ||
| 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 { |
| 1389 | 1390 | ||
| 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); |
| 1408 | 1409 | ||
| 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 | } |
| 1421 | 1423 | ||
| 1422 | // Fixup offsets | 1424 | // 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 | } |
| 1474 | 1476 | ||
| 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 | } |
| 1478 | 1480 | ||
| 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 | } |
| 397 | 397 | ||
| 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 | } |
| 408 | 402 | ||
| 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 | }; |
| 444 | 438 | ||
| 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 | } |
| 455 | 443 | ||
| 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 | } |
| 472 | 454 | ||
| 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 | } |
| 798 | 780 | ||
| 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 | } |
| 802 | 784 | ||
| ... | @@ -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 | } |
| 855 | 834 | ||
| 856 | pub fn readMachHeader(file: std.fs.File, offset: usize) !macho.mach_header_64 { | 835 | pub 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); |
| 30 | 30 | ||
| 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 | } |
| 37 | 36 | ||
| 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 | } |
| 30 | 30 | ||
| 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 | } |
| 41 | 35 | ||
| 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 | } |
| 96 | 90 | ||
| 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 | } |
| 107 | 95 | ||
| 108 | if (diags.hasErrors()) return error.FlushFailure; | 96 | if (diags.hasErrors()) return error.FlushFailure; |