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

Merge pull request #21681 from ziglang/reduce-flush

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

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

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