Commit 4706ec81d4
Changed files (6)
lib
compiler
std
Build
Step
test
link
lib/compiler/build_runner.zig
@@ -280,6 +280,10 @@ pub fn main() !void {
builder.enable_darling = true;
} else if (mem.eql(u8, arg, "-fno-darling")) {
builder.enable_darling = false;
+ } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
+ graph.allow_so_scripts = true;
+ } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
+ graph.allow_so_scripts = false;
} else if (mem.eql(u8, arg, "-freference-trace")) {
builder.reference_trace = 256;
} else if (mem.startsWith(u8, arg, "-freference-trace=")) {
@@ -1341,6 +1345,8 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
\\Advanced Options:
\\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
\\ -fno-reference-trace Disable reference trace
+ \\ -fallow-so-scripts Allows .so files to be GNU ld scripts
+ \\ -fno-allow-so-scripts (default) .so files must be ELF files
\\ --build-file [file] Override path to build.zig
\\ --cache-dir [path] Override path to local Zig cache directory
\\ --global-cache-dir [path] Override path to global Zig cache directory
lib/std/Build/Step/Compile.zig
@@ -186,6 +186,15 @@ want_lto: ?bool = null,
use_llvm: ?bool,
use_lld: ?bool,
+/// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI
+/// flags, overriding the global user setting provided to the `zig build`
+/// command.
+///
+/// The compiler defaults this value to off so that users whose system shared
+/// libraries are all ELF files don't have to pay the cost of checking every
+/// file to find out if it is a text file instead.
+allow_so_scripts: ?bool = null,
+
/// This is an advanced setting that can change the intent of this Compile step.
/// If this value is non-null, it means that this Compile step exists to
/// check for compile errors and return *success* if they match, and failure
@@ -1036,6 +1045,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
if (b.reference_trace) |some| {
try zig_args.append(try std.fmt.allocPrint(arena, "-freference-trace={d}", .{some}));
}
+ try addFlag(&zig_args, "allow-so-scripts", compile.allow_so_scripts orelse b.graph.allow_so_scripts);
try addFlag(&zig_args, "llvm", compile.use_llvm);
try addFlag(&zig_args, "lld", compile.use_lld);
lib/std/Build.zig
@@ -123,6 +123,7 @@ pub const Graph = struct {
incremental: ?bool = null,
random_seed: u32 = 0,
dependency_cache: InitializedDepMap = .empty,
+ allow_so_scripts: ?bool = null,
};
const AvailableDeps = []const struct { []const u8, []const u8 };
src/link/Elf.zig
@@ -1337,6 +1337,12 @@ pub fn parseInputReportingFailure(self: *Elf, path: Path, needed: bool, must_lin
.needed = needed,
}, &self.shared_objects, &self.files, target) catch |err| switch (err) {
error.LinkFailure => return, // already reported
+ error.BadMagic, error.UnexpectedEndOfFile => {
+ var notes = diags.addErrorWithNotes(2) catch return diags.setAllocFailure();
+ notes.addMsg("failed to parse shared object: {s}", .{@errorName(err)}) catch return diags.setAllocFailure();
+ notes.addNote("while parsing {}", .{path}) catch return diags.setAllocFailure();
+ notes.addNote("{s}", .{@as([]const u8, "the file may be a GNU ld script, in which case it is not an ELF file but a text file referencing other libraries to link. In this case, avoid depending on the library, convince your system administrators to refrain from using this kind of file, or pass -fallow-so-scripts to force the compiler to check every shared library in case it is an ld script.")}) catch return diags.setAllocFailure();
+ },
else => |e| diags.addParseError(path, "failed to parse shared object: {s}", .{@errorName(e)}),
},
.static_library => parseArchive(self, path, must_link) catch |err| switch (err) {
src/main.zig
@@ -555,6 +555,8 @@ const usage_build_generic =
\\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
\\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
\\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries
+ \\ -fallow-so-scripts Allows .so files to be GNU ld scripts
+ \\ -fno-allow-so-scripts (default) .so files must be ELF files
\\ --build-id[=style] At a minor link-time expense, coordinates stripped binaries
\\ fast, uuid, sha1, md5 with debug symbols via a '.note.gnu.build-id' section
\\ 0x[hexstring] Maximum 32 bytes
@@ -1003,6 +1005,7 @@ fn buildOutputType(
.libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
.link_objects = .{},
.native_system_include_paths = &.{},
+ .allow_so_scripts = false,
};
// before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables
@@ -1573,6 +1576,10 @@ fn buildOutputType(
linker_allow_shlib_undefined = true;
} else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
linker_allow_shlib_undefined = false;
+ } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
+ create_module.allow_so_scripts = true;
+ } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
+ create_module.allow_so_scripts = false;
} else if (mem.eql(u8, arg, "-z")) {
const z_arg = args_iter.nextOrFatal();
if (mem.eql(u8, z_arg, "nodelete")) {
@@ -3679,6 +3686,7 @@ const CreateModule = struct {
each_lib_rpath: ?bool,
libc_paths_file: ?[]const u8,
link_objects: std.ArrayListUnmanaged(Compilation.LinkObject),
+ allow_so_scripts: bool,
};
fn createModule(
@@ -6950,7 +6958,7 @@ fn accessLibPath(
// In the case of .so files, they might actually be "linker scripts"
// that contain references to other libraries.
- if (target.ofmt == .elf and mem.endsWith(u8, test_path.items, ".so")) {
+ if (create_module.allow_so_scripts and target.ofmt == .elf and mem.endsWith(u8, test_path.items, ".so")) {
var file = fs.cwd().openFile(test_path.items, .{}) catch |err| switch (err) {
error.FileNotFound => break :main_check,
else => |e| fatal("unable to search for {s} library '{s}': {s}", .{
test/link/elf.zig
@@ -2145,6 +2145,7 @@ fn testLdScript(b: *Build, opts: Options) *Step {
exe.addLibraryPath(dso.getEmittedBinDirectory());
exe.addRPath(dso.getEmittedBinDirectory());
exe.linkLibC();
+ exe.allow_so_scripts = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2164,6 +2165,7 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
exe.linkSystemLibrary2("a", .{});
exe.addLibraryPath(scripts.getDirectory());
exe.linkLibC();
+ exe.allow_so_scripts = true;
// TODO: A future enhancement could make this error message also mention
// the file that references the missing library.
@@ -2201,6 +2203,7 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
});
exe.linkLibrary(so);
exe.linkLibC();
+ exe.allow_so_scripts = true;
const run = addRunArtifact(exe);
run.expectStdErrEqual("3\n");
@@ -2223,6 +2226,7 @@ fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {
const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
so.setLinkerScript(ld);
so.linker_allow_undefined_version = false;
+ so.allow_so_scripts = true;
expectLinkErrors(
so,