authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-09 14:23:31-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-09 14:23:31-08:00
log7320b24e0ea768cf8dffaaeaa058db8e9134b444
tree66b14e8b17373b4578529f30540ffc6414668e1f
parentacca16c8cee4529bcb11c150c2c99b7de32ce21f
parent3cd646869b1791b8833134294d3f415cb6fddcf7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #18486 from castholm/undefined-version

Add support for `--(no-)undefined-version`

9 files changed, 100 insertions(+), 7 deletions(-)

lib/std/Build/Step/Compile.zig+6
......@@ -110,6 +110,9 @@ linker_dynamicbase: bool = true,
110110
111111linker_allow_shlib_undefined: ?bool = null,
112112
113/// Allow version scripts to refer to undefined symbols.
114linker_allow_undefined_version: ?bool = null,
115
113116/// Permit read-only relocations in read-only segments. Disallowed by default.
114117link_z_notext: bool = false,
115118
......@@ -1451,6 +1454,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
14511454 try zig_args.append("--version-script");
14521455 try zig_args.append(version_script.getPath(b));
14531456 }
1457 if (self.linker_allow_undefined_version) |x| {
1458 try zig_args.append(if (x) "--undefined-version" else "--no-undefined-version");
1459 }
14541460
14551461 if (self.kind == .@"test") {
14561462 if (self.exec_cmd_args) |exec_cmd_args| {
src/Compilation.zig+5-2
......@@ -1033,6 +1033,7 @@ pub const CreateOptions = struct {
10331033 link_emit_relocs: bool = false,
10341034 linker_script: ?[]const u8 = null,
10351035 version_script: ?[]const u8 = null,
1036 linker_allow_undefined_version: bool = false,
10361037 soname: ?[]const u8 = null,
10371038 linker_gc_sections: ?bool = null,
10381039 linker_allow_shlib_undefined: ?bool = null,
......@@ -1572,6 +1573,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
15721573 .stack_size = options.stack_size,
15731574 .image_base = options.image_base,
15741575 .version_script = options.version_script,
1576 .allow_undefined_version = options.linker_allow_undefined_version,
15751577 .gc_sections = options.linker_gc_sections,
15761578 .emit_relocs = options.link_emit_relocs,
15771579 .soname = options.soname,
......@@ -2458,7 +2460,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
24582460/// to remind the programmer to update multiple related pieces of code that
24592461/// are in different locations. Bump this number when adding or deleting
24602462/// anything from the link cache manifest.
2461pub const link_hash_implementation_version = 10;
2463pub const link_hash_implementation_version = 11;
24622464
24632465fn addNonIncrementalStuffToCacheManifest(
24642466 comp: *Compilation,
......@@ -2467,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest(
24672469) !void {
24682470 const gpa = comp.gpa;
24692471
2470 comptime assert(link_hash_implementation_version == 10);
2472 comptime assert(link_hash_implementation_version == 11);
24712473
24722474 if (comp.module) |mod| {
24732475 const main_zig_file = try mod.main_mod.root.joinString(arena, mod.main_mod.root_src_path);
......@@ -2541,6 +2543,7 @@ fn addNonIncrementalStuffToCacheManifest(
25412543
25422544 try man.addOptionalFile(opts.linker_script);
25432545 try man.addOptionalFile(opts.version_script);
2546 man.hash.add(opts.allow_undefined_version);
25442547
25452548 man.hash.addOptional(opts.stack_size);
25462549 man.hash.addOptional(opts.image_base);
src/link.zig+1
......@@ -113,6 +113,7 @@ pub const File = struct {
113113 minor_subsystem_version: ?u16,
114114 gc_sections: ?bool,
115115 allow_shlib_undefined: ?bool,
116 allow_undefined_version: bool,
116117 subsystem: ?std.Target.SubSystem,
117118 linker_script: ?[]const u8,
118119 version_script: ?[]const u8,
src/link/Coff/lld.zig+1-1
......@@ -70,7 +70,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)
7070 man = comp.cache_parent.obtain();
7171 self.base.releaseLock();
7272
73 comptime assert(Compilation.link_hash_implementation_version == 10);
73 comptime assert(Compilation.link_hash_implementation_version == 11);
7474
7575 for (comp.objects) |obj| {
7676 _ = try man.addFile(obj.path, null);
src/link/Elf.zig+9-1
......@@ -22,6 +22,7 @@ soname: ?[]const u8,
2222bind_global_refs_locally: bool,
2323linker_script: ?[]const u8,
2424version_script: ?[]const u8,
25allow_undefined_version: bool,
2526print_icf_sections: bool,
2627print_map: bool,
2728entry_name: ?[]const u8,
......@@ -325,6 +326,7 @@ pub fn createEmpty(
325326 .bind_global_refs_locally = options.bind_global_refs_locally,
326327 .linker_script = options.linker_script,
327328 .version_script = options.version_script,
329 .allow_undefined_version = options.allow_undefined_version,
328330 .print_icf_sections = options.print_icf_sections,
329331 .print_map = options.print_map,
330332 };
......@@ -2410,10 +2412,11 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
24102412 // We are about to obtain this lock, so here we give other processes a chance first.
24112413 self.base.releaseLock();
24122414
2413 comptime assert(Compilation.link_hash_implementation_version == 10);
2415 comptime assert(Compilation.link_hash_implementation_version == 11);
24142416
24152417 try man.addOptionalFile(self.linker_script);
24162418 try man.addOptionalFile(self.version_script);
2419 man.hash.add(self.allow_undefined_version);
24172420 for (comp.objects) |obj| {
24182421 _ = try man.addFile(obj.path, null);
24192422 man.hash.add(obj.must_link);
......@@ -2789,6 +2792,11 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
27892792 try argv.append("-version-script");
27902793 try argv.append(version_script);
27912794 }
2795 if (self.allow_undefined_version) {
2796 try argv.append("--undefined-version");
2797 } else {
2798 try argv.append("--no-undefined-version");
2799 }
27922800 }
27932801
27942802 // Positional arguments to the linker such as object files.
src/link/MachO/zld.zig+1-1
......@@ -55,7 +55,7 @@ pub fn linkWithZld(
5555 // We are about to obtain this lock, so here we give other processes a chance first.
5656 macho_file.base.releaseLock();
5757
58 comptime assert(Compilation.link_hash_implementation_version == 10);
58 comptime assert(Compilation.link_hash_implementation_version == 11);
5959
6060 for (objects) |obj| {
6161 _ = try man.addFile(obj.path, null);
src/link/Wasm.zig+2-2
......@@ -3547,7 +3547,7 @@ fn linkWithZld(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) lin
35473547 // We are about to obtain this lock, so here we give other processes a chance first.
35483548 wasm.base.releaseLock();
35493549
3550 comptime assert(Compilation.link_hash_implementation_version == 10);
3550 comptime assert(Compilation.link_hash_implementation_version == 11);
35513551
35523552 for (objects) |obj| {
35533553 _ = try man.addFile(obj.path, null);
......@@ -4633,7 +4633,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo
46334633 // We are about to obtain this lock, so here we give other processes a chance first.
46344634 wasm.base.releaseLock();
46354635
4636 comptime assert(Compilation.link_hash_implementation_version == 10);
4636 comptime assert(Compilation.link_hash_implementation_version == 11);
46374637
46384638 for (comp.objects) |obj| {
46394639 _ = try man.addFile(obj.path, null);
src/main.zig+12
......@@ -500,6 +500,8 @@ const usage_build_generic =
500500 \\Global Link Options:
501501 \\ -T[script], --script [script] Use a custom linker script
502502 \\ --version-script [path] Provide a version .map file
503 \\ --undefined-version Allow version scripts to refer to undefined symbols
504 \\ --no-undefined-version (default) Disallow version scripts from referring to undefined symbols
503505 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
504506 \\ --sysroot [path] Set the system root directory (usually /)
505507 \\ --version [ver] Dynamic library semver
......@@ -826,6 +828,7 @@ fn buildOutputType(
826828 var want_compiler_rt: ?bool = null;
827829 var linker_script: ?[]const u8 = null;
828830 var version_script: ?[]const u8 = null;
831 var linker_allow_undefined_version: bool = false;
829832 var disable_c_depfile = false;
830833 var linker_sort_section: ?link.File.Elf.SortSection = null;
831834 var linker_gc_sections: ?bool = null;
......@@ -1200,6 +1203,10 @@ fn buildOutputType(
12001203 linker_script = args_iter.nextOrFatal();
12011204 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
12021205 version_script = args_iter.nextOrFatal();
1206 } else if (mem.eql(u8, arg, "--undefined-version")) {
1207 linker_allow_undefined_version = true;
1208 } else if (mem.eql(u8, arg, "--no-undefined-version")) {
1209 linker_allow_undefined_version = false;
12031210 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
12041211 // We don't know whether this library is part of libc
12051212 // or libc++ until we resolve the target, so we append
......@@ -2153,6 +2160,10 @@ fn buildOutputType(
21532160 create_module.opts.rdynamic = true;
21542161 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
21552162 version_script = linker_args_it.nextOrFatal();
2163 } else if (mem.eql(u8, arg, "--undefined-version")) {
2164 linker_allow_undefined_version = true;
2165 } else if (mem.eql(u8, arg, "--no-undefined-version")) {
2166 linker_allow_undefined_version = false;
21562167 } else if (mem.eql(u8, arg, "-O")) {
21572168 linker_optimization = linker_args_it.nextOrFatal();
21582169 } else if (mem.startsWith(u8, arg, "-O")) {
......@@ -3166,6 +3177,7 @@ fn buildOutputType(
31663177 .hash_style = hash_style,
31673178 .linker_script = linker_script,
31683179 .version_script = version_script,
3180 .linker_allow_undefined_version = linker_allow_undefined_version,
31693181 .disable_c_depfile = disable_c_depfile,
31703182 .soname = resolved_soname,
31713183 .linker_sort_section = linker_sort_section,
test/link/elf.zig+63
......@@ -94,6 +94,8 @@ pub fn testAll(b: *Build) *Step {
9494 elf_step.dependOn(testLinkOrder(b, .{ .target = glibc_target }));
9595 elf_step.dependOn(testLdScript(b, .{ .target = glibc_target }));
9696 elf_step.dependOn(testLdScriptPathError(b, .{ .target = glibc_target }));
97 elf_step.dependOn(testLdScriptAllowUndefinedVersion(b, .{ .target = glibc_target, .use_lld = true }));
98 elf_step.dependOn(testLdScriptDisallowUndefinedVersion(b, .{ .target = glibc_target, .use_lld = true }));
9799 elf_step.dependOn(testMismatchedCpuArchitectureError(b, .{ .target = glibc_target }));
98100 // https://github.com/ziglang/zig/issues/17451
99101 // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = glibc_target }));
......@@ -2008,6 +2010,67 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
20082010 return test_step;
20092011}
20102012
2013fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
2014 const test_step = addTestStep(b, "ld-script-allow-undefined-version", opts);
2015
2016 const so = addSharedLibrary(b, opts, .{
2017 .name = "add",
2018 .zig_source_bytes =
2019 \\export fn add(a: i32, b: i32) i32 {
2020 \\ return a + b;
2021 \\}
2022 ,
2023 });
2024 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
2025 so.setLinkerScript(ld);
2026 so.linker_allow_undefined_version = true;
2027
2028 const exe = addExecutable(b, opts, .{
2029 .name = "main",
2030 .zig_source_bytes =
2031 \\const std = @import("std");
2032 \\extern fn add(a: i32, b: i32) i32;
2033 \\pub fn main() void {
2034 \\ std.debug.print("{d}\n", .{add(1, 2)});
2035 \\}
2036 ,
2037 });
2038 exe.linkLibrary(so);
2039 exe.linkLibC();
2040
2041 const run = addRunArtifact(exe);
2042 run.expectStdErrEqual("3\n");
2043 test_step.dependOn(&run.step);
2044
2045 return test_step;
2046}
2047
2048fn testLdScriptDisallowUndefinedVersion(b: *Build, opts: Options) *Step {
2049 const test_step = addTestStep(b, "ld-script-disallow-undefined-version", opts);
2050
2051 const so = addSharedLibrary(b, opts, .{
2052 .name = "add",
2053 .zig_source_bytes =
2054 \\export fn add(a: i32, b: i32) i32 {
2055 \\ return a + b;
2056 \\}
2057 ,
2058 });
2059 const ld = b.addWriteFiles().add("add.ld", "VERSION { ADD_1.0 { global: add; sub; local: *; }; }");
2060 so.setLinkerScript(ld);
2061 so.linker_allow_undefined_version = false;
2062
2063 expectLinkErrors(
2064 so,
2065 test_step,
2066 .{
2067 .contains = "error: ld.lld: version script assignment of 'ADD_1.0' to symbol 'sub' failed: symbol not defined",
2068 },
2069 );
2070
2071 return test_step;
2072}
2073
20112074fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
20122075 const test_step = addTestStep(b, "mismatched-cpu-architecture-error", opts);
20132076