Commit 1ba3fc90be
Changed files (18)
lib/std/Build/Cache.zig
@@ -150,6 +150,14 @@ pub const File = struct {
inode: fs.File.INode,
size: u64,
mtime: i128,
+
+ pub fn fromFs(fs_stat: fs.File.Stat) Stat {
+ return .{
+ .inode = fs_stat.inode,
+ .size = fs_stat.size,
+ .mtime = fs_stat.mtime,
+ };
+ }
};
pub fn deinit(self: *File, gpa: Allocator) void {
lib/std/os/linux/vdso.zig
@@ -37,7 +37,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
var maybe_strings: ?[*]u8 = null;
var maybe_syms: ?[*]elf.Sym = null;
var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
- var maybe_versym: ?[*]u16 = null;
+ var maybe_versym: ?[*]elf.Versym = null;
var maybe_verdef: ?*elf.Verdef = null;
{
@@ -48,7 +48,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
elf.DT_STRTAB => maybe_strings = @as([*]u8, @ptrFromInt(p)),
elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
elf.DT_HASH => maybe_hashtab = @as([*]linux.Elf_Symndx, @ptrFromInt(p)),
- elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
+ elf.DT_VERSYM => maybe_versym = @as([*]elf.Versym, @ptrFromInt(p)),
elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
else => {},
}
@@ -80,17 +80,15 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
return 0;
}
-fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool {
+fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, strings: [*]u8) bool {
var def = def_arg;
- const vsym = @as(u32, @bitCast(vsym_arg)) & 0x7fff;
+ const vsym_index = vsym_arg.VERSION;
while (true) {
- if (0 == (def.vd_flags & elf.VER_FLG_BASE) and (def.vd_ndx & 0x7fff) == vsym)
- break;
- if (def.vd_next == 0)
- return false;
- def = @as(*elf.Verdef, @ptrFromInt(@intFromPtr(def) + def.vd_next));
+ if (0 == (def.flags & elf.VER_FLG_BASE) and @intFromEnum(def.ndx) == vsym_index) break;
+ if (def.next == 0) return false;
+ def = @ptrFromInt(@intFromPtr(def) + def.next);
}
- const aux = @as(*elf.Verdaux, @ptrFromInt(@intFromPtr(def) + def.vd_aux));
- const vda_name = @as([*:0]u8, @ptrCast(strings + aux.vda_name));
+ const aux: *elf.Verdaux = @ptrFromInt(@intFromPtr(def) + def.aux);
+ const vda_name: [*:0]u8 = @ptrCast(strings + aux.name);
return mem.eql(u8, vername, mem.sliceTo(vda_name, 0));
}
lib/std/elf.zig
@@ -258,17 +258,26 @@ pub const DF_1_SINGLETON = 0x02000000;
pub const DF_1_STUB = 0x04000000;
pub const DF_1_PIE = 0x08000000;
-pub const VERSYM_HIDDEN = 0x8000;
-pub const VERSYM_VERSION = 0x7fff;
-
-/// Symbol is local
-pub const VER_NDX_LOCAL = 0;
-/// Symbol is global
-pub const VER_NDX_GLOBAL = 1;
-/// Beginning of reserved entries
-pub const VER_NDX_LORESERVE = 0xff00;
-/// Symbol is to be eliminated
-pub const VER_NDX_ELIMINATE = 0xff01;
+pub const Versym = packed struct(u16) {
+ VERSION: u15,
+ HIDDEN: bool,
+
+ pub const LOCAL: Versym = @bitCast(@intFromEnum(VER_NDX.LOCAL));
+ pub const GLOBAL: Versym = @bitCast(@intFromEnum(VER_NDX.GLOBAL));
+};
+
+pub const VER_NDX = enum(u16) {
+ /// Symbol is local
+ LOCAL = 0,
+ /// Symbol is global
+ GLOBAL = 1,
+ /// Beginning of reserved entries
+ LORESERVE = 0xff00,
+ /// Symbol is to be eliminated
+ ELIMINATE = 0xff01,
+ UNSPECIFIED = 0xffff,
+ _,
+};
/// Version definition of the file itself
pub const VER_FLG_BASE = 1;
@@ -698,12 +707,9 @@ pub const EI_PAD = 9;
pub const EI_NIDENT = 16;
-pub const Elf32_Half = u16;
-pub const Elf64_Half = u16;
-pub const Elf32_Word = u32;
-pub const Elf32_Sword = i32;
-pub const Elf64_Word = u32;
-pub const Elf64_Sword = i32;
+pub const Half = u16;
+pub const Word = u32;
+pub const Sword = i32;
pub const Elf32_Xword = u64;
pub const Elf32_Sxword = i64;
pub const Elf64_Xword = u64;
@@ -714,53 +720,51 @@ pub const Elf32_Off = u32;
pub const Elf64_Off = u64;
pub const Elf32_Section = u16;
pub const Elf64_Section = u16;
-pub const Elf32_Versym = Elf32_Half;
-pub const Elf64_Versym = Elf64_Half;
pub const Elf32_Ehdr = extern struct {
e_ident: [EI_NIDENT]u8,
e_type: ET,
e_machine: EM,
- e_version: Elf32_Word,
+ e_version: Word,
e_entry: Elf32_Addr,
e_phoff: Elf32_Off,
e_shoff: Elf32_Off,
- e_flags: Elf32_Word,
- e_ehsize: Elf32_Half,
- e_phentsize: Elf32_Half,
- e_phnum: Elf32_Half,
- e_shentsize: Elf32_Half,
- e_shnum: Elf32_Half,
- e_shstrndx: Elf32_Half,
+ e_flags: Word,
+ e_ehsize: Half,
+ e_phentsize: Half,
+ e_phnum: Half,
+ e_shentsize: Half,
+ e_shnum: Half,
+ e_shstrndx: Half,
};
pub const Elf64_Ehdr = extern struct {
e_ident: [EI_NIDENT]u8,
e_type: ET,
e_machine: EM,
- e_version: Elf64_Word,
+ e_version: Word,
e_entry: Elf64_Addr,
e_phoff: Elf64_Off,
e_shoff: Elf64_Off,
- e_flags: Elf64_Word,
- e_ehsize: Elf64_Half,
- e_phentsize: Elf64_Half,
- e_phnum: Elf64_Half,
- e_shentsize: Elf64_Half,
- e_shnum: Elf64_Half,
- e_shstrndx: Elf64_Half,
+ e_flags: Word,
+ e_ehsize: Half,
+ e_phentsize: Half,
+ e_phnum: Half,
+ e_shentsize: Half,
+ e_shnum: Half,
+ e_shstrndx: Half,
};
pub const Elf32_Phdr = extern struct {
- p_type: Elf32_Word,
+ p_type: Word,
p_offset: Elf32_Off,
p_vaddr: Elf32_Addr,
p_paddr: Elf32_Addr,
- p_filesz: Elf32_Word,
- p_memsz: Elf32_Word,
- p_flags: Elf32_Word,
- p_align: Elf32_Word,
+ p_filesz: Word,
+ p_memsz: Word,
+ p_flags: Word,
+ p_align: Word,
};
pub const Elf64_Phdr = extern struct {
- p_type: Elf64_Word,
- p_flags: Elf64_Word,
+ p_type: Word,
+ p_flags: Word,
p_offset: Elf64_Off,
p_vaddr: Elf64_Addr,
p_paddr: Elf64_Addr,
@@ -769,44 +773,44 @@ pub const Elf64_Phdr = extern struct {
p_align: Elf64_Xword,
};
pub const Elf32_Shdr = extern struct {
- sh_name: Elf32_Word,
- sh_type: Elf32_Word,
- sh_flags: Elf32_Word,
+ sh_name: Word,
+ sh_type: Word,
+ sh_flags: Word,
sh_addr: Elf32_Addr,
sh_offset: Elf32_Off,
- sh_size: Elf32_Word,
- sh_link: Elf32_Word,
- sh_info: Elf32_Word,
- sh_addralign: Elf32_Word,
- sh_entsize: Elf32_Word,
+ sh_size: Word,
+ sh_link: Word,
+ sh_info: Word,
+ sh_addralign: Word,
+ sh_entsize: Word,
};
pub const Elf64_Shdr = extern struct {
- sh_name: Elf64_Word,
- sh_type: Elf64_Word,
+ sh_name: Word,
+ sh_type: Word,
sh_flags: Elf64_Xword,
sh_addr: Elf64_Addr,
sh_offset: Elf64_Off,
sh_size: Elf64_Xword,
- sh_link: Elf64_Word,
- sh_info: Elf64_Word,
+ sh_link: Word,
+ sh_info: Word,
sh_addralign: Elf64_Xword,
sh_entsize: Elf64_Xword,
};
pub const Elf32_Chdr = extern struct {
ch_type: COMPRESS,
- ch_size: Elf32_Word,
- ch_addralign: Elf32_Word,
+ ch_size: Word,
+ ch_addralign: Word,
};
pub const Elf64_Chdr = extern struct {
ch_type: COMPRESS,
- ch_reserved: Elf64_Word = 0,
+ ch_reserved: Word = 0,
ch_size: Elf64_Xword,
ch_addralign: Elf64_Xword,
};
pub const Elf32_Sym = extern struct {
- st_name: Elf32_Word,
+ st_name: Word,
st_value: Elf32_Addr,
- st_size: Elf32_Word,
+ st_size: Word,
st_info: u8,
st_other: u8,
st_shndx: Elf32_Section,
@@ -819,7 +823,7 @@ pub const Elf32_Sym = extern struct {
}
};
pub const Elf64_Sym = extern struct {
- st_name: Elf64_Word,
+ st_name: Word,
st_info: u8,
st_other: u8,
st_shndx: Elf64_Section,
@@ -834,16 +838,16 @@ pub const Elf64_Sym = extern struct {
}
};
pub const Elf32_Syminfo = extern struct {
- si_boundto: Elf32_Half,
- si_flags: Elf32_Half,
+ si_boundto: Half,
+ si_flags: Half,
};
pub const Elf64_Syminfo = extern struct {
- si_boundto: Elf64_Half,
- si_flags: Elf64_Half,
+ si_boundto: Half,
+ si_flags: Half,
};
pub const Elf32_Rel = extern struct {
r_offset: Elf32_Addr,
- r_info: Elf32_Word,
+ r_info: Word,
pub inline fn r_sym(self: @This()) u24 {
return @truncate(self.r_info >> 8);
@@ -865,8 +869,8 @@ pub const Elf64_Rel = extern struct {
};
pub const Elf32_Rela = extern struct {
r_offset: Elf32_Addr,
- r_info: Elf32_Word,
- r_addend: Elf32_Sword,
+ r_info: Word,
+ r_addend: Sword,
pub inline fn r_sym(self: @This()) u24 {
return @truncate(self.r_info >> 8);
@@ -887,69 +891,49 @@ pub const Elf64_Rela = extern struct {
return @truncate(self.r_info);
}
};
-pub const Elf32_Relr = Elf32_Word;
+pub const Elf32_Relr = Word;
pub const Elf64_Relr = Elf64_Xword;
pub const Elf32_Dyn = extern struct {
- d_tag: Elf32_Sword,
+ d_tag: Sword,
d_val: Elf32_Addr,
};
pub const Elf64_Dyn = extern struct {
d_tag: Elf64_Sxword,
d_val: Elf64_Addr,
};
-pub const Elf32_Verdef = extern struct {
- vd_version: Elf32_Half,
- vd_flags: Elf32_Half,
- vd_ndx: Elf32_Half,
- vd_cnt: Elf32_Half,
- vd_hash: Elf32_Word,
- vd_aux: Elf32_Word,
- vd_next: Elf32_Word,
-};
-pub const Elf64_Verdef = extern struct {
- vd_version: Elf64_Half,
- vd_flags: Elf64_Half,
- vd_ndx: Elf64_Half,
- vd_cnt: Elf64_Half,
- vd_hash: Elf64_Word,
- vd_aux: Elf64_Word,
- vd_next: Elf64_Word,
+pub const Verdef = extern struct {
+ version: Half,
+ flags: Half,
+ ndx: VER_NDX,
+ cnt: Half,
+ hash: Word,
+ aux: Word,
+ next: Word,
};
-pub const Elf32_Verdaux = extern struct {
- vda_name: Elf32_Word,
- vda_next: Elf32_Word,
-};
-pub const Elf64_Verdaux = extern struct {
- vda_name: Elf64_Word,
- vda_next: Elf64_Word,
+pub const Verdaux = extern struct {
+ name: Word,
+ next: Word,
};
pub const Elf32_Verneed = extern struct {
- vn_version: Elf32_Half,
- vn_cnt: Elf32_Half,
- vn_file: Elf32_Word,
- vn_aux: Elf32_Word,
- vn_next: Elf32_Word,
+ vn_version: Half,
+ vn_cnt: Half,
+ vn_file: Word,
+ vn_aux: Word,
+ vn_next: Word,
};
pub const Elf64_Verneed = extern struct {
- vn_version: Elf64_Half,
- vn_cnt: Elf64_Half,
- vn_file: Elf64_Word,
- vn_aux: Elf64_Word,
- vn_next: Elf64_Word,
-};
-pub const Elf32_Vernaux = extern struct {
- vna_hash: Elf32_Word,
- vna_flags: Elf32_Half,
- vna_other: Elf32_Half,
- vna_name: Elf32_Word,
- vna_next: Elf32_Word,
+ vn_version: Half,
+ vn_cnt: Half,
+ vn_file: Word,
+ vn_aux: Word,
+ vn_next: Word,
};
-pub const Elf64_Vernaux = extern struct {
- vna_hash: Elf64_Word,
- vna_flags: Elf64_Half,
- vna_other: Elf64_Half,
- vna_name: Elf64_Word,
- vna_next: Elf64_Word,
+pub const Vernaux = extern struct {
+ hash: Word,
+ flags: Half,
+ other: Half,
+ name: Word,
+ next: Word,
};
pub const Elf32_auxv_t = extern struct {
a_type: u32,
@@ -964,81 +948,81 @@ pub const Elf64_auxv_t = extern struct {
},
};
pub const Elf32_Nhdr = extern struct {
- n_namesz: Elf32_Word,
- n_descsz: Elf32_Word,
- n_type: Elf32_Word,
+ n_namesz: Word,
+ n_descsz: Word,
+ n_type: Word,
};
pub const Elf64_Nhdr = extern struct {
- n_namesz: Elf64_Word,
- n_descsz: Elf64_Word,
- n_type: Elf64_Word,
+ n_namesz: Word,
+ n_descsz: Word,
+ n_type: Word,
};
pub const Elf32_Move = extern struct {
m_value: Elf32_Xword,
- m_info: Elf32_Word,
- m_poffset: Elf32_Word,
- m_repeat: Elf32_Half,
- m_stride: Elf32_Half,
+ m_info: Word,
+ m_poffset: Word,
+ m_repeat: Half,
+ m_stride: Half,
};
pub const Elf64_Move = extern struct {
m_value: Elf64_Xword,
m_info: Elf64_Xword,
m_poffset: Elf64_Xword,
- m_repeat: Elf64_Half,
- m_stride: Elf64_Half,
+ m_repeat: Half,
+ m_stride: Half,
};
pub const Elf32_gptab = extern union {
gt_header: extern struct {
- gt_current_g_value: Elf32_Word,
- gt_unused: Elf32_Word,
+ gt_current_g_value: Word,
+ gt_unused: Word,
},
gt_entry: extern struct {
- gt_g_value: Elf32_Word,
- gt_bytes: Elf32_Word,
+ gt_g_value: Word,
+ gt_bytes: Word,
},
};
pub const Elf32_RegInfo = extern struct {
- ri_gprmask: Elf32_Word,
- ri_cprmask: [4]Elf32_Word,
- ri_gp_value: Elf32_Sword,
+ ri_gprmask: Word,
+ ri_cprmask: [4]Word,
+ ri_gp_value: Sword,
};
pub const Elf_Options = extern struct {
kind: u8,
size: u8,
section: Elf32_Section,
- info: Elf32_Word,
+ info: Word,
};
pub const Elf_Options_Hw = extern struct {
- hwp_flags1: Elf32_Word,
- hwp_flags2: Elf32_Word,
+ hwp_flags1: Word,
+ hwp_flags2: Word,
};
pub const Elf32_Lib = extern struct {
- l_name: Elf32_Word,
- l_time_stamp: Elf32_Word,
- l_checksum: Elf32_Word,
- l_version: Elf32_Word,
- l_flags: Elf32_Word,
+ l_name: Word,
+ l_time_stamp: Word,
+ l_checksum: Word,
+ l_version: Word,
+ l_flags: Word,
};
pub const Elf64_Lib = extern struct {
- l_name: Elf64_Word,
- l_time_stamp: Elf64_Word,
- l_checksum: Elf64_Word,
- l_version: Elf64_Word,
- l_flags: Elf64_Word,
+ l_name: Word,
+ l_time_stamp: Word,
+ l_checksum: Word,
+ l_version: Word,
+ l_flags: Word,
};
pub const Elf32_Conflict = Elf32_Addr;
pub const Elf_MIPS_ABIFlags_v0 = extern struct {
- version: Elf32_Half,
+ version: Half,
isa_level: u8,
isa_rev: u8,
gpr_size: u8,
cpr1_size: u8,
cpr2_size: u8,
fp_abi: u8,
- isa_ext: Elf32_Word,
- ases: Elf32_Word,
- flags1: Elf32_Word,
- flags2: Elf32_Word,
+ isa_ext: Word,
+ ases: Word,
+ flags1: Word,
+ flags2: Word,
};
comptime {
@@ -1102,22 +1086,11 @@ pub const Sym = switch (@sizeOf(usize)) {
8 => Elf64_Sym,
else => @compileError("expected pointer size of 32 or 64"),
};
-pub const Verdef = switch (@sizeOf(usize)) {
- 4 => Elf32_Verdef,
- 8 => Elf64_Verdef,
- else => @compileError("expected pointer size of 32 or 64"),
-};
-pub const Verdaux = switch (@sizeOf(usize)) {
- 4 => Elf32_Verdaux,
- 8 => Elf64_Verdaux,
- else => @compileError("expected pointer size of 32 or 64"),
-};
pub const Addr = switch (@sizeOf(usize)) {
4 => Elf32_Addr,
8 => Elf64_Addr,
else => @compileError("expected pointer size of 32 or 64"),
};
-pub const Half = u16;
pub const OSABI = enum(u8) {
/// UNIX System V ABI
src/link/Elf/Archive.zig
@@ -1,15 +1,6 @@
objects: std.ArrayListUnmanaged(Object) = .empty,
strtab: std.ArrayListUnmanaged(u8) = .empty,
-pub fn isArchive(path: Path) !bool {
- const file = try path.root_dir.handle.openFile(path.sub_path, .{});
- defer file.close();
- const reader = file.reader();
- const magic = reader.readBytesNoEof(elf.ARMAG.len) catch return false;
- if (!mem.eql(u8, &magic, elf.ARMAG)) return false;
- return true;
-}
-
pub fn deinit(self: *Archive, allocator: Allocator) void {
self.objects.deinit(allocator);
self.strtab.deinit(allocator);
@@ -18,6 +9,7 @@ pub fn deinit(self: *Archive, allocator: Allocator) void {
pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
+ const diags = &comp.link_diags;
const handle = elf_file.fileHandle(handle_index);
const size = (try handle.stat()).size;
@@ -35,7 +27,7 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
pos += @sizeOf(elf.ar_hdr);
if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
- return elf_file.failParse(path, "invalid archive header delimiter: {s}", .{
+ return diags.failParse(path, "invalid archive header delimiter: {s}", .{
std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
});
}
src/link/Elf/Atom.zig
@@ -592,6 +592,7 @@ fn reportUndefined(
const file_ptr = self.file(elf_file).?;
const rel_esym = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),
+ .shared_object => |so| so.parsed.symtab[rel.r_sym()],
inline else => |x| x.symtab.items[rel.r_sym()],
};
const esym = sym.elfSym(elf_file);
src/link/Elf/LdScript.zig
@@ -21,6 +21,8 @@ pub const Error = error{
pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
+ const diags = &comp.link_diags;
+
var tokenizer = Tokenizer{ .source = data };
var tokens = std.ArrayList(Token).init(gpa);
defer tokens.deinit();
@@ -37,7 +39,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
try line_col.append(.{ .line = line, .column = column });
switch (tok.id) {
.invalid => {
- return elf_file.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
+ return diags.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
});
},
@@ -61,7 +63,7 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
const last_token_id = parser.it.pos - 1;
const last_token = parser.it.get(last_token_id);
const lcol = line_col.items[last_token_id];
- return elf_file.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
+ return diags.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
@tagName(last_token.id),
last_token.get(data),
lcol.line,
src/link/Elf/Object.zig
@@ -310,7 +310,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
sym_ptr.name_offset = sym.st_name;
sym_ptr.esym_index = @intCast(i);
sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
- sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL;
+ sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else .LOCAL;
sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
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 {
sym.ref = .{ .index = 0, .file = 0 };
sym.esym_index = esym_index;
sym.file_index = self.index;
- sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
+ sym.version_index = if (is_import) .LOCAL else elf_file.default_sym_version;
sym.flags.import = is_import;
const idx = self.symbols_resolver.items[i];
@@ -598,8 +598,9 @@ pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
const ref = self.resolveSymbol(@intCast(idx), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
- if (sym.version_index == elf.VER_NDX_LOCAL) continue;
- const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
+ // https://github.com/ziglang/zig/issues/21678
+ if (@as(u16, @bitCast(sym.version_index)) == @as(u16, @bitCast(elf.Versym.LOCAL))) continue;
+ const vis: elf.STV = @enumFromInt(sym.elfSym(elf_file).st_other);
if (vis == .HIDDEN) continue;
if (file == .shared_object and !sym.isAbs(elf_file)) {
sym.flags.import = true;
src/link/Elf/relocatable.zig
@@ -4,22 +4,22 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path
for (comp.objects) |obj| {
switch (Compilation.classifyFileExt(obj.path.sub_path)) {
- .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
- .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
- else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),
+ .object => parseObjectStaticLibReportingFailure(elf_file, obj.path),
+ .static_library => parseArchiveStaticLibReportingFailure(elf_file, obj.path),
+ else => diags.addParseError(obj.path, "unrecognized file extension", .{}),
}
}
for (comp.c_object_table.keys()) |key| {
- try parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path);
+ parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path);
}
if (module_obj_path) |path| {
- try parseObjectStaticLibReportingFailure(elf_file, path);
+ parseObjectStaticLibReportingFailure(elf_file, path);
}
if (comp.include_compiler_rt) {
- try parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
+ parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path);
}
if (diags.hasErrors()) return error.FlushFailure;
@@ -154,21 +154,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
const diags = &comp.link_diags;
for (comp.objects) |obj| {
- if (obj.isObject()) {
- try elf_file.parseObjectReportingFailure(obj.path);
- } else {
- try elf_file.parseLibraryReportingFailure(.{ .path = obj.path }, obj.must_link);
- }
+ elf_file.parseInputReportingFailure(obj.path, false, obj.must_link);
}
// This is a set of object files emitted by clang in a single `build-exe` invocation.
// For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
// in this set.
for (comp.c_object_table.keys()) |key| {
- try elf_file.parseObjectReportingFailure(key.status.success.object_path);
+ elf_file.parseObjectReportingFailure(key.status.success.object_path);
}
- if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);
+ if (module_obj_path) |path| elf_file.parseObjectReportingFailure(path);
if (diags.hasErrors()) return error.FlushFailure;
@@ -219,19 +215,19 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?Path) l
if (diags.hasErrors()) return error.FlushFailure;
}
-fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
+fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
+ const diags = &elf_file.base.comp.link_diags;
parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
error.LinkFailure => return,
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| try elf_file.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
+ else => |e| diags.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
};
}
-fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) error{OutOfMemory}!void {
+fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
+ const diags = &elf_file.base.comp.link_diags;
parseArchiveStaticLib(elf_file, path) catch |err| switch (err) {
error.LinkFailure => return,
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| try elf_file.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
+ else => |e| diags.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}),
};
}
src/link/Elf/Symbol.zig
@@ -22,7 +22,7 @@ esym_index: Index = 0,
/// Index of the source version symbol this symbol references if any.
/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.
-version_index: elf.Elf64_Versym = elf.VER_NDX_LOCAL,
+version_index: elf.Versym = .LOCAL,
/// Misc flags for the symbol packaged as packed struct for compression.
flags: Flags = .{},
@@ -87,6 +87,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
return switch (symbol.file(elf_file).?) {
.zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],
+ .shared_object => |so| so.parsed.symtab[symbol.esym_index],
inline else => |x| x.symtab.items[symbol.esym_index],
};
}
@@ -235,7 +236,7 @@ pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
assert(file_ptr == .shared_object);
const shared_object = file_ptr.shared_object;
const esym = symbol.elfSym(elf_file);
- const shdr = shared_object.shdrs.items[esym.st_shndx];
+ const shdr = shared_object.parsed.sections[esym.st_shndx];
const alignment = @max(1, shdr.sh_addralign);
return if (esym.st_value == 0)
alignment
@@ -351,8 +352,8 @@ fn formatName(
const elf_file = ctx.elf_file;
const symbol = ctx.symbol;
try writer.writeAll(symbol.name(elf_file));
- switch (symbol.version_index & elf.VERSYM_VERSION) {
- elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},
+ switch (symbol.version_index.VERSION) {
+ @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {},
else => {
const file_ptr = symbol.file(elf_file).?;
assert(file_ptr == .shared_object);
src/link/Elf/synthetic_sections.zig
@@ -1345,8 +1345,8 @@ pub const GnuHashSection = struct {
pub const VerneedSection = struct {
verneed: std.ArrayListUnmanaged(elf.Elf64_Verneed) = .empty,
- vernaux: std.ArrayListUnmanaged(elf.Elf64_Vernaux) = .empty,
- index: elf.Elf64_Versym = elf.VER_NDX_GLOBAL + 1,
+ vernaux: std.ArrayListUnmanaged(elf.Vernaux) = .empty,
+ index: elf.Versym = .{ .VERSION = elf.Versym.GLOBAL.VERSION + 1, .HIDDEN = false },
pub fn deinit(vern: *VerneedSection, allocator: Allocator) void {
vern.verneed.deinit(allocator);
@@ -1363,7 +1363,7 @@ pub const VerneedSection = struct {
/// Index of the defining this symbol version shared object file
shared_object: File.Index,
/// Version index
- version_index: elf.Elf64_Versym,
+ version_index: elf.Versym,
fn soname(this: @This(), ctx: *Elf) []const u8 {
const shared_object = ctx.file(this.shared_object).?.shared_object;
@@ -1376,7 +1376,8 @@ pub const VerneedSection = struct {
}
pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
- if (lhs.shared_object == rhs.shared_object) return lhs.version_index < rhs.version_index;
+ if (lhs.shared_object == rhs.shared_object)
+ return @as(u16, @bitCast(lhs.version_index)) < @as(u16, @bitCast(rhs.version_index));
return mem.lessThan(u8, lhs.soname(ctx), rhs.soname(ctx));
}
};
@@ -1389,7 +1390,7 @@ pub const VerneedSection = struct {
for (dynsyms, 1..) |entry, i| {
const symbol = elf_file.symbol(entry.ref).?;
- if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) {
+ if (symbol.flags.import and symbol.version_index.VERSION > elf.Versym.GLOBAL.VERSION) {
const shared_object = symbol.file(elf_file).?.shared_object;
verneed.appendAssumeCapacity(.{
.index = i,
@@ -1404,11 +1405,12 @@ pub const VerneedSection = struct {
var last = verneed.items[0];
var last_verneed = try vern.addVerneed(last.soname(elf_file), elf_file);
var last_vernaux = try vern.addVernaux(last_verneed, last.versionString(elf_file), elf_file);
- versyms[last.index] = last_vernaux.vna_other;
+ versyms[last.index] = @bitCast(last_vernaux.other);
for (verneed.items[1..]) |ver| {
if (ver.shared_object == last.shared_object) {
- if (ver.version_index != last.version_index) {
+ // https://github.com/ziglang/zig/issues/21678
+ if (@as(u16, @bitCast(ver.version_index)) != @as(u16, @bitCast(last.version_index))) {
last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
}
} else {
@@ -1416,7 +1418,7 @@ pub const VerneedSection = struct {
last_vernaux = try vern.addVernaux(last_verneed, ver.versionString(elf_file), elf_file);
}
last = ver;
- versyms[ver.index] = last_vernaux.vna_other;
+ versyms[ver.index] = @bitCast(last_vernaux.other);
}
// Fixup offsets
@@ -1428,8 +1430,8 @@ pub const VerneedSection = struct {
vsym.vn_aux = vernaux_off - verneed_off;
var inner_off: u32 = 0;
for (vern.vernaux.items[count..][0..vsym.vn_cnt], 0..) |*vaux, vaux_i| {
- if (vaux_i < vsym.vn_cnt - 1) vaux.vna_next = @sizeOf(elf.Elf64_Vernaux);
- inner_off += @sizeOf(elf.Elf64_Vernaux);
+ if (vaux_i < vsym.vn_cnt - 1) vaux.next = @sizeOf(elf.Vernaux);
+ inner_off += @sizeOf(elf.Vernaux);
}
vernaux_off += inner_off;
verneed_off += @sizeOf(elf.Elf64_Verneed);
@@ -1456,24 +1458,24 @@ pub const VerneedSection = struct {
verneed_sym: *elf.Elf64_Verneed,
version: [:0]const u8,
elf_file: *Elf,
- ) !elf.Elf64_Vernaux {
+ ) !elf.Vernaux {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const sym = try vern.vernaux.addOne(gpa);
sym.* = .{
- .vna_hash = HashSection.hasher(version),
- .vna_flags = 0,
- .vna_other = vern.index,
- .vna_name = try elf_file.insertDynString(version),
- .vna_next = 0,
+ .hash = HashSection.hasher(version),
+ .flags = 0,
+ .other = @bitCast(vern.index),
+ .name = try elf_file.insertDynString(version),
+ .next = 0,
};
verneed_sym.vn_cnt += 1;
- vern.index += 1;
+ vern.index.VERSION += 1;
return sym.*;
}
pub fn size(vern: VerneedSection) usize {
- return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Elf64_Vernaux);
+ return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux);
}
pub fn write(vern: VerneedSection, writer: anytype) !void {
src/link/Elf/ZigObject.zig
@@ -264,7 +264,7 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
}
}
-pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
+pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
// Handle any lazy symbols that were emitted by incremental compilation.
if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
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 {
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = @intCast(index);
global.file_index = self.index;
- global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
+ global.version_index = if (is_import) .LOCAL else elf_file.default_sym_version;
global.flags.import = is_import;
const idx = self.symbols_resolver.items[i];
@@ -689,8 +689,9 @@ pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
- if (sym.version_index == elf.VER_NDX_LOCAL) continue;
- const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
+ // https://github.com/ziglang/zig/issues/21678
+ if (@as(u16, @bitCast(sym.version_index)) == @as(u16, @bitCast(elf.Versym.LOCAL))) continue;
+ const vis: elf.STV = @enumFromInt(sym.elfSym(elf_file).st_other);
if (vis == .HIDDEN) continue;
if (file == .shared_object and !sym.isAbs(elf_file)) {
sym.flags.import = true;
src/link/MachO/Archive.zig
@@ -29,10 +29,9 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
pos += @sizeOf(ar_hdr);
if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
- try diags.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
+ return diags.failParse(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
});
- return error.MalformedArchive;
}
var hdr_size = try hdr.size();
src/link/MachO/relocatable.zig
@@ -29,14 +29,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
}
for (positionals.items) |obj| {
- macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
- error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
- else => |e| try diags.reportParseError(
- obj.path,
- "unexpected error: reading input file failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
+ diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
}
if (diags.hasErrors()) return error.FlushFailure;
@@ -95,14 +89,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
}
for (positionals.items) |obj| {
- macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
- error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
- else => |e| try diags.reportParseError(
- obj.path,
- "unexpected error: reading input file failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ macho_file.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
+ diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
}
if (diags.hasErrors()) return error.FlushFailure;
src/link/Elf.zig
@@ -46,7 +46,7 @@ file_handles: std.ArrayListUnmanaged(File.Handle) = .empty,
zig_object_index: ?File.Index = null,
linker_defined_index: ?File.Index = null,
objects: std.ArrayListUnmanaged(File.Index) = .empty,
-shared_objects: std.ArrayListUnmanaged(File.Index) = .empty,
+shared_objects: std.StringArrayHashMapUnmanaged(File.Index) = .empty,
/// List of all output sections and their associated metadata.
sections: std.MultiArrayList(Section) = .{},
@@ -62,7 +62,7 @@ phdr_indexes: ProgramHeaderIndexes = .{},
section_indexes: SectionIndexes = .{},
page_size: u32,
-default_sym_version: elf.Elf64_Versym,
+default_sym_version: elf.Versym,
/// .shstrtab buffer
shstrtab: std.ArrayListUnmanaged(u8) = .empty,
@@ -75,7 +75,7 @@ dynsym: DynsymSection = .{},
/// .dynstrtab buffer
dynstrtab: std.ArrayListUnmanaged(u8) = .empty,
/// Version symbol table. Only populated and emitted when linking dynamically.
-versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .empty,
+versym: std.ArrayListUnmanaged(elf.Versym) = .empty,
/// .verneed section
verneed: VerneedSection = .{},
/// .got section
@@ -114,7 +114,7 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,
merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,
comment_merge_section_index: ?Merge.Section.Index = null,
-first_eflags: ?elf.Elf64_Word = null,
+first_eflags: ?elf.Word = null,
const SectionIndexes = struct {
copy_rel: ?u32 = null,
@@ -265,10 +265,7 @@ pub fn createEmpty(
};
const is_dyn_lib = output_mode == .Lib and link_mode == .dynamic;
- const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or comp.config.rdynamic)
- elf.VER_NDX_GLOBAL
- else
- elf.VER_NDX_LOCAL;
+ const default_sym_version: elf.Versym = if (is_dyn_lib or comp.config.rdynamic) .GLOBAL else .LOCAL;
// If using LLD to link, this code should produce an object file so that it
// can be passed to LLD.
@@ -794,58 +791,51 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
// --verbose-link
if (comp.verbose_link) try self.dumpArgv(comp);
- if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self, tid);
+ if (self.zigObjectPtr()) |zig_object| try zig_object.flush(self, tid);
if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
const csu = try comp.getCrtPaths(arena);
// csu prelude
- if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
- if (csu.crti) |path| try parseObjectReportingFailure(self, path);
- if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path);
+ if (csu.crt0) |path| parseObjectReportingFailure(self, path);
+ if (csu.crti) |path| parseObjectReportingFailure(self, path);
+ if (csu.crtbegin) |path| parseObjectReportingFailure(self, path);
for (comp.objects) |obj| {
- if (obj.isObject()) {
- try parseObjectReportingFailure(self, obj.path);
- } else {
- try parseLibraryReportingFailure(self, .{ .path = obj.path }, obj.must_link);
- }
+ parseInputReportingFailure(self, obj.path, obj.needed, obj.must_link);
}
// This is a set of object files emitted by clang in a single `build-exe` invocation.
// For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
// in this set.
for (comp.c_object_table.keys()) |key| {
- try parseObjectReportingFailure(self, key.status.success.object_path);
+ parseObjectReportingFailure(self, key.status.success.object_path);
}
- if (module_obj_path) |path| try parseObjectReportingFailure(self, path);
+ if (module_obj_path) |path| parseObjectReportingFailure(self, path);
- if (comp.config.any_sanitize_thread) try parseCrtFileReportingFailure(self, comp.tsan_lib.?);
- if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
+ if (comp.config.any_sanitize_thread) parseCrtFileReportingFailure(self, comp.tsan_lib.?);
+ if (comp.config.any_fuzz) parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
// libc
if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
- if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
+ if (comp.libc_static_lib) |lib| parseCrtFileReportingFailure(self, lib);
}
for (comp.system_libs.values()) |lib_info| {
- try self.parseLibraryReportingFailure(.{
- .needed = lib_info.needed,
- .path = lib_info.path.?,
- }, false);
+ parseInputReportingFailure(self, lib_info.path.?, lib_info.needed, false);
}
// libc++ dep
if (comp.config.link_libcpp) {
- try self.parseLibraryReportingFailure(.{ .path = comp.libcxxabi_static_lib.?.full_object_path }, false);
- try self.parseLibraryReportingFailure(.{ .path = comp.libcxx_static_lib.?.full_object_path }, false);
+ parseInputReportingFailure(self, comp.libcxxabi_static_lib.?.full_object_path, false, false);
+ parseInputReportingFailure(self, comp.libcxx_static_lib.?.full_object_path, false, false);
}
// libunwind dep
if (comp.config.link_libunwind) {
- try self.parseLibraryReportingFailure(.{ .path = comp.libunwind_static_lib.?.full_object_path }, false);
+ parseInputReportingFailure(self, comp.libunwind_static_lib.?.full_object_path, false, false);
}
// libc dep
@@ -869,17 +859,16 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
if (try self.accessLibPath(arena, &test_path, &checked_paths, lc.crt_dir.?, lib_name, .static))
break :success;
- try diags.reportMissingLibraryError(
+ diags.addMissingLibraryError(
checked_paths.items,
"missing system library: '{s}' was not found",
.{lib_name},
);
-
continue;
}
const resolved_path = Path.initCwd(try arena.dupe(u8, test_path.items));
- try self.parseLibraryReportingFailure(.{ .path = resolved_path }, false);
+ parseInputReportingFailure(self, resolved_path, false, false);
}
} else if (target.isGnuLibC()) {
for (glibc.libs) |lib| {
@@ -890,17 +879,15 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
const lib_path = Path.initCwd(try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
}));
- try self.parseLibraryReportingFailure(.{ .path = lib_path }, false);
+ parseInputReportingFailure(self, lib_path, false, false);
}
- try self.parseLibraryReportingFailure(.{
- .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
- }, false);
+ parseInputReportingFailure(self, try comp.get_libc_crt_file(arena, "libc_nonshared.a"), false, false);
} else if (target.isMusl()) {
const path = try comp.get_libc_crt_file(arena, switch (link_mode) {
.static => "libc.a",
.dynamic => "libc.so",
});
- try self.parseLibraryReportingFailure(.{ .path = path }, false);
+ parseInputReportingFailure(self, path, false, false);
} else {
diags.flags.missing_libc = true;
}
@@ -912,35 +899,17 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
// to be after the shared libraries, so they are picked up from the shared
// libraries, not libcompiler_rt.
if (comp.compiler_rt_lib) |crt_file| {
- try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
+ parseInputReportingFailure(self, crt_file.full_object_path, false, false);
} else if (comp.compiler_rt_obj) |crt_file| {
- try parseObjectReportingFailure(self, crt_file.full_object_path);
+ parseObjectReportingFailure(self, crt_file.full_object_path);
}
// csu postlude
- if (csu.crtend) |path| try parseObjectReportingFailure(self, path);
- if (csu.crtn) |path| try parseObjectReportingFailure(self, path);
+ if (csu.crtend) |path| parseObjectReportingFailure(self, path);
+ if (csu.crtn) |path| parseObjectReportingFailure(self, path);
if (diags.hasErrors()) return error.FlushFailure;
- // Dedup shared objects
- {
- var seen_dsos = std.StringHashMap(void).init(gpa);
- defer seen_dsos.deinit();
- try seen_dsos.ensureTotalCapacity(@as(u32, @intCast(self.shared_objects.items.len)));
-
- var i: usize = 0;
- while (i < self.shared_objects.items.len) {
- const index = self.shared_objects.items[i];
- const shared_object = self.file(index).?.shared_object;
- const soname = shared_object.soname();
- const gop = seen_dsos.getOrPutAssumeCapacity(soname);
- if (gop.found_existing) {
- _ = self.shared_objects.orderedRemove(i);
- } else i += 1;
- }
- }
-
// If we haven't already, create a linker-generated input file comprising of
// linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
if (self.linker_defined_index == null) {
@@ -1372,42 +1341,51 @@ pub const ParseError = error{
UnknownFileType,
} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
-fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) error{OutOfMemory}!void {
- if (crt_file.isObject()) {
- try parseObjectReportingFailure(self, crt_file.full_object_path);
- } else {
- try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
- }
+fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CrtFile) void {
+ parseInputReportingFailure(self, crt_file.full_object_path, false, false);
}
-pub fn parseObjectReportingFailure(self: *Elf, path: Path) error{OutOfMemory}!void {
- self.parseObject(path) catch |err| switch (err) {
- error.LinkFailure => return, // already reported
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| try self.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),
- };
+pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_link: bool) void {
+ const gpa = self.base.comp.gpa;
+ const diags = &self.base.comp.link_diags;
+ const target = self.getTarget();
+
+ switch (Compilation.classifyFileExt(path.sub_path)) {
+ .object => parseObjectReportingFailure(self, path),
+ .shared_library => parseSharedObject(gpa, diags, .{
+ .path = path,
+ .needed = needed,
+ }, &self.shared_objects, &self.files, target) catch |err| switch (err) {
+ error.LinkFailure => return, // already reported
+ error.BadMagic, error.UnexpectedEndOfFile => {
+ // It could be a linker script.
+ self.parseLdScript(.{ .path = path, .needed = needed }) catch |err2| switch (err2) {
+ error.LinkFailure => return, // already reported
+ else => |e| diags.addParseError(path, "failed to parse linker script: {s}", .{@errorName(e)}),
+ };
+ },
+ else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),
+ },
+ .static_library => parseArchive(self, path, must_link) catch |err| switch (err) {
+ error.LinkFailure => return, // already reported
+ else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
+ },
+ .unknown => self.parseLdScript(.{ .path = path, .needed = needed }) catch |err| switch (err) {
+ error.LinkFailure => return, // already reported
+ else => |e| diags.addParseError(path, "failed to parse linker script: {s}", .{@errorName(e)}),
+ },
+ else => diags.addParseError(path, "unrecognized file type", .{}),
+ }
}
-pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool) error{OutOfMemory}!void {
- self.parseLibrary(lib, must_link) catch |err| switch (err) {
+pub fn parseObjectReportingFailure(self: *Elf, path: Path) void {
+ const diags = &self.base.comp.link_diags;
+ self.parseObject(path) catch |err| switch (err) {
error.LinkFailure => return, // already reported
- error.OutOfMemory => return error.OutOfMemory,
- else => |e| try self.addParseError(lib.path, "unable to parse library: {s}", .{@errorName(e)}),
+ else => |e| diags.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}),
};
}
-fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
- const tracy = trace(@src());
- defer tracy.end();
- if (try Archive.isArchive(lib.path)) {
- try self.parseArchive(lib.path, must_link);
- } else if (try SharedObject.isSharedObject(lib.path)) {
- try self.parseSharedObject(lib);
- } else {
- try self.parseLdScript(lib);
- }
-}
-
fn parseObject(self: *Elf, path: Path) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
@@ -1457,28 +1435,80 @@ fn parseArchive(self: *Elf, path: Path, must_link: bool) ParseError!void {
}
}
-fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
+fn parseSharedObject(
+ gpa: Allocator,
+ diags: *Diags,
+ lib: SystemLib,
+ shared_objects: *std.StringArrayHashMapUnmanaged(File.Index),
+ files: *std.MultiArrayList(File.Entry),
+ target: std.Target,
+) !void {
const tracy = trace(@src());
defer tracy.end();
- const gpa = self.base.comp.gpa;
const handle = try lib.path.root_dir.handle.openFile(lib.path.sub_path, .{});
defer handle.close();
- const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
- self.files.set(index, .{ .shared_object = .{
- .path = .{
- .root_dir = lib.path.root_dir,
- .sub_path = try gpa.dupe(u8, lib.path.sub_path),
+ const stat = Stat.fromFs(try handle.stat());
+ var header = try SharedObject.parseHeader(gpa, diags, lib.path, handle, stat, target);
+ defer header.deinit(gpa);
+
+ const soname = header.soname() orelse lib.path.basename();
+
+ const gop = try shared_objects.getOrPut(gpa, soname);
+ if (gop.found_existing) {
+ header.deinit(gpa);
+ return;
+ }
+ errdefer _ = shared_objects.pop();
+
+ const index: File.Index = @intCast(try files.addOne(gpa));
+ errdefer _ = files.pop();
+
+ gop.value_ptr.* = index;
+
+ var parsed = try SharedObject.parse(gpa, &header, handle);
+ errdefer parsed.deinit(gpa);
+
+ const duped_path: Path = .{
+ .root_dir = lib.path.root_dir,
+ .sub_path = try gpa.dupe(u8, lib.path.sub_path),
+ };
+ errdefer gpa.free(duped_path.sub_path);
+
+ files.set(index, .{
+ .shared_object = .{
+ .parsed = parsed,
+ .path = duped_path,
+ .index = index,
+ .needed = lib.needed,
+ .alive = lib.needed,
+ .aliases = null,
+ .symbols = .empty,
+ .symbols_extra = .empty,
+ .symbols_resolver = .empty,
+ .output_symtab_ctx = .{},
},
- .index = index,
- .needed = lib.needed,
- .alive = lib.needed,
- } });
- try self.shared_objects.append(gpa, index);
+ });
+ const so = fileLookup(files.*, index).?.shared_object;
- const shared_object = self.file(index).?.shared_object;
- try shared_object.parse(self, handle);
+ // TODO: save this work for later
+ const nsyms = parsed.symbols.len;
+ try so.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
+ try so.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @typeInfo(Symbol.Extra).@"struct".fields.len);
+ try so.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
+ so.symbols_resolver.appendNTimesAssumeCapacity(0, nsyms);
+
+ for (parsed.symtab, parsed.symbols, parsed.versyms, 0..) |esym, sym, versym, i| {
+ const out_sym_index = so.addSymbolAssumeCapacity();
+ const out_sym = &so.symbols.items[out_sym_index];
+ out_sym.value = @intCast(esym.st_value);
+ out_sym.name_offset = sym.mangled_name;
+ out_sym.ref = .{ .index = 0, .file = 0 };
+ out_sym.esym_index = @intCast(i);
+ out_sym.version_index = versym;
+ out_sym.extra_index = so.addSymbolExtraAssumeCapacity(.{});
+ }
}
fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
@@ -1537,7 +1567,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
}
}
- try diags.reportMissingLibraryError(
+ diags.addMissingLibraryError(
checked_paths.items,
"missing library dependency: GNU ld script '{}' requires '{s}', but file not found",
.{ @as(Path, lib.path), script_arg.path },
@@ -1546,26 +1576,16 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
}
const full_path = Path.initCwd(test_path.items);
- self.parseLibrary(.{
- .needed = script_arg.needed,
- .path = full_path,
- }, false) catch |err| switch (err) {
- error.LinkFailure => continue, // already reported
- else => |e| try self.addParseError(
- full_path,
- "unexpected error: parsing library failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ parseInputReportingFailure(self, full_path, script_arg.needed, false);
}
}
-pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {
+pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Word) !void {
if (self.first_eflags == null) {
self.first_eflags = e_flags;
return; // there isn't anything to conflict with yet
}
- const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;
+ const self_eflags: *elf.Word = &self.first_eflags.?;
switch (self.getTarget().cpu.arch) {
.riscv64 => {
@@ -1641,11 +1661,14 @@ fn accessLibPath(
/// 5. Remove references to dead objects/shared objects
/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
pub fn resolveSymbols(self: *Elf) !void {
+ // This function mutates `shared_objects`.
+ const shared_objects = &self.shared_objects;
+
// Resolve symbols in the ZigObject. For now, we assume that it's always live.
if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
// Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
- for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ for (shared_objects.values()) |index| try self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
// Mark live objects.
@@ -1662,11 +1685,14 @@ pub fn resolveSymbols(self: *Elf) !void {
_ = self.objects.orderedRemove(i);
} else i += 1;
}
+ // TODO This loop has 2 major flaws:
+ // 1. It is O(N^2) which is never allowed in the codebase.
+ // 2. It mutates shared_objects, which is a non-starter for incremental compilation.
i = 0;
- while (i < self.shared_objects.items.len) {
- const index = self.shared_objects.items[i];
+ while (i < shared_objects.values().len) {
+ const index = shared_objects.values()[i];
if (!self.file(index).?.isAlive()) {
- _ = self.shared_objects.orderedRemove(i);
+ _ = shared_objects.orderedRemoveAt(i);
} else i += 1;
}
@@ -1687,7 +1713,7 @@ pub fn resolveSymbols(self: *Elf) !void {
// Re-resolve the symbols.
if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
- for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
+ for (shared_objects.values()) |index| try self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
}
@@ -1696,12 +1722,13 @@ pub fn resolveSymbols(self: *Elf) !void {
/// This routine will prune unneeded objects extracted from archives and
/// unneeded shared objects.
fn markLive(self: *Elf) void {
+ const shared_objects = self.shared_objects.values();
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
for (self.objects.items) |index| {
const file_ptr = self.file(index).?;
if (file_ptr.isAlive()) file_ptr.markLive(self);
}
- for (self.shared_objects.items) |index| {
+ for (shared_objects) |index| {
const file_ptr = self.file(index).?;
if (file_ptr.isAlive()) file_ptr.markLive(self);
}
@@ -1716,6 +1743,7 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {
}
fn markImportsExports(self: *Elf) void {
+ const shared_objects = self.shared_objects.values();
if (self.zigObjectPtr()) |zo| {
zo.markImportsExports(self);
}
@@ -1723,7 +1751,7 @@ fn markImportsExports(self: *Elf) void {
self.file(index).?.object.markImportsExports(self);
}
if (!self.isEffectivelyDynLib()) {
- for (self.shared_objects.items) |index| {
+ for (shared_objects) |index| {
self.file(index).?.shared_object.markImportExports(self);
}
}
@@ -1744,6 +1772,7 @@ fn claimUnresolved(self: *Elf) void {
/// alloc sections.
fn scanRelocs(self: *Elf) !void {
const gpa = self.base.comp.gpa;
+ const shared_objects = self.shared_objects.values();
var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
defer {
@@ -1787,7 +1816,7 @@ fn scanRelocs(self: *Elf) !void {
for (self.objects.items) |index| {
try self.file(index).?.createSymbolIndirection(self);
}
- for (self.shared_objects.items) |index| {
+ for (shared_objects) |index| {
try self.file(index).?.createSymbolIndirection(self);
}
if (self.linkerDefinedPtr()) |obj| {
@@ -1905,10 +1934,10 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
// our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.
const id_symlink_basename = "lld.id";
- var man: Cache.Manifest = undefined;
+ var man: std.Build.Cache.Manifest = undefined;
defer if (!self.base.disable_lld_caching) man.deinit();
- var digest: [Cache.hex_digest_len]u8 = undefined;
+ var digest: [std.Build.Cache.hex_digest_len]u8 = undefined;
if (!self.base.disable_lld_caching) {
man = comp.cache_parent.obtain();
@@ -1988,7 +2017,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
digest = man.final();
var prev_digest_buf: [digest.len]u8 = undefined;
- const prev_digest: []u8 = Cache.readSmallFile(
+ const prev_digest: []u8 = std.Build.Cache.readSmallFile(
directory.handle,
id_symlink_basename,
&prev_digest_buf,
@@ -2442,7 +2471,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
if (!self.base.disable_lld_caching) {
// Update the file with the digest. If it fails we can continue; it only
// means that the next invocation will have an unnecessary cache miss.
- Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
+ std.Build.Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
};
// Again failure here only means an unnecessary cache miss.
@@ -2899,6 +2928,7 @@ fn initSyntheticSections(self: *Elf) !void {
const comp = self.base.comp;
const target = self.getTarget();
const ptr_size = self.ptrWidthBytes();
+ const shared_objects = self.shared_objects.values();
const needs_eh_frame = blk: {
if (self.zigObjectPtr()) |zo|
@@ -3023,7 +3053,7 @@ fn initSyntheticSections(self: *Elf) !void {
});
}
- if (self.isEffectivelyDynLib() or self.shared_objects.items.len > 0 or comp.config.pie) {
+ if (self.isEffectivelyDynLib() or shared_objects.len > 0 or comp.config.pie) {
if (self.section_indexes.dynstrtab == null) {
self.section_indexes.dynstrtab = try self.addSection(.{
.name = try self.insertShString(".dynstr"),
@@ -3072,7 +3102,7 @@ fn initSyntheticSections(self: *Elf) !void {
const needs_versions = for (self.dynsym.entries.items) |entry| {
const sym = self.symbol(entry.ref).?;
- if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
+ if (sym.flags.import and sym.version_index.VERSION > elf.Versym.GLOBAL.VERSION) break true;
} else false;
if (needs_versions) {
if (self.section_indexes.versym == null) {
@@ -3080,8 +3110,8 @@ fn initSyntheticSections(self: *Elf) !void {
.name = try self.insertShString(".gnu.version"),
.flags = elf.SHF_ALLOC,
.type = elf.SHT_GNU_VERSYM,
- .addralign = @alignOf(elf.Elf64_Versym),
- .entsize = @sizeOf(elf.Elf64_Versym),
+ .addralign = @alignOf(elf.Versym),
+ .entsize = @sizeOf(elf.Versym),
});
}
if (self.section_indexes.verneed == null) {
@@ -3259,7 +3289,9 @@ fn sortInitFini(self: *Elf) !void {
fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
if (self.section_indexes.dynamic == null) return;
- for (self.shared_objects.items) |index| {
+ const shared_objects = self.shared_objects.values();
+
+ for (shared_objects) |index| {
const shared_object = self.file(index).?.shared_object;
if (!shared_object.alive) continue;
try self.dynamic.addNeeded(shared_object, self);
@@ -3283,7 +3315,7 @@ fn setVersionSymtab(self: *Elf) !void {
const gpa = self.base.comp.gpa;
if (self.section_indexes.versym == null) return;
try self.versym.resize(gpa, self.dynsym.count());
- self.versym.items[0] = elf.VER_NDX_LOCAL;
+ self.versym.items[0] = .LOCAL;
for (self.dynsym.entries.items, 1..) |entry, i| {
const sym = self.symbol(entry.ref).?;
self.versym.items[i] = sym.version_index;
@@ -3653,7 +3685,7 @@ fn updateSectionSizes(self: *Elf) !void {
}
if (self.section_indexes.versym) |index| {
- shdrs[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
+ shdrs[index].sh_size = self.versym.items.len * @sizeOf(elf.Versym);
}
if (self.section_indexes.verneed) |index| {
@@ -4055,13 +4087,15 @@ pub fn updateSymtabSize(self: *Elf) !void {
var strsize: u32 = 0;
const gpa = self.base.comp.gpa;
+ const shared_objects = self.shared_objects.values();
+
var files = std.ArrayList(File.Index).init(gpa);
defer files.deinit();
- try files.ensureTotalCapacityPrecise(self.objects.items.len + self.shared_objects.items.len + 2);
+ try files.ensureTotalCapacityPrecise(self.objects.items.len + shared_objects.len + 2);
if (self.zig_object_index) |index| files.appendAssumeCapacity(index);
for (self.objects.items) |index| files.appendAssumeCapacity(index);
- for (self.shared_objects.items) |index| files.appendAssumeCapacity(index);
+ for (shared_objects) |index| files.appendAssumeCapacity(index);
if (self.linker_defined_index) |index| files.appendAssumeCapacity(index);
// Section symbols
@@ -4284,6 +4318,8 @@ pub fn writeShStrtab(self: *Elf) !void {
pub fn writeSymtab(self: *Elf) !void {
const gpa = self.base.comp.gpa;
+ const shared_objects = self.shared_objects.values();
+
const slice = self.sections.slice();
const symtab_shdr = slice.items(.shdr)[self.section_indexes.symtab.?];
const strtab_shdr = slice.items(.shdr)[self.section_indexes.strtab.?];
@@ -4335,7 +4371,7 @@ pub fn writeSymtab(self: *Elf) !void {
file_ptr.writeSymtab(self);
}
- for (self.shared_objects.items) |index| {
+ for (shared_objects) |index| {
const file_ptr = self.file(index).?;
file_ptr.writeSymtab(self);
}
@@ -4368,8 +4404,8 @@ pub fn writeSymtab(self: *Elf) !void {
.st_info = sym.st_info,
.st_other = sym.st_other,
.st_shndx = sym.st_shndx,
- .st_value = @as(u32, @intCast(sym.st_value)),
- .st_size = @as(u32, @intCast(sym.st_size)),
+ .st_value = @intCast(sym.st_value),
+ .st_size = @intCast(sym.st_size),
};
if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
}
@@ -4925,18 +4961,6 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
});
}
-pub fn addParseError(
- self: *Elf,
- path: Path,
- comptime format: []const u8,
- args: anytype,
-) error{OutOfMemory}!void {
- const diags = &self.base.comp.link_diags;
- var err = try diags.addErrorWithNotes(1);
- try err.addMsg(format, args);
- try err.addNote("while parsing {}", .{path});
-}
-
pub fn addFileError(
self: *Elf,
file_index: File.Index,
@@ -4959,16 +4983,6 @@ pub fn failFile(
return error.LinkFailure;
}
-pub fn failParse(
- self: *Elf,
- path: Path,
- comptime format: []const u8,
- args: anytype,
-) error{ OutOfMemory, LinkFailure } {
- try addParseError(self, path, format, args);
- return error.LinkFailure;
-}
-
const FormatShdrCtx = struct {
elf_file: *Elf,
shdr: elf.Elf64_Shdr,
@@ -5113,6 +5127,8 @@ fn fmtDumpState(
_ = unused_fmt_string;
_ = options;
+ const shared_objects = self.shared_objects.values();
+
if (self.zigObjectPtr()) |zig_object| {
try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.basename });
try writer.print("{}{}", .{
@@ -5136,11 +5152,11 @@ fn fmtDumpState(
});
}
- for (self.shared_objects.items) |index| {
+ for (shared_objects) |index| {
const shared_object = self.file(index).?.shared_object;
- try writer.print("shared_object({d}) : ", .{index});
- try writer.print("{}", .{shared_object.path});
- try writer.print(" : needed({})", .{shared_object.needed});
+ try writer.print("shared_object({d}) : {} : needed({})", .{
+ index, shared_object.path, shared_object.needed,
+ });
if (!shared_object.alive) try writer.writeAll(" : [*]");
try writer.writeByte('\n');
try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
@@ -5204,10 +5220,7 @@ pub fn preadAllAlloc(allocator: Allocator, handle: fs.File, offset: u64, size: u
}
/// Binary search
-pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
- if (!@hasDecl(@TypeOf(predicate), "predicate"))
- @compileError("Predicate is required to define fn predicate(@This(), T) bool");
-
+pub fn bsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
var min: usize = 0;
var max: usize = haystack.len;
while (min < max) {
@@ -5223,10 +5236,7 @@ pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytyp
}
/// Linear search
-pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
- if (!@hasDecl(@TypeOf(predicate), "predicate"))
- @compileError("Predicate is required to define fn predicate(@This(), T) bool");
-
+pub fn lsearch(comptime T: type, haystack: []const T, predicate: anytype) usize {
var i: usize = 0;
while (i < haystack.len) : (i += 1) {
if (predicate.predicate(haystack[i])) break;
@@ -5569,6 +5579,11 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
}
}
+pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 {
+ const slice = strtab[off..];
+ return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
+}
+
const std = @import("std");
const build_options = @import("build_options");
const builtin = @import("builtin");
@@ -5581,8 +5596,9 @@ const state_log = std.log.scoped(.link_state);
const math = std.math;
const mem = std.mem;
const Allocator = std.mem.Allocator;
-const Cache = std.Build.Cache;
const Hash = std.hash.Wyhash;
+const Path = std.Build.Cache.Path;
+const Stat = std.Build.Cache.File.Stat;
const codegen = @import("../codegen.zig");
const dev = @import("../dev.zig");
@@ -5601,10 +5617,10 @@ const Merge = @import("Elf/Merge.zig");
const Air = @import("../Air.zig");
const Archive = @import("Elf/Archive.zig");
const AtomList = @import("Elf/AtomList.zig");
-const Path = Cache.Path;
const Compilation = @import("../Compilation.zig");
const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
const CopyRelSection = synthetic_sections.CopyRelSection;
+const Diags = @import("../link.zig").Diags;
const DynamicSection = synthetic_sections.DynamicSection;
const DynsymSection = synthetic_sections.DynsymSection;
const Dwarf = @import("Dwarf.zig");
src/link/MachO.zig
@@ -396,14 +396,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
}
for (positionals.items) |obj| {
- self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err| switch (err) {
- error.UnknownFileType => try diags.reportParseError(obj.path, "unknown file type for an input file", .{}),
- else => |e| try diags.reportParseError(
- obj.path,
- "unexpected error: reading input file failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ self.classifyInputFile(obj.path, .{ .path = obj.path }, obj.must_link) catch |err|
+ diags.addParseError(obj.path, "failed to read input file: {s}", .{@errorName(err)});
}
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
};
for (system_libs.items) |lib| {
- self.classifyInputFile(lib.path, lib, false) catch |err| switch (err) {
- error.UnknownFileType => try diags.reportParseError(lib.path, "unknown file type for an input file", .{}),
- else => |e| try diags.reportParseError(
- lib.path,
- "unexpected error: parsing input file failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ self.classifyInputFile(lib.path, lib, false) catch |err|
+ diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});
}
// Finally, link against compiler_rt.
@@ -460,14 +448,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
break :blk null;
};
if (compiler_rt_path) |path| {
- self.classifyInputFile(path, .{ .path = path }, false) catch |err| switch (err) {
- error.UnknownFileType => try diags.reportParseError(path, "unknown file type for an input file", .{}),
- else => |e| try diags.reportParseError(
- path,
- "unexpected error: parsing input file failed with error {s}",
- .{@errorName(e)},
- ),
- };
+ self.classifyInputFile(path, .{ .path = path }, false) catch |err|
+ diags.addParseError(path, "failed to parse input file: {s}", .{@errorName(err)});
}
try self.parseInputFiles();
@@ -796,7 +778,7 @@ pub fn resolveLibSystem(
if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
}
- try diags.reportMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
+ diags.addMissingLibraryError(checked_paths.items, "unable to find libSystem system library", .{});
return error.MissingLibSystem;
}
@@ -847,10 +829,7 @@ fn parseFatFile(self: *MachO, file: std.fs.File, path: Path) !?fat.Arch {
for (fat_archs) |arch| {
if (arch.tag == cpu_arch) return arch;
}
- try diags.reportParseError(path, "missing arch in universal file: expected {s}", .{
- @tagName(cpu_arch),
- });
- return error.MissingCpuArch;
+ return diags.failParse(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
}
pub fn readMachHeader(file: std.fs.File, offset: usize) !macho.mach_header_64 {
src/Compilation.zig
@@ -1002,6 +1002,7 @@ const CacheUse = union(CacheMode) {
pub const LinkObject = struct {
path: Path,
must_link: bool = false,
+ needed: bool = false,
// When the library is passed via a positional argument, it will be
// added as a full path. If it's `-l<lib>`, then just the basename.
//
@@ -2561,6 +2562,7 @@ fn addNonIncrementalStuffToCacheManifest(
for (comp.objects) |obj| {
_ = try man.addFilePath(obj.path, null);
man.hash.add(obj.must_link);
+ man.hash.add(obj.needed);
man.hash.add(obj.loption);
}
src/link.zig
@@ -207,23 +207,19 @@ pub const Diags = struct {
pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
@branchHint(.cold);
const gpa = diags.gpa;
+ const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
diags.mutex.lock();
defer diags.mutex.unlock();
- diags.msgs.ensureUnusedCapacity(gpa, 1) catch |err| switch (err) {
- error.OutOfMemory => {
- diags.flags.alloc_failure_occurred = true;
- return;
- },
- };
- const err_msg: Msg = .{
- .msg = std.fmt.allocPrint(gpa, format, args) catch |err| switch (err) {
- error.OutOfMemory => {
- diags.flags.alloc_failure_occurred = true;
- return;
- },
- },
+ addErrorLockedFallible(diags, eu_main_msg) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailureLocked(),
};
- diags.msgs.appendAssumeCapacity(err_msg);
+ }
+
+ fn addErrorLockedFallible(diags: *Diags, eu_main_msg: Allocator.Error![]u8) Allocator.Error!void {
+ const gpa = diags.gpa;
+ const main_msg = try eu_main_msg;
+ errdefer gpa.free(main_msg);
+ try diags.msgs.append(gpa, .{ .msg = main_msg });
}
pub fn addErrorWithNotes(diags: *Diags, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
@@ -242,7 +238,7 @@ pub const Diags = struct {
const err = diags.msgs.addOneAssumeCapacity();
err.* = .{
.msg = undefined,
- .notes = try gpa.alloc(Diags.Msg, note_count),
+ .notes = try gpa.alloc(Msg, note_count),
};
return .{
.diags = diags,
@@ -250,34 +246,93 @@ pub const Diags = struct {
};
}
- pub fn reportMissingLibraryError(
+ pub fn addMissingLibraryError(
diags: *Diags,
checked_paths: []const []const u8,
comptime format: []const u8,
args: anytype,
- ) error{OutOfMemory}!void {
+ ) void {
@branchHint(.cold);
- var err = try diags.addErrorWithNotes(checked_paths.len);
- try err.addMsg(format, args);
- for (checked_paths) |path| {
- try err.addNote("tried {s}", .{path});
+ const gpa = diags.gpa;
+ const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
+ diags.mutex.lock();
+ defer diags.mutex.unlock();
+ addMissingLibraryErrorLockedFallible(diags, checked_paths, eu_main_msg) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailureLocked(),
+ };
+ }
+
+ fn addMissingLibraryErrorLockedFallible(
+ diags: *Diags,
+ checked_paths: []const []const u8,
+ eu_main_msg: Allocator.Error![]u8,
+ ) Allocator.Error!void {
+ const gpa = diags.gpa;
+ const main_msg = try eu_main_msg;
+ errdefer gpa.free(main_msg);
+ try diags.msgs.ensureUnusedCapacity(gpa, 1);
+ const notes = try gpa.alloc(Msg, checked_paths.len);
+ errdefer gpa.free(notes);
+ for (checked_paths, notes) |path, *note| {
+ note.* = .{ .msg = try std.fmt.allocPrint(gpa, "tried {s}", .{path}) };
}
+ diags.msgs.appendAssumeCapacity(.{
+ .msg = main_msg,
+ .notes = notes,
+ });
+ }
+
+ pub fn addParseError(
+ diags: *Diags,
+ path: Path,
+ comptime format: []const u8,
+ args: anytype,
+ ) void {
+ @branchHint(.cold);
+ const gpa = diags.gpa;
+ const eu_main_msg = std.fmt.allocPrint(gpa, format, args);
+ diags.mutex.lock();
+ defer diags.mutex.unlock();
+ addParseErrorLockedFallible(diags, path, eu_main_msg) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailureLocked(),
+ };
}
- pub fn reportParseError(
+ fn addParseErrorLockedFallible(diags: *Diags, path: Path, m: Allocator.Error![]u8) Allocator.Error!void {
+ const gpa = diags.gpa;
+ const main_msg = try m;
+ errdefer gpa.free(main_msg);
+ try diags.msgs.ensureUnusedCapacity(gpa, 1);
+ const note = try std.fmt.allocPrint(gpa, "while parsing {}", .{path});
+ errdefer gpa.free(note);
+ const notes = try gpa.create([1]Msg);
+ errdefer gpa.destroy(notes);
+ notes.* = .{.{ .msg = note }};
+ diags.msgs.appendAssumeCapacity(.{
+ .msg = main_msg,
+ .notes = notes,
+ });
+ }
+
+ pub fn failParse(
diags: *Diags,
path: Path,
comptime format: []const u8,
args: anytype,
- ) error{OutOfMemory}!void {
+ ) error{LinkFailure} {
@branchHint(.cold);
- var err = try diags.addErrorWithNotes(1);
- try err.addMsg(format, args);
- try err.addNote("while parsing {}", .{path});
+ addParseError(diags, path, format, args);
+ return error.LinkFailure;
}
pub fn setAllocFailure(diags: *Diags) void {
@branchHint(.cold);
+ diags.mutex.lock();
+ defer diags.mutex.unlock();
+ setAllocFailureLocked(diags);
+ }
+
+ fn setAllocFailureLocked(diags: *Diags) void {
log.debug("memory allocation failure", .{});
diags.flags.alloc_failure_occurred = true;
}
@@ -727,7 +782,8 @@ pub const File = struct {
FailedToEmit,
FileSystem,
FilesOpenedWithWrongFlags,
- /// Indicates an error will be present in `Compilation.link_errors`.
+ /// Deprecated. Use `LinkFailure` instead.
+ /// Formerly used to indicate an error will be present in `Compilation.link_errors`.
FlushFailure,
/// Indicates an error will be present in `Compilation.link_errors`.
LinkFailure,