Commit 336466c9df
Changed files (3)
src
link
src/link/Elf/Archive.zig
@@ -16,6 +16,15 @@ pub fn parse(
handle_index: File.HandleIndex,
) !Archive {
const handle = file_handles.items[handle_index];
+ var pos: usize = 0;
+ {
+ var magic_buffer: [elf.ARMAG.len]u8 = undefined;
+ const n = try handle.preadAll(&magic_buffer, pos);
+ if (n != magic_buffer.len) return error.BadMagic;
+ if (!mem.eql(u8, &magic_buffer, elf.ARMAG)) return error.BadMagic;
+ pos += magic_buffer.len;
+ }
+
const size = (try handle.stat()).size;
var objects: std.ArrayListUnmanaged(Object) = .empty;
@@ -24,17 +33,14 @@ pub fn parse(
var strtab: std.ArrayListUnmanaged(u8) = .empty;
defer strtab.deinit(gpa);
- var pos: usize = elf.ARMAG.len;
- while (true) {
- if (pos >= size) break;
- if (!mem.isAligned(pos, 2)) pos += 1;
+ while (pos < size) {
+ pos = mem.alignForward(usize, pos, 2);
- var hdr_buffer: [@sizeOf(elf.ar_hdr)]u8 = undefined;
+ var hdr: elf.ar_hdr = undefined;
{
- const amt = try handle.preadAll(&hdr_buffer, pos);
- if (amt != @sizeOf(elf.ar_hdr)) return error.InputOutput;
+ const n = try handle.preadAll(mem.asBytes(&hdr), pos);
+ if (n != @sizeOf(elf.ar_hdr)) return error.UnexpectedEndOfFile;
}
- const hdr = @as(*align(1) const elf.ar_hdr, @ptrCast(&hdr_buffer)).*;
pos += @sizeOf(elf.ar_hdr);
if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {
src/link/Elf.zig
@@ -1098,20 +1098,6 @@ fn dumpArgvInit(self: *Elf, arena: Allocator) !void {
}
}
-pub const ParseError = error{
- /// Indicates the error is already reported on `Compilation.link_diags`.
- LinkFailure,
-
- OutOfMemory,
- Overflow,
- InputOutput,
- EndOfStream,
- FileSystem,
- NotSupported,
- InvalidCharacter,
- UnknownFileType,
-} || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
-
pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {
const diags = &self.base.comp.link_diags;
const obj = link.openObject(path, false, false) catch |err| {
@@ -1130,7 +1116,7 @@ fn parseObjectReportingFailure(self: *Elf, obj: link.Input.Object) void {
};
}
-fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
+fn parseObject(self: *Elf, obj: link.Input.Object) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -1175,7 +1161,7 @@ fn parseArchive(
objects: *std.ArrayListUnmanaged(File.Index),
obj: link.Input.Object,
is_static_lib: bool,
-) ParseError!void {
+) !void {
const tracy = trace(@src());
defer tracy.end();
src/link.zig
@@ -1009,11 +1009,25 @@ pub const File = struct {
}
/// Opens a path as a static library and parses it into the linker.
- fn openLoadArchive(base: *File, path: Path) anyerror!void {
- const diags = &base.comp.link_diags;
- const input = try openArchiveInput(diags, path, false, false);
- errdefer input.archive.file.close();
- try loadInput(base, input);
+ /// If `query` is non-null, allows GNU ld scripts.
+ fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void {
+ if (opt_query) |query| {
+ const archive = try openObject(path, query.must_link, query.hidden);
+ errdefer archive.file.close();
+ loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
+ error.BadMagic, error.UnexpectedEndOfFile => {
+ if (base.tag != .elf) return err;
+ try loadGnuLdScript(base, path, query, archive.file);
+ archive.file.close();
+ return;
+ },
+ else => return err,
+ };
+ } else {
+ const archive = try openObject(path, false, false);
+ errdefer archive.file.close();
+ try loadInput(base, .{ .archive = archive });
+ }
}
/// Opens a path as a shared library and parses it into the linker.
@@ -1060,7 +1074,7 @@ pub const File = struct {
switch (Compilation.classifyFileExt(arg.path)) {
.shared_library => try openLoadDso(base, new_path, query),
.object => try openLoadObject(base, new_path),
- .static_library => try openLoadArchive(base, new_path),
+ .static_library => try openLoadArchive(base, new_path, query),
else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}),
}
} else {
@@ -1408,33 +1422,51 @@ pub const File = struct {
assert(mem.startsWith(u8, flag, "-l"));
const lib_name = flag["-l".len..];
switch (comp.config.link_mode) {
- .dynamic => d: {
- const path = Path.initCwd(
+ .dynamic => {
+ const dso_path = Path.initCwd(
std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{
crt_dir, target.libPrefix(), lib_name, target.dynamicLibSuffix(),
}) catch return diags.setAllocFailure(),
);
- base.openLoadDso(path, .{
+ base.openLoadDso(dso_path, .{
.preferred_mode = .dynamic,
.search_strategy = .paths_first,
}) catch |err| switch (err) {
- error.FileNotFound => break :d, // also try static
+ error.FileNotFound => {
+ // Also try static.
+ const archive_path = Path.initCwd(
+ std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{
+ crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),
+ }) catch return diags.setAllocFailure(),
+ );
+ base.openLoadArchive(archive_path, .{
+ .preferred_mode = .dynamic,
+ .search_strategy = .paths_first,
+ }) catch |archive_err| switch (archive_err) {
+ error.LinkFailure => return, // error reported via diags
+ else => |e| diags.addParseError(dso_path, "failed to parse archive {}: {s}", .{ archive_path, @errorName(e) }),
+ };
+ },
+ error.LinkFailure => return, // error reported via diags
+ else => |e| diags.addParseError(dso_path, "failed to parse shared library: {s}", .{@errorName(e)}),
+ };
+ },
+ .static => {
+ const path = Path.initCwd(
+ std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{
+ crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),
+ }) catch return diags.setAllocFailure(),
+ );
+ // glibc sometimes makes even archive files GNU ld scripts.
+ base.openLoadArchive(path, .{
+ .preferred_mode = .static,
+ .search_strategy = .no_fallback,
+ }) catch |err| switch (err) {
error.LinkFailure => return, // error reported via diags
- else => |e| diags.addParseError(path, "failed to parse shared library: {s}", .{@errorName(e)}),
+ else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
};
- continue;
},
- .static => {},
}
- const path = Path.initCwd(
- std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}{s}{s}", .{
- crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),
- }) catch return diags.setAllocFailure(),
- );
- base.openLoadArchive(path) catch |err| switch (err) {
- error.LinkFailure => return, // error reported via diags
- else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
- };
}
},
.load_object => |path| {
@@ -1444,7 +1476,7 @@ pub const File = struct {
};
},
.load_archive => |path| {
- base.openLoadArchive(path) catch |err| switch (err) {
+ base.openLoadArchive(path, null) catch |err| switch (err) {
error.LinkFailure => return, // error reported via link_diags
else => |e| comp.link_diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),
};