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