| author | |
| committer | |
| log | 98138ba78c1540830a4fdb0537ed6ad5c7b57e7a |
| tree | 8ff0a80295d0702fbe63bf8849c4b390ba94bd50 |
| parent | a97a39bea6022fb7449620384641cdfa70303f8d |
Pass `-pagezero_size` to the MachO linker. This is the final
"unsupported linker arg" that I could chase that CGo uses. After this
and #11874 we may be able to fail on an "unsupported linker arg" instead
of emiting a warning.
Test case:
zig=/code/zig/build/zig
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 CC="$zig cc -target x86_64-macos" CXX="$zig c++ -target x86_64-macos" go build -a -ldflags "-s -w" cgo.go
I compiled a trivial CGo program and executed it on an amd64 Darwin
host.
To be honest, I am not entirely sure what this is doing. This feels
right after reading what this argument does in LLVM sources, but I am by
no means qualified to make MachO pull requests. Will take feedback.7 files changed, 29 insertions(+), 10 deletions(-)
src/Compilation.zig+5-2| ... | @@ -903,6 +903,8 @@ pub const InitOptions = struct { | ... | @@ -903,6 +903,8 @@ pub const InitOptions = struct { |
| 903 | install_name: ?[]const u8 = null, | 903 | install_name: ?[]const u8 = null, |
| 904 | /// (Darwin) Path to entitlements file | 904 | /// (Darwin) Path to entitlements file |
| 905 | entitlements: ?[]const u8 = null, | 905 | entitlements: ?[]const u8 = null, |
| 906 | /// (Darwin) size of the __PAGEZERO segment | ||
| 907 | pagezero_size: ?u64 = null, | ||
| 906 | }; | 908 | }; |
| 907 | 909 | ||
| 908 | fn addPackageTableToCacheHash( | 910 | fn addPackageTableToCacheHash( |
| ... | @@ -2359,7 +2361,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo | ... | @@ -2359,7 +2361,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo |
| 2359 | /// to remind the programmer to update multiple related pieces of code that | 2361 | /// to remind the programmer to update multiple related pieces of code that |
| 2360 | /// are in different locations. Bump this number when adding or deleting | 2362 | /// are in different locations. Bump this number when adding or deleting |
| 2361 | /// anything from the link cache manifest. | 2363 | /// anything from the link cache manifest. |
| 2362 | pub const link_hash_implementation_version = 3; | 2364 | pub const link_hash_implementation_version = 4; |
| 2363 | 2365 | ||
| 2364 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | 2366 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { |
| 2365 | const gpa = comp.gpa; | 2367 | const gpa = comp.gpa; |
| ... | @@ -2369,7 +2371,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2369,7 +2371,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2369 | defer arena_allocator.deinit(); | 2371 | defer arena_allocator.deinit(); |
| 2370 | const arena = arena_allocator.allocator(); | 2372 | const arena = arena_allocator.allocator(); |
| 2371 | 2373 | ||
| 2372 | comptime assert(link_hash_implementation_version == 3); | 2374 | comptime assert(link_hash_implementation_version == 4); |
| 2373 | 2375 | ||
| 2374 | if (comp.bin_file.options.module) |mod| { | 2376 | if (comp.bin_file.options.module) |mod| { |
| 2375 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ | 2377 | const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ |
| ... | @@ -2474,6 +2476,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes | ... | @@ -2474,6 +2476,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes |
| 2474 | man.hash.addListOfBytes(comp.bin_file.options.framework_dirs); | 2476 | man.hash.addListOfBytes(comp.bin_file.options.framework_dirs); |
| 2475 | man.hash.addListOfBytes(comp.bin_file.options.frameworks); | 2477 | man.hash.addListOfBytes(comp.bin_file.options.frameworks); |
| 2476 | try man.addOptionalFile(comp.bin_file.options.entitlements); | 2478 | try man.addOptionalFile(comp.bin_file.options.entitlements); |
| 2479 | if (comp.bin_file.options.pagezero_size) |value| man.hash.add(value); | ||
| 2477 | 2480 | ||
| 2478 | // COFF specific stuff | 2481 | // COFF specific stuff |
| 2479 | man.hash.addOptional(comp.bin_file.options.subsystem); | 2482 | man.hash.addOptional(comp.bin_file.options.subsystem); |
src/link.zig+3| ... | @@ -187,6 +187,9 @@ pub const Options = struct { | ... | @@ -187,6 +187,9 @@ pub const Options = struct { |
| 187 | /// (Darwin) Path to entitlements file | 187 | /// (Darwin) Path to entitlements file |
| 188 | entitlements: ?[]const u8 = null, | 188 | entitlements: ?[]const u8 = null, |
| 189 | 189 | ||
| 190 | /// (Darwin) size of the __PAGEZERO segment | ||
| 191 | pagezero_size: ?u64 = null, | ||
| 192 | |||
| 190 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { | 193 | pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { |
| 191 | return if (options.use_lld) .Obj else options.output_mode; | 194 | return if (options.use_lld) .Obj else options.output_mode; |
| 192 | } | 195 | } |
src/link/Coff.zig+1-1| ... | @@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 969 | man = comp.cache_parent.obtain(); | 969 | man = comp.cache_parent.obtain(); |
| 970 | self.base.releaseLock(); | 970 | self.base.releaseLock(); |
| 971 | 971 | ||
| 972 | comptime assert(Compilation.link_hash_implementation_version == 3); | 972 | comptime assert(Compilation.link_hash_implementation_version == 4); |
| 973 | 973 | ||
| 974 | for (self.base.options.objects) |obj| { | 974 | for (self.base.options.objects) |obj| { |
| 975 | _ = try man.addFile(obj.path, null); | 975 | _ = try man.addFile(obj.path, null); |
src/link/Elf.zig+1-1| ... | @@ -1298,7 +1298,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v | ... | @@ -1298,7 +1298,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v |
| 1298 | // We are about to obtain this lock, so here we give other processes a chance first. | 1298 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 1299 | self.base.releaseLock(); | 1299 | self.base.releaseLock(); |
| 1300 | 1300 | ||
| 1301 | comptime assert(Compilation.link_hash_implementation_version == 3); | 1301 | comptime assert(Compilation.link_hash_implementation_version == 4); |
| 1302 | 1302 | ||
| 1303 | try man.addOptionalFile(self.base.options.linker_script); | 1303 | try man.addOptionalFile(self.base.options.linker_script); |
| 1304 | try man.addOptionalFile(self.base.options.version_script); | 1304 | try man.addOptionalFile(self.base.options.version_script); |
src/link/MachO.zig+6-5| ... | @@ -286,8 +286,8 @@ const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; | ... | @@ -286,8 +286,8 @@ const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; |
| 286 | const minimum_text_block_size = 64; | 286 | const minimum_text_block_size = 64; |
| 287 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); | 287 | pub const min_text_capacity = padToIdeal(minimum_text_block_size); |
| 288 | 288 | ||
| 289 | /// Virtual memory offset corresponds to the size of __PAGEZERO segment and start of | 289 | /// Virtual memory offset corresponds to the size of __PAGEZERO segment and |
| 290 | /// __TEXT segment. | 290 | /// start of __TEXT segment. |
| 291 | const pagezero_vmsize: u64 = 0x100000000; | 291 | const pagezero_vmsize: u64 = 0x100000000; |
| 292 | 292 | ||
| 293 | pub const Export = struct { | 293 | pub const Export = struct { |
| ... | @@ -536,7 +536,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -536,7 +536,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 536 | // We are about to obtain this lock, so here we give other processes a chance first. | 536 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 537 | self.base.releaseLock(); | 537 | self.base.releaseLock(); |
| 538 | 538 | ||
| 539 | comptime assert(Compilation.link_hash_implementation_version == 3); | 539 | comptime assert(Compilation.link_hash_implementation_version == 4); |
| 540 | 540 | ||
| 541 | for (self.base.options.objects) |obj| { | 541 | for (self.base.options.objects) |obj| { |
| 542 | _ = try man.addFile(obj.path, null); | 542 | _ = try man.addFile(obj.path, null); |
| ... | @@ -549,6 +549,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -549,6 +549,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 549 | // We can skip hashing libc and libc++ components that we are in charge of building from Zig | 549 | // We can skip hashing libc and libc++ components that we are in charge of building from Zig |
| 550 | // installation sources because they are always a product of the compiler version + target information. | 550 | // installation sources because they are always a product of the compiler version + target information. |
| 551 | man.hash.add(stack_size); | 551 | man.hash.add(stack_size); |
| 552 | if (self.base.options.pagezero_size) |value| man.hash.add(value); | ||
| 552 | man.hash.addListOfBytes(self.base.options.lib_dirs); | 553 | man.hash.addListOfBytes(self.base.options.lib_dirs); |
| 553 | man.hash.addListOfBytes(self.base.options.framework_dirs); | 554 | man.hash.addListOfBytes(self.base.options.framework_dirs); |
| 554 | man.hash.addListOfBytes(self.base.options.frameworks); | 555 | man.hash.addListOfBytes(self.base.options.frameworks); |
| ... | @@ -4372,7 +4373,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4372,7 +4373,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4372 | .segment = .{ | 4373 | .segment = .{ |
| 4373 | .inner = .{ | 4374 | .inner = .{ |
| 4374 | .segname = makeStaticString("__PAGEZERO"), | 4375 | .segname = makeStaticString("__PAGEZERO"), |
| 4375 | .vmsize = pagezero_vmsize, | 4376 | .vmsize = self.base.options.pagezero_size orelse pagezero_vmsize, |
| 4376 | .cmdsize = @sizeOf(macho.segment_command_64), | 4377 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 4377 | }, | 4378 | }, |
| 4378 | }, | 4379 | }, |
| ... | @@ -4394,7 +4395,7 @@ fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -4394,7 +4395,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4394 | .segment = .{ | 4395 | .segment = .{ |
| 4395 | .inner = .{ | 4396 | .inner = .{ |
| 4396 | .segname = makeStaticString("__TEXT"), | 4397 | .segname = makeStaticString("__TEXT"), |
| 4397 | .vmaddr = pagezero_vmsize, | 4398 | .vmaddr = self.base.options.pagezero_size orelse pagezero_vmsize, |
| 4398 | .vmsize = needed_size, | 4399 | .vmsize = needed_size, |
| 4399 | .filesize = needed_size, | 4400 | .filesize = needed_size, |
| 4400 | .maxprot = macho.PROT.READ | macho.PROT.EXEC, | 4401 | .maxprot = macho.PROT.READ | macho.PROT.EXEC, |
src/link/Wasm.zig+1-1| ... | @@ -2274,7 +2274,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! | ... | @@ -2274,7 +2274,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! |
| 2274 | // We are about to obtain this lock, so here we give other processes a chance first. | 2274 | // We are about to obtain this lock, so here we give other processes a chance first. |
| 2275 | self.base.releaseLock(); | 2275 | self.base.releaseLock(); |
| 2276 | 2276 | ||
| 2277 | comptime assert(Compilation.link_hash_implementation_version == 3); | 2277 | comptime assert(Compilation.link_hash_implementation_version == 4); |
| 2278 | 2278 | ||
| 2279 | for (self.base.options.objects) |obj| { | 2279 | for (self.base.options.objects) |obj| { |
| 2280 | _ = try man.addFile(obj.path, null); | 2280 | _ = try man.addFile(obj.path, null); |
src/main.zig+12| ... | @@ -447,6 +447,7 @@ const usage_build_generic = | ... | @@ -447,6 +447,7 @@ const usage_build_generic = |
| 447 | \\ -F[dir] (Darwin) add search path for frameworks | 447 | \\ -F[dir] (Darwin) add search path for frameworks |
| 448 | \\ -install_name=[value] (Darwin) add dylib's install name | 448 | \\ -install_name=[value] (Darwin) add dylib's install name |
| 449 | \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature | 449 | \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature |
| 450 | \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment | ||
| 450 | \\ --import-memory (WebAssembly) import memory from the environment | 451 | \\ --import-memory (WebAssembly) import memory from the environment |
| 451 | \\ --import-table (WebAssembly) import function table from the host environment | 452 | \\ --import-table (WebAssembly) import function table from the host environment |
| 452 | \\ --export-table (WebAssembly) export function table to the host environment | 453 | \\ --export-table (WebAssembly) export function table to the host environment |
| ... | @@ -694,6 +695,7 @@ fn buildOutputType( | ... | @@ -694,6 +695,7 @@ fn buildOutputType( |
| 694 | var install_name: ?[]const u8 = null; | 695 | var install_name: ?[]const u8 = null; |
| 695 | var hash_style: link.HashStyle = .both; | 696 | var hash_style: link.HashStyle = .both; |
| 696 | var entitlements: ?[]const u8 = null; | 697 | var entitlements: ?[]const u8 = null; |
| 698 | var pagezero_size: ?u64 = null; | ||
| 697 | 699 | ||
| 698 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. | 700 | // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. |
| 699 | // This array is populated by zig cc frontend and then has to be converted to zig-style | 701 | // This array is populated by zig cc frontend and then has to be converted to zig-style |
| ... | @@ -1647,6 +1649,15 @@ fn buildOutputType( | ... | @@ -1647,6 +1649,15 @@ fn buildOutputType( |
| 1647 | linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| { | 1649 | linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| { |
| 1648 | fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); | 1650 | fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); |
| 1649 | }; | 1651 | }; |
| 1652 | } else if (mem.eql(u8, arg, "-pagezero_size")) { | ||
| 1653 | i += 1; | ||
| 1654 | if (i >= linker_args.items.len) { | ||
| 1655 | fatal("expected linker arg after '{s}'", .{arg}); | ||
| 1656 | } | ||
| 1657 | const next_arg = linker_args.items[i]; | ||
| 1658 | pagezero_size = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| { | ||
| 1659 | fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) }); | ||
| 1660 | }; | ||
| 1650 | } else if (mem.eql(u8, arg, "--gc-sections")) { | 1661 | } else if (mem.eql(u8, arg, "--gc-sections")) { |
| 1651 | linker_gc_sections = true; | 1662 | linker_gc_sections = true; |
| 1652 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { | 1663 | } else if (mem.eql(u8, arg, "--no-gc-sections")) { |
| ... | @@ -2763,6 +2774,7 @@ fn buildOutputType( | ... | @@ -2763,6 +2774,7 @@ fn buildOutputType( |
| 2763 | .native_darwin_sdk = native_darwin_sdk, | 2774 | .native_darwin_sdk = native_darwin_sdk, |
| 2764 | .install_name = install_name, | 2775 | .install_name = install_name, |
| 2765 | .entitlements = entitlements, | 2776 | .entitlements = entitlements, |
| 2777 | .pagezero_size = pagezero_size, | ||
| 2766 | }) catch |err| switch (err) { | 2778 | }) catch |err| switch (err) { |
| 2767 | error.LibCUnavailable => { | 2779 | error.LibCUnavailable => { |
| 2768 | const target = target_info.target; | 2780 | const target = target_info.target; |