| author | |
| committer | |
| log | 7320b24e0ea768cf8dffaaeaa058db8e9134b444 |
| tree | 66b14e8b17373b4578529f30540ffc6414668e1f |
| parent | acca16c8cee4529bcb11c150c2c99b7de32ce21f |
| parent | 3cd646869b1791b8833134294d3f415cb6fddcf7 |
| signature |
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, |
| 110 | 110 | |
| 111 | 111 | linker_allow_shlib_undefined: ?bool = null, |
| 112 | 112 | |
| 113 | /// Allow version scripts to refer to undefined symbols. | |
| 114 | linker_allow_undefined_version: ?bool = null, | |
| 115 | ||
| 113 | 116 | /// Permit read-only relocations in read-only segments. Disallowed by default. |
| 114 | 117 | link_z_notext: bool = false, |
| 115 | 118 | |
| ... | ... | @@ -1451,6 +1454,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1451 | 1454 | try zig_args.append("--version-script"); |
| 1452 | 1455 | try zig_args.append(version_script.getPath(b)); |
| 1453 | 1456 | } |
| 1457 | if (self.linker_allow_undefined_version) |x| { | |
| 1458 | try zig_args.append(if (x) "--undefined-version" else "--no-undefined-version"); | |
| 1459 | } | |
| 1454 | 1460 | |
| 1455 | 1461 | if (self.kind == .@"test") { |
| 1456 | 1462 | if (self.exec_cmd_args) |exec_cmd_args| { |
src/Compilation.zig+5-2| ... | ... | @@ -1033,6 +1033,7 @@ pub const CreateOptions = struct { |
| 1033 | 1033 | link_emit_relocs: bool = false, |
| 1034 | 1034 | linker_script: ?[]const u8 = null, |
| 1035 | 1035 | version_script: ?[]const u8 = null, |
| 1036 | linker_allow_undefined_version: bool = false, | |
| 1036 | 1037 | soname: ?[]const u8 = null, |
| 1037 | 1038 | linker_gc_sections: ?bool = null, |
| 1038 | 1039 | linker_allow_shlib_undefined: ?bool = null, |
| ... | ... | @@ -1572,6 +1573,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1572 | 1573 | .stack_size = options.stack_size, |
| 1573 | 1574 | .image_base = options.image_base, |
| 1574 | 1575 | .version_script = options.version_script, |
| 1576 | .allow_undefined_version = options.linker_allow_undefined_version, | |
| 1575 | 1577 | .gc_sections = options.linker_gc_sections, |
| 1576 | 1578 | .emit_relocs = options.link_emit_relocs, |
| 1577 | 1579 | .soname = options.soname, |
| ... | ... | @@ -2458,7 +2460,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo |
| 2458 | 2460 | /// to remind the programmer to update multiple related pieces of code that |
| 2459 | 2461 | /// are in different locations. Bump this number when adding or deleting |
| 2460 | 2462 | /// anything from the link cache manifest. |
| 2461 | pub const link_hash_implementation_version = 10; | |
| 2463 | pub const link_hash_implementation_version = 11; | |
| 2462 | 2464 | |
| 2463 | 2465 | fn addNonIncrementalStuffToCacheManifest( |
| 2464 | 2466 | comp: *Compilation, |
| ... | ... | @@ -2467,7 +2469,7 @@ fn addNonIncrementalStuffToCacheManifest( |
| 2467 | 2469 | ) !void { |
| 2468 | 2470 | const gpa = comp.gpa; |
| 2469 | 2471 | |
| 2470 | comptime assert(link_hash_implementation_version == 10); | |
| 2472 | comptime assert(link_hash_implementation_version == 11); | |
| 2471 | 2473 | |
| 2472 | 2474 | if (comp.module) |mod| { |
| 2473 | 2475 | const main_zig_file = try mod.main_mod.root.joinString(arena, mod.main_mod.root_src_path); |
| ... | ... | @@ -2541,6 +2543,7 @@ fn addNonIncrementalStuffToCacheManifest( |
| 2541 | 2543 | |
| 2542 | 2544 | try man.addOptionalFile(opts.linker_script); |
| 2543 | 2545 | try man.addOptionalFile(opts.version_script); |
| 2546 | man.hash.add(opts.allow_undefined_version); | |
| 2544 | 2547 | |
| 2545 | 2548 | man.hash.addOptional(opts.stack_size); |
| 2546 | 2549 | man.hash.addOptional(opts.image_base); |
src/link.zig+1| ... | ... | @@ -113,6 +113,7 @@ pub const File = struct { |
| 113 | 113 | minor_subsystem_version: ?u16, |
| 114 | 114 | gc_sections: ?bool, |
| 115 | 115 | allow_shlib_undefined: ?bool, |
| 116 | allow_undefined_version: bool, | |
| 116 | 117 | subsystem: ?std.Target.SubSystem, |
| 117 | 118 | linker_script: ?[]const u8, |
| 118 | 119 | 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) |
| 70 | 70 | man = comp.cache_parent.obtain(); |
| 71 | 71 | self.base.releaseLock(); |
| 72 | 72 | |
| 73 | comptime assert(Compilation.link_hash_implementation_version == 10); | |
| 73 | comptime assert(Compilation.link_hash_implementation_version == 11); | |
| 74 | 74 | |
| 75 | 75 | for (comp.objects) |obj| { |
| 76 | 76 | _ = try man.addFile(obj.path, null); |
src/link/Elf.zig+9-1| ... | ... | @@ -22,6 +22,7 @@ soname: ?[]const u8, |
| 22 | 22 | bind_global_refs_locally: bool, |
| 23 | 23 | linker_script: ?[]const u8, |
| 24 | 24 | version_script: ?[]const u8, |
| 25 | allow_undefined_version: bool, | |
| 25 | 26 | print_icf_sections: bool, |
| 26 | 27 | print_map: bool, |
| 27 | 28 | entry_name: ?[]const u8, |
| ... | ... | @@ -325,6 +326,7 @@ pub fn createEmpty( |
| 325 | 326 | .bind_global_refs_locally = options.bind_global_refs_locally, |
| 326 | 327 | .linker_script = options.linker_script, |
| 327 | 328 | .version_script = options.version_script, |
| 329 | .allow_undefined_version = options.allow_undefined_version, | |
| 328 | 330 | .print_icf_sections = options.print_icf_sections, |
| 329 | 331 | .print_map = options.print_map, |
| 330 | 332 | }; |
| ... | ... | @@ -2410,10 +2412,11 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi |
| 2410 | 2412 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 2411 | 2413 | self.base.releaseLock(); |
| 2412 | 2414 | |
| 2413 | comptime assert(Compilation.link_hash_implementation_version == 10); | |
| 2415 | comptime assert(Compilation.link_hash_implementation_version == 11); | |
| 2414 | 2416 | |
| 2415 | 2417 | try man.addOptionalFile(self.linker_script); |
| 2416 | 2418 | try man.addOptionalFile(self.version_script); |
| 2419 | man.hash.add(self.allow_undefined_version); | |
| 2417 | 2420 | for (comp.objects) |obj| { |
| 2418 | 2421 | _ = try man.addFile(obj.path, null); |
| 2419 | 2422 | man.hash.add(obj.must_link); |
| ... | ... | @@ -2789,6 +2792,11 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi |
| 2789 | 2792 | try argv.append("-version-script"); |
| 2790 | 2793 | try argv.append(version_script); |
| 2791 | 2794 | } |
| 2795 | if (self.allow_undefined_version) { | |
| 2796 | try argv.append("--undefined-version"); | |
| 2797 | } else { | |
| 2798 | try argv.append("--no-undefined-version"); | |
| 2799 | } | |
| 2792 | 2800 | } |
| 2793 | 2801 | |
| 2794 | 2802 | // Positional arguments to the linker such as object files. |
src/link/MachO/zld.zig+1-1| ... | ... | @@ -55,7 +55,7 @@ pub fn linkWithZld( |
| 55 | 55 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 56 | 56 | macho_file.base.releaseLock(); |
| 57 | 57 | |
| 58 | comptime assert(Compilation.link_hash_implementation_version == 10); | |
| 58 | comptime assert(Compilation.link_hash_implementation_version == 11); | |
| 59 | 59 | |
| 60 | 60 | for (objects) |obj| { |
| 61 | 61 | _ = 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 |
| 3547 | 3547 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 3548 | 3548 | wasm.base.releaseLock(); |
| 3549 | 3549 | |
| 3550 | comptime assert(Compilation.link_hash_implementation_version == 10); | |
| 3550 | comptime assert(Compilation.link_hash_implementation_version == 11); | |
| 3551 | 3551 | |
| 3552 | 3552 | for (objects) |obj| { |
| 3553 | 3553 | _ = try man.addFile(obj.path, null); |
| ... | ... | @@ -4633,7 +4633,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo |
| 4633 | 4633 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 4634 | 4634 | wasm.base.releaseLock(); |
| 4635 | 4635 | |
| 4636 | comptime assert(Compilation.link_hash_implementation_version == 10); | |
| 4636 | comptime assert(Compilation.link_hash_implementation_version == 11); | |
| 4637 | 4637 | |
| 4638 | 4638 | for (comp.objects) |obj| { |
| 4639 | 4639 | _ = try man.addFile(obj.path, null); |
src/main.zig+12| ... | ... | @@ -500,6 +500,8 @@ const usage_build_generic = |
| 500 | 500 | \\Global Link Options: |
| 501 | 501 | \\ -T[script], --script [script] Use a custom linker script |
| 502 | 502 | \\ --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 | |
| 503 | 505 | \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) |
| 504 | 506 | \\ --sysroot [path] Set the system root directory (usually /) |
| 505 | 507 | \\ --version [ver] Dynamic library semver |
| ... | ... | @@ -826,6 +828,7 @@ fn buildOutputType( |
| 826 | 828 | var want_compiler_rt: ?bool = null; |
| 827 | 829 | var linker_script: ?[]const u8 = null; |
| 828 | 830 | var version_script: ?[]const u8 = null; |
| 831 | var linker_allow_undefined_version: bool = false; | |
| 829 | 832 | var disable_c_depfile = false; |
| 830 | 833 | var linker_sort_section: ?link.File.Elf.SortSection = null; |
| 831 | 834 | var linker_gc_sections: ?bool = null; |
| ... | ... | @@ -1200,6 +1203,10 @@ fn buildOutputType( |
| 1200 | 1203 | linker_script = args_iter.nextOrFatal(); |
| 1201 | 1204 | } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { |
| 1202 | 1205 | 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; | |
| 1203 | 1210 | } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) { |
| 1204 | 1211 | // We don't know whether this library is part of libc |
| 1205 | 1212 | // or libc++ until we resolve the target, so we append |
| ... | ... | @@ -2153,6 +2160,10 @@ fn buildOutputType( |
| 2153 | 2160 | create_module.opts.rdynamic = true; |
| 2154 | 2161 | } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { |
| 2155 | 2162 | 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; | |
| 2156 | 2167 | } else if (mem.eql(u8, arg, "-O")) { |
| 2157 | 2168 | linker_optimization = linker_args_it.nextOrFatal(); |
| 2158 | 2169 | } else if (mem.startsWith(u8, arg, "-O")) { |
| ... | ... | @@ -3166,6 +3177,7 @@ fn buildOutputType( |
| 3166 | 3177 | .hash_style = hash_style, |
| 3167 | 3178 | .linker_script = linker_script, |
| 3168 | 3179 | .version_script = version_script, |
| 3180 | .linker_allow_undefined_version = linker_allow_undefined_version, | |
| 3169 | 3181 | .disable_c_depfile = disable_c_depfile, |
| 3170 | 3182 | .soname = resolved_soname, |
| 3171 | 3183 | .linker_sort_section = linker_sort_section, |
test/link/elf.zig+63| ... | ... | @@ -94,6 +94,8 @@ pub fn testAll(b: *Build) *Step { |
| 94 | 94 | elf_step.dependOn(testLinkOrder(b, .{ .target = glibc_target })); |
| 95 | 95 | elf_step.dependOn(testLdScript(b, .{ .target = glibc_target })); |
| 96 | 96 | 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 })); | |
| 97 | 99 | elf_step.dependOn(testMismatchedCpuArchitectureError(b, .{ .target = glibc_target })); |
| 98 | 100 | // https://github.com/ziglang/zig/issues/17451 |
| 99 | 101 | // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = glibc_target })); |
| ... | ... | @@ -2008,6 +2010,67 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step { |
| 2008 | 2010 | return test_step; |
| 2009 | 2011 | } |
| 2010 | 2012 | |
| 2013 | fn 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 | ||
| 2048 | fn 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 | ||
| 2011 | 2074 | fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step { |
| 2012 | 2075 | const test_step = addTestStep(b, "mismatched-cpu-architecture-error", opts); |
| 2013 | 2076 |