authorgravatar for motiejus@jakstys.ltMotiejus Jakštys <motiejus@jakstys.lt> 2022-06-16 15:42:35+03:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-20 13:39:33+02:00
log98138ba78c1540830a4fdb0537ed6ad5c7b57e7a
tree8ff0a80295d0702fbe63bf8849c4b390ba94bd50
parenta97a39bea6022fb7449620384641cdfa70303f8d

[MachO] add -pagezero_size

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 {
903903 install_name: ?[]const u8 = null,
904904 /// (Darwin) Path to entitlements file
905905 entitlements: ?[]const u8 = null,
906 /// (Darwin) size of the __PAGEZERO segment
907 pagezero_size: ?u64 = null,
906908};
907909
908910fn addPackageTableToCacheHash(
......@@ -2359,7 +2361,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
23592361/// to remind the programmer to update multiple related pieces of code that
23602362/// are in different locations. Bump this number when adding or deleting
23612363/// anything from the link cache manifest.
2362pub const link_hash_implementation_version = 3;
2364pub const link_hash_implementation_version = 4;
23632365
23642366fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
23652367 const gpa = comp.gpa;
......@@ -2369,7 +2371,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
23692371 defer arena_allocator.deinit();
23702372 const arena = arena_allocator.allocator();
23712373
2372 comptime assert(link_hash_implementation_version == 3);
2374 comptime assert(link_hash_implementation_version == 4);
23732375
23742376 if (comp.bin_file.options.module) |mod| {
23752377 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
24742476 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
24752477 man.hash.addListOfBytes(comp.bin_file.options.frameworks);
24762478 try man.addOptionalFile(comp.bin_file.options.entitlements);
2479 if (comp.bin_file.options.pagezero_size) |value| man.hash.add(value);
24772480
24782481 // COFF specific stuff
24792482 man.hash.addOptional(comp.bin_file.options.subsystem);
src/link.zig+3
......@@ -187,6 +187,9 @@ pub const Options = struct {
187187 /// (Darwin) Path to entitlements file
188188 entitlements: ?[]const u8 = null,
189189
190 /// (Darwin) size of the __PAGEZERO segment
191 pagezero_size: ?u64 = null,
192
190193 pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
191194 return if (options.use_lld) .Obj else options.output_mode;
192195 }
src/link/Coff.zig+1-1
......@@ -969,7 +969,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
969969 man = comp.cache_parent.obtain();
970970 self.base.releaseLock();
971971
972 comptime assert(Compilation.link_hash_implementation_version == 3);
972 comptime assert(Compilation.link_hash_implementation_version == 4);
973973
974974 for (self.base.options.objects) |obj| {
975975 _ = 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
12981298 // We are about to obtain this lock, so here we give other processes a chance first.
12991299 self.base.releaseLock();
13001300
1301 comptime assert(Compilation.link_hash_implementation_version == 3);
1301 comptime assert(Compilation.link_hash_implementation_version == 4);
13021302
13031303 try man.addOptionalFile(self.base.options.linker_script);
13041304 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";
286286const minimum_text_block_size = 64;
287287pub const min_text_capacity = padToIdeal(minimum_text_block_size);
288288
289/// Virtual memory offset corresponds to the size of __PAGEZERO segment and start of
290/// __TEXT segment.
289/// Virtual memory offset corresponds to the size of __PAGEZERO segment and
290/// start of __TEXT segment.
291291const pagezero_vmsize: u64 = 0x100000000;
292292
293293pub const Export = struct {
......@@ -536,7 +536,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
536536 // We are about to obtain this lock, so here we give other processes a chance first.
537537 self.base.releaseLock();
538538
539 comptime assert(Compilation.link_hash_implementation_version == 3);
539 comptime assert(Compilation.link_hash_implementation_version == 4);
540540
541541 for (self.base.options.objects) |obj| {
542542 _ = try man.addFile(obj.path, null);
......@@ -549,6 +549,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
549549 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
550550 // installation sources because they are always a product of the compiler version + target information.
551551 man.hash.add(stack_size);
552 if (self.base.options.pagezero_size) |value| man.hash.add(value);
552553 man.hash.addListOfBytes(self.base.options.lib_dirs);
553554 man.hash.addListOfBytes(self.base.options.framework_dirs);
554555 man.hash.addListOfBytes(self.base.options.frameworks);
......@@ -4372,7 +4373,7 @@ fn populateMissingMetadata(self: *MachO) !void {
43724373 .segment = .{
43734374 .inner = .{
43744375 .segname = makeStaticString("__PAGEZERO"),
4375 .vmsize = pagezero_vmsize,
4376 .vmsize = self.base.options.pagezero_size orelse pagezero_vmsize,
43764377 .cmdsize = @sizeOf(macho.segment_command_64),
43774378 },
43784379 },
......@@ -4394,7 +4395,7 @@ fn populateMissingMetadata(self: *MachO) !void {
43944395 .segment = .{
43954396 .inner = .{
43964397 .segname = makeStaticString("__TEXT"),
4397 .vmaddr = pagezero_vmsize,
4398 .vmaddr = self.base.options.pagezero_size orelse pagezero_vmsize,
43984399 .vmsize = needed_size,
43994400 .filesize = needed_size,
44004401 .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) !
22742274 // We are about to obtain this lock, so here we give other processes a chance first.
22752275 self.base.releaseLock();
22762276
2277 comptime assert(Compilation.link_hash_implementation_version == 3);
2277 comptime assert(Compilation.link_hash_implementation_version == 4);
22782278
22792279 for (self.base.options.objects) |obj| {
22802280 _ = try man.addFile(obj.path, null);
src/main.zig+12
......@@ -447,6 +447,7 @@ const usage_build_generic =
447447 \\ -F[dir] (Darwin) add search path for frameworks
448448 \\ -install_name=[value] (Darwin) add dylib's install name
449449 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
450 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment
450451 \\ --import-memory (WebAssembly) import memory from the environment
451452 \\ --import-table (WebAssembly) import function table from the host environment
452453 \\ --export-table (WebAssembly) export function table to the host environment
......@@ -694,6 +695,7 @@ fn buildOutputType(
694695 var install_name: ?[]const u8 = null;
695696 var hash_style: link.HashStyle = .both;
696697 var entitlements: ?[]const u8 = null;
698 var pagezero_size: ?u64 = null;
697699
698700 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
699701 // This array is populated by zig cc frontend and then has to be converted to zig-style
......@@ -1647,6 +1649,15 @@ fn buildOutputType(
16471649 linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {
16481650 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
16491651 };
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 };
16501661 } else if (mem.eql(u8, arg, "--gc-sections")) {
16511662 linker_gc_sections = true;
16521663 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
......@@ -2763,6 +2774,7 @@ fn buildOutputType(
27632774 .native_darwin_sdk = native_darwin_sdk,
27642775 .install_name = install_name,
27652776 .entitlements = entitlements,
2777 .pagezero_size = pagezero_size,
27662778 }) catch |err| switch (err) {
27672779 error.LibCUnavailable => {
27682780 const target = target_info.target;