| author | |
| committer | |
| log | f87b443af1f654d3363ce6a1081bdf7932ae354c |
| tree | f4b242f4e9463026e1b53cab879fd21acbbb2e9a |
| parent | a7467b9bb2aa667a8d34bc8b678ce35fcb19ebd4 |
This can also be extended to ELF later as it means roughly the same thing there.
This addresses the main issue in #21721 but as I don't have a macOS machine to
do further testing on, I can't confirm whether zig cc is able to pass the entire
cgo test suite after this commit. It can, however, cross-compile a basic program
that uses cgo to x86_64-macos-none which previously failed due to lack of -x
support. Unlike previously, the resulting symbol table does not contain local
symbols (such as C static functions).
I believe this satisfies the related donor bounty: https://ziglang.org/news/second-donor-bounty10 files changed, 83 insertions(+), 3 deletions(-)
lib/std/Build/Step/Compile.zig+6| ... | @@ -160,6 +160,9 @@ dead_strip_dylibs: bool = false, | ... | @@ -160,6 +160,9 @@ dead_strip_dylibs: bool = false, |
| 160 | /// (Darwin) Force load all members of static archives that implement an Objective-C class or category | 160 | /// (Darwin) Force load all members of static archives that implement an Objective-C class or category |
| 161 | force_load_objc: bool = false, | 161 | force_load_objc: bool = false, |
| 162 | 162 | ||
| 163 | /// Whether local symbols should be discarded from the symbol table. | ||
| 164 | discard_local_symbols: bool = false, | ||
| 165 | |||
| 163 | /// Position Independent Executable | 166 | /// Position Independent Executable |
| 164 | pie: ?bool = null, | 167 | pie: ?bool = null, |
| 165 | 168 | ||
| ... | @@ -1555,6 +1558,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1555,6 +1558,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1555 | if (compile.force_load_objc) { | 1558 | if (compile.force_load_objc) { |
| 1556 | try zig_args.append("-ObjC"); | 1559 | try zig_args.append("-ObjC"); |
| 1557 | } | 1560 | } |
| 1561 | if (compile.discard_local_symbols) { | ||
| 1562 | try zig_args.append("--discard-all"); | ||
| 1563 | } | ||
| 1558 | 1564 | ||
| 1559 | try addFlag(&zig_args, "compiler-rt", compile.bundle_compiler_rt); | 1565 | try addFlag(&zig_args, "compiler-rt", compile.bundle_compiler_rt); |
| 1560 | try addFlag(&zig_args, "dll-export-fns", compile.dll_export_fns); | 1566 | try addFlag(&zig_args, "dll-export-fns", compile.dll_export_fns); |
src/Compilation.zig+4| ... | @@ -1160,6 +1160,8 @@ pub const CreateOptions = struct { | ... | @@ -1160,6 +1160,8 @@ pub const CreateOptions = struct { |
| 1160 | dead_strip_dylibs: bool = false, | 1160 | dead_strip_dylibs: bool = false, |
| 1161 | /// (Darwin) Force load all members of static archives that implement an Objective-C class or category | 1161 | /// (Darwin) Force load all members of static archives that implement an Objective-C class or category |
| 1162 | force_load_objc: bool = false, | 1162 | force_load_objc: bool = false, |
| 1163 | /// Whether local symbols should be discarded from the symbol table. | ||
| 1164 | discard_local_symbols: bool = false, | ||
| 1163 | libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, | 1165 | libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, |
| 1164 | /// (Windows) PDB source path prefix to instruct the linker how to resolve relative | 1166 | /// (Windows) PDB source path prefix to instruct the linker how to resolve relative |
| 1165 | /// paths when consolidating CodeView streams into a single PDB file. | 1167 | /// paths when consolidating CodeView streams into a single PDB file. |
| ... | @@ -1585,6 +1587,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1585,6 +1587,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1585 | .headerpad_max_install_names = options.headerpad_max_install_names, | 1587 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| 1586 | .dead_strip_dylibs = options.dead_strip_dylibs, | 1588 | .dead_strip_dylibs = options.dead_strip_dylibs, |
| 1587 | .force_load_objc = options.force_load_objc, | 1589 | .force_load_objc = options.force_load_objc, |
| 1590 | .discard_local_symbols = options.discard_local_symbols, | ||
| 1588 | .pdb_source_path = options.pdb_source_path, | 1591 | .pdb_source_path = options.pdb_source_path, |
| 1589 | .pdb_out_path = options.pdb_out_path, | 1592 | .pdb_out_path = options.pdb_out_path, |
| 1590 | .entry_addr = null, // CLI does not expose this option (yet?) | 1593 | .entry_addr = null, // CLI does not expose this option (yet?) |
| ... | @@ -2665,6 +2668,7 @@ fn addNonIncrementalStuffToCacheManifest( | ... | @@ -2665,6 +2668,7 @@ fn addNonIncrementalStuffToCacheManifest( |
| 2665 | man.hash.add(opts.headerpad_max_install_names); | 2668 | man.hash.add(opts.headerpad_max_install_names); |
| 2666 | man.hash.add(opts.dead_strip_dylibs); | 2669 | man.hash.add(opts.dead_strip_dylibs); |
| 2667 | man.hash.add(opts.force_load_objc); | 2670 | man.hash.add(opts.force_load_objc); |
| 2671 | man.hash.add(opts.discard_local_symbols); | ||
| 2668 | 2672 | ||
| 2669 | // COFF specific stuff | 2673 | // COFF specific stuff |
| 2670 | man.hash.addOptional(opts.subsystem); | 2674 | man.hash.addOptional(opts.subsystem); |
src/link.zig+2| ... | @@ -491,6 +491,8 @@ pub const File = struct { | ... | @@ -491,6 +491,8 @@ pub const File = struct { |
| 491 | /// Force load all members of static archives that implement an | 491 | /// Force load all members of static archives that implement an |
| 492 | /// Objective-C class or category | 492 | /// Objective-C class or category |
| 493 | force_load_objc: bool, | 493 | force_load_objc: bool, |
| 494 | /// Whether local symbols should be discarded from the symbol table. | ||
| 495 | discard_local_symbols: bool, | ||
| 494 | 496 | ||
| 495 | /// Windows-specific linker flags: | 497 | /// Windows-specific linker flags: |
| 496 | /// PDB source path prefix to instruct the linker how to resolve relative | 498 | /// PDB source path prefix to instruct the linker how to resolve relative |
src/link/MachO.zig+7| ... | @@ -139,6 +139,8 @@ no_implicit_dylibs: bool = false, | ... | @@ -139,6 +139,8 @@ no_implicit_dylibs: bool = false, |
| 139 | /// Whether the linker should parse and always force load objects containing ObjC in archives. | 139 | /// Whether the linker should parse and always force load objects containing ObjC in archives. |
| 140 | // TODO: in Zig we currently take -ObjC as always on | 140 | // TODO: in Zig we currently take -ObjC as always on |
| 141 | force_load_objc: bool = true, | 141 | force_load_objc: bool = true, |
| 142 | /// Whether local symbols should be discarded from the symbol table. | ||
| 143 | discard_local_symbols: bool = false, | ||
| 142 | 144 | ||
| 143 | /// Hot-code swapping state. | 145 | /// Hot-code swapping state. |
| 144 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, | 146 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, |
| ... | @@ -221,6 +223,7 @@ pub fn createEmpty( | ... | @@ -221,6 +223,7 @@ pub fn createEmpty( |
| 221 | .lib_directories = options.lib_directories, | 223 | .lib_directories = options.lib_directories, |
| 222 | .framework_dirs = options.framework_dirs, | 224 | .framework_dirs = options.framework_dirs, |
| 223 | .force_load_objc = options.force_load_objc, | 225 | .force_load_objc = options.force_load_objc, |
| 226 | .discard_local_symbols = options.discard_local_symbols, | ||
| 224 | }; | 227 | }; |
| 225 | if (use_llvm and comp.config.have_zcu) { | 228 | if (use_llvm and comp.config.have_zcu) { |
| 226 | self.llvm_object = try LlvmObject.create(arena, comp); | 229 | self.llvm_object = try LlvmObject.create(arena, comp); |
| ... | @@ -720,6 +723,10 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { | ... | @@ -720,6 +723,10 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 720 | try argv.append("-ObjC"); | 723 | try argv.append("-ObjC"); |
| 721 | } | 724 | } |
| 722 | 725 | ||
| 726 | if (self.discard_local_symbols) { | ||
| 727 | try argv.append("-x"); | ||
| 728 | } | ||
| 729 | |||
| 723 | if (self.entry_name) |entry_name| { | 730 | if (self.entry_name) |entry_name| { |
| 724 | try argv.appendSlice(&.{ "-e", entry_name }); | 731 | try argv.appendSlice(&.{ "-e", entry_name }); |
| 725 | } | 732 | } |
src/link/MachO/InternalObject.zig+1| ... | @@ -583,6 +583,7 @@ pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) void { | ... | @@ -583,6 +583,7 @@ pub fn calcSymtabSize(self: *InternalObject, macho_file: *MachO) void { |
| 583 | const file = ref.getFile(macho_file) orelse continue; | 583 | const file = ref.getFile(macho_file) orelse continue; |
| 584 | if (file.getIndex() != self.index) continue; | 584 | if (file.getIndex() != self.index) continue; |
| 585 | if (sym.getName(macho_file).len == 0) continue; | 585 | if (sym.getName(macho_file).len == 0) continue; |
| 586 | if (macho_file.discard_local_symbols and sym.isLocal()) continue; | ||
| 586 | sym.flags.output_symtab = true; | 587 | sym.flags.output_symtab = true; |
| 587 | if (sym.isLocal()) { | 588 | if (sym.isLocal()) { |
| 588 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); | 589 | sym.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, macho_file); |
src/link/MachO/Object.zig+1| ... | @@ -1722,6 +1722,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { | ... | @@ -1722,6 +1722,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { |
| 1722 | if (file.getIndex() != self.index) continue; | 1722 | if (file.getIndex() != self.index) continue; |
| 1723 | if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; | 1723 | if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; |
| 1724 | if (sym.isSymbolStab(macho_file)) continue; | 1724 | if (sym.isSymbolStab(macho_file)) continue; |
| 1725 | if (macho_file.discard_local_symbols and sym.isLocal()) continue; | ||
| 1725 | const name = sym.getName(macho_file); | 1726 | const name = sym.getName(macho_file); |
| 1726 | if (name.len == 0) continue; | 1727 | if (name.len == 0) continue; |
| 1727 | // TODO in -r mode, we actually want to merge symbol names and emit only one | 1728 | // TODO in -r mode, we actually want to merge symbol names and emit only one |
src/link/MachO/ZigObject.zig+1| ... | @@ -500,6 +500,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void { | ... | @@ -500,6 +500,7 @@ pub fn calcSymtabSize(self: *ZigObject, macho_file: *MachO) void { |
| 500 | const file = ref.getFile(macho_file) orelse continue; | 500 | const file = ref.getFile(macho_file) orelse continue; |
| 501 | if (file.getIndex() != self.index) continue; | 501 | if (file.getIndex() != self.index) continue; |
| 502 | if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; | 502 | if (sym.getAtom(macho_file)) |atom| if (!atom.isAlive()) continue; |
| 503 | if (macho_file.discard_local_symbols and sym.isLocal()) continue; | ||
| 503 | const name = sym.getName(macho_file); | 504 | const name = sym.getName(macho_file); |
| 504 | assert(name.len > 0); | 505 | assert(name.len > 0); |
| 505 | sym.flags.output_symtab = true; | 506 | sym.flags.output_symtab = true; |
src/link/MachO/synthetic.zig+9-3| ... | @@ -532,17 +532,23 @@ pub const Indsymtab = struct { | ... | @@ -532,17 +532,23 @@ pub const Indsymtab = struct { |
| 532 | 532 | ||
| 533 | for (macho_file.stubs.symbols.items) |ref| { | 533 | for (macho_file.stubs.symbols.items) |ref| { |
| 534 | const sym = ref.getSymbol(macho_file).?; | 534 | const sym = ref.getSymbol(macho_file).?; |
| 535 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 535 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 536 | try writer.writeInt(u32, idx, .little); | ||
| 537 | } | ||
| 536 | } | 538 | } |
| 537 | 539 | ||
| 538 | for (macho_file.got.symbols.items) |ref| { | 540 | for (macho_file.got.symbols.items) |ref| { |
| 539 | const sym = ref.getSymbol(macho_file).?; | 541 | const sym = ref.getSymbol(macho_file).?; |
| 540 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 542 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 543 | try writer.writeInt(u32, idx, .little); | ||
| 544 | } | ||
| 541 | } | 545 | } |
| 542 | 546 | ||
| 543 | for (macho_file.stubs.symbols.items) |ref| { | 547 | for (macho_file.stubs.symbols.items) |ref| { |
| 544 | const sym = ref.getSymbol(macho_file).?; | 548 | const sym = ref.getSymbol(macho_file).?; |
| 545 | try writer.writeInt(u32, sym.getOutputSymtabIndex(macho_file).?, .little); | 549 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 550 | try writer.writeInt(u32, idx, .little); | ||
| 551 | } | ||
| 546 | } | 552 | } |
| 547 | } | 553 | } |
| 548 | }; | 554 | }; |
src/main.zig+6| ... | @@ -918,6 +918,7 @@ fn buildOutputType( | ... | @@ -918,6 +918,7 @@ fn buildOutputType( |
| 918 | var headerpad_max_install_names: bool = false; | 918 | var headerpad_max_install_names: bool = false; |
| 919 | var dead_strip_dylibs: bool = false; | 919 | var dead_strip_dylibs: bool = false; |
| 920 | var force_load_objc: bool = false; | 920 | var force_load_objc: bool = false; |
| 921 | var discard_local_symbols: bool = false; | ||
| 921 | var contains_res_file: bool = false; | 922 | var contains_res_file: bool = false; |
| 922 | var reference_trace: ?u32 = null; | 923 | var reference_trace: ?u32 = null; |
| 923 | var pdb_out_path: ?[]const u8 = null; | 924 | var pdb_out_path: ?[]const u8 = null; |
| ... | @@ -1151,6 +1152,8 @@ fn buildOutputType( | ... | @@ -1151,6 +1152,8 @@ fn buildOutputType( |
| 1151 | entry = .{ .named = arg["-fentry=".len..] }; | 1152 | entry = .{ .named = arg["-fentry=".len..] }; |
| 1152 | } else if (mem.eql(u8, arg, "--force_undefined")) { | 1153 | } else if (mem.eql(u8, arg, "--force_undefined")) { |
| 1153 | try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {}); | 1154 | try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {}); |
| 1155 | } else if (mem.eql(u8, arg, "--discard-all")) { | ||
| 1156 | discard_local_symbols = true; | ||
| 1154 | } else if (mem.eql(u8, arg, "--stack")) { | 1157 | } else if (mem.eql(u8, arg, "--stack")) { |
| 1155 | stack_size = parseStackSize(args_iter.nextOrFatal()); | 1158 | stack_size = parseStackSize(args_iter.nextOrFatal()); |
| 1156 | } else if (mem.eql(u8, arg, "--image-base")) { | 1159 | } else if (mem.eql(u8, arg, "--image-base")) { |
| ... | @@ -2510,6 +2513,8 @@ fn buildOutputType( | ... | @@ -2510,6 +2513,8 @@ fn buildOutputType( |
| 2510 | entry = .{ .named = linker_args_it.nextOrFatal() }; | 2513 | entry = .{ .named = linker_args_it.nextOrFatal() }; |
| 2511 | } else if (mem.eql(u8, arg, "-u")) { | 2514 | } else if (mem.eql(u8, arg, "-u")) { |
| 2512 | try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {}); | 2515 | try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {}); |
| 2516 | } else if (mem.eql(u8, arg, "-x") or mem.eql(u8, arg, "--discard-all")) { | ||
| 2517 | discard_local_symbols = true; | ||
| 2513 | } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) { | 2518 | } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) { |
| 2514 | stack_size = parseStackSize(linker_args_it.nextOrFatal()); | 2519 | stack_size = parseStackSize(linker_args_it.nextOrFatal()); |
| 2515 | } else if (mem.eql(u8, arg, "--image-base")) { | 2520 | } else if (mem.eql(u8, arg, "--image-base")) { |
| ... | @@ -3579,6 +3584,7 @@ fn buildOutputType( | ... | @@ -3579,6 +3584,7 @@ fn buildOutputType( |
| 3579 | .headerpad_max_install_names = headerpad_max_install_names, | 3584 | .headerpad_max_install_names = headerpad_max_install_names, |
| 3580 | .dead_strip_dylibs = dead_strip_dylibs, | 3585 | .dead_strip_dylibs = dead_strip_dylibs, |
| 3581 | .force_load_objc = force_load_objc, | 3586 | .force_load_objc = force_load_objc, |
| 3587 | .discard_local_symbols = discard_local_symbols, | ||
| 3582 | .reference_trace = reference_trace, | 3588 | .reference_trace = reference_trace, |
| 3583 | .pdb_out_path = pdb_out_path, | 3589 | .pdb_out_path = pdb_out_path, |
| 3584 | .error_limit = error_limit, | 3590 | .error_limit = error_limit, |
test/link/macho.zig+46| ... | @@ -62,6 +62,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -62,6 +62,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 62 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); | 62 | macho_step.dependOn(testTlsLargeTbss(b, .{ .target = default_target })); |
| 63 | macho_step.dependOn(testTlsZig(b, .{ .target = default_target })); | 63 | macho_step.dependOn(testTlsZig(b, .{ .target = default_target })); |
| 64 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); | 64 | macho_step.dependOn(testUndefinedFlag(b, .{ .target = default_target })); |
| 65 | macho_step.dependOn(testDiscardLocalSymbols(b, .{ .target = default_target })); | ||
| 65 | macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target })); | 66 | macho_step.dependOn(testUnresolvedError(b, .{ .target = default_target })); |
| 66 | macho_step.dependOn(testUnresolvedError2(b, .{ .target = default_target })); | 67 | macho_step.dependOn(testUnresolvedError2(b, .{ .target = default_target })); |
| 67 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); | 68 | macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target })); |
| ... | @@ -2502,6 +2503,51 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { | ... | @@ -2502,6 +2503,51 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { |
| 2502 | return test_step; | 2503 | return test_step; |
| 2503 | } | 2504 | } |
| 2504 | 2505 | ||
| 2506 | fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step { | ||
| 2507 | const test_step = addTestStep(b, "discard-local-symbols", opts); | ||
| 2508 | |||
| 2509 | const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" }); | ||
| 2510 | |||
| 2511 | const lib = addStaticLibrary(b, opts, .{ .name = "a" }); | ||
| 2512 | lib.addObject(obj); | ||
| 2513 | |||
| 2514 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); | ||
| 2515 | |||
| 2516 | { | ||
| 2517 | const exe = addExecutable(b, opts, .{ .name = "main3" }); | ||
| 2518 | exe.addObject(main_o); | ||
| 2519 | exe.addObject(obj); | ||
| 2520 | exe.discard_local_symbols = true; | ||
| 2521 | |||
| 2522 | const run = addRunArtifact(exe); | ||
| 2523 | run.expectExitCode(0); | ||
| 2524 | test_step.dependOn(&run.step); | ||
| 2525 | |||
| 2526 | const check = exe.checkObject(); | ||
| 2527 | check.checkInSymtab(); | ||
| 2528 | check.checkNotPresent("_foo"); | ||
| 2529 | test_step.dependOn(&check.step); | ||
| 2530 | } | ||
| 2531 | |||
| 2532 | { | ||
| 2533 | const exe = addExecutable(b, opts, .{ .name = "main4" }); | ||
| 2534 | exe.addObject(main_o); | ||
| 2535 | exe.linkLibrary(lib); | ||
| 2536 | exe.discard_local_symbols = true; | ||
| 2537 | |||
| 2538 | const run = addRunArtifact(exe); | ||
| 2539 | run.expectExitCode(0); | ||
| 2540 | test_step.dependOn(&run.step); | ||
| 2541 | |||
| 2542 | const check = exe.checkObject(); | ||
| 2543 | check.checkInSymtab(); | ||
| 2544 | check.checkNotPresent("_foo"); | ||
| 2545 | test_step.dependOn(&check.step); | ||
| 2546 | } | ||
| 2547 | |||
| 2548 | return test_step; | ||
| 2549 | } | ||
| 2550 | |||
| 2505 | fn testUndefinedFlag(b: *Build, opts: Options) *Step { | 2551 | fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2506 | const test_step = addTestStep(b, "undefined-flag", opts); | 2552 | const test_step = addTestStep(b, "undefined-flag", opts); |
| 2507 | 2553 |