authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-20 17:51:20+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-20 17:51:20+02:00
log74ed7c1f0998e9dd89aa3f3480fff845afd6b422
treece9809fd8d6f92bf0d502cd1f50e3d7a43fb6c64
parenta97a39bea6022fb7449620384641cdfa70303f8d
parent8752db3285060c6f2d85c0fa744c44094239a792
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11875 from motiejus/pagezero-size

[MachO] add -pagezero_size

7 files changed, 68 insertions(+), 14 deletions(-)

src/Compilation.zig+6-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 file904 /// (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};
907909
908fn addPackageTableToCacheHash(910fn addPackageTableToCacheHash(
...@@ -1742,6 +1744,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1742,6 +1744,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1742 .native_darwin_sdk = options.native_darwin_sdk,1744 .native_darwin_sdk = options.native_darwin_sdk,
1743 .install_name = options.install_name,1745 .install_name = options.install_name,
1744 .entitlements = options.entitlements,1746 .entitlements = options.entitlements,
1747 .pagezero_size = options.pagezero_size,
1745 });1748 });
1746 errdefer bin_file.destroy();1749 errdefer bin_file.destroy();
1747 comp.* = .{1750 comp.* = .{
...@@ -2359,7 +2362,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo...@@ -2359,7 +2362,7 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo
2359/// to remind the programmer to update multiple related pieces of code that2362/// to remind the programmer to update multiple related pieces of code that
2360/// are in different locations. Bump this number when adding or deleting2363/// are in different locations. Bump this number when adding or deleting
2361/// anything from the link cache manifest.2364/// anything from the link cache manifest.
2362pub const link_hash_implementation_version = 3;2365pub const link_hash_implementation_version = 4;
23632366
2364fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {2367fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
2365 const gpa = comp.gpa;2368 const gpa = comp.gpa;
...@@ -2369,7 +2372,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2369,7 +2372,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2369 defer arena_allocator.deinit();2372 defer arena_allocator.deinit();
2370 const arena = arena_allocator.allocator();2373 const arena = arena_allocator.allocator();
23712374
2372 comptime assert(link_hash_implementation_version == 3);2375 comptime assert(link_hash_implementation_version == 4);
23732376
2374 if (comp.bin_file.options.module) |mod| {2377 if (comp.bin_file.options.module) |mod| {
2375 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{2378 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{
...@@ -2474,6 +2477,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2474,6 +2477,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2474 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);2477 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
2475 man.hash.addListOfBytes(comp.bin_file.options.frameworks);2478 man.hash.addListOfBytes(comp.bin_file.options.frameworks);
2476 try man.addOptionalFile(comp.bin_file.options.entitlements);2479 try man.addOptionalFile(comp.bin_file.options.entitlements);
2480 man.hash.addOptional(comp.bin_file.options.pagezero_size);
24772481
2478 // COFF specific stuff2482 // COFF specific stuff
2479 man.hash.addOptional(comp.bin_file.options.subsystem);2483 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 file187 /// (Darwin) Path to entitlements file
188 entitlements: ?[]const u8 = null,188 entitlements: ?[]const u8 = null,
189189
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();
971971
972 comptime assert(Compilation.link_hash_implementation_version == 3);972 comptime assert(Compilation.link_hash_implementation_version == 4);
973973
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();
13001300
1301 comptime assert(Compilation.link_hash_implementation_version == 3);1301 comptime assert(Compilation.link_hash_implementation_version == 4);
13021302
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+25-9
...@@ -286,9 +286,9 @@ const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld";...@@ -286,9 +286,9 @@ const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld";
286const minimum_text_block_size = 64;286const minimum_text_block_size = 64;
287pub const min_text_capacity = padToIdeal(minimum_text_block_size);287pub const min_text_capacity = padToIdeal(minimum_text_block_size);
288288
289/// Virtual memory offset corresponds to the size of __PAGEZERO segment and start of289/// Default virtual memory offset corresponds to the size of __PAGEZERO segment and
290/// __TEXT segment.290/// start of __TEXT segment.
291const pagezero_vmsize: u64 = 0x100000000;291const default_pagezero_vmsize: u64 = 0x100000000;
292292
293pub const Export = struct {293pub const Export = struct {
294 sym_index: ?u32 = null,294 sym_index: ?u32 = null,
...@@ -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();
538538
539 comptime assert(Compilation.link_hash_implementation_version == 3);539 comptime assert(Compilation.link_hash_implementation_version == 4);
540540
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 Zig549 // 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 man.hash.addOptional(self.base.options.pagezero_size);
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);
...@@ -928,6 +929,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -928,6 +929,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
928 try argv.append(rpath);929 try argv.append(rpath);
929 }930 }
930931
932 if (self.base.options.pagezero_size) |pagezero_size| {
933 try argv.append("-pagezero_size");
934 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));
935 }
936
931 try argv.appendSlice(positionals.items);937 try argv.appendSlice(positionals.items);
932938
933 try argv.append("-o");939 try argv.append("-o");
...@@ -4365,14 +4371,21 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -4365,14 +4371,21 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
43654371
4366fn populateMissingMetadata(self: *MachO) !void {4372fn populateMissingMetadata(self: *MachO) !void {
4367 const cpu_arch = self.base.options.target.cpu.arch;4373 const cpu_arch = self.base.options.target.cpu.arch;
43684374 const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;
4369 if (self.pagezero_segment_cmd_index == null) {4375 const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size);
4376
4377 if (self.pagezero_segment_cmd_index == null) blk: {
4378 if (aligned_pagezero_vmsize == 0) break :blk;
4379 if (aligned_pagezero_vmsize != pagezero_vmsize) {
4380 log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
4381 log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
4382 }
4370 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4383 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
4371 try self.load_commands.append(self.base.allocator, .{4384 try self.load_commands.append(self.base.allocator, .{
4372 .segment = .{4385 .segment = .{
4373 .inner = .{4386 .inner = .{
4374 .segname = makeStaticString("__PAGEZERO"),4387 .segname = makeStaticString("__PAGEZERO"),
4375 .vmsize = pagezero_vmsize,4388 .vmsize = aligned_pagezero_vmsize,
4376 .cmdsize = @sizeOf(macho.segment_command_64),4389 .cmdsize = @sizeOf(macho.segment_command_64),
4377 },4390 },
4378 },4391 },
...@@ -4394,7 +4407,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4394,7 +4407,7 @@ fn populateMissingMetadata(self: *MachO) !void {
4394 .segment = .{4407 .segment = .{
4395 .inner = .{4408 .inner = .{
4396 .segname = makeStaticString("__TEXT"),4409 .segname = makeStaticString("__TEXT"),
4397 .vmaddr = pagezero_vmsize,4410 .vmaddr = aligned_pagezero_vmsize,
4398 .vmsize = needed_size,4411 .vmsize = needed_size,
4399 .filesize = needed_size,4412 .filesize = needed_size,
4400 .maxprot = macho.PROT.READ | macho.PROT.EXEC,4413 .maxprot = macho.PROT.READ | macho.PROT.EXEC,
...@@ -4881,7 +4894,10 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -4881,7 +4894,10 @@ fn populateMissingMetadata(self: *MachO) !void {
48814894
4882fn allocateTextSegment(self: *MachO) !void {4895fn allocateTextSegment(self: *MachO) !void {
4883 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;4896 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment;
4884 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].segment.inner.vmsize;4897 const base_vmaddr = if (self.pagezero_segment_cmd_index) |index|
4898 self.load_commands.items[index].segment.inner.vmsize
4899 else
4900 0;
4885 seg.inner.fileoff = 0;4901 seg.inner.fileoff = 0;
4886 seg.inner.vmaddr = base_vmaddr;4902 seg.inner.vmaddr = base_vmaddr;
48874903
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();
22762276
2277 comptime assert(Compilation.link_hash_implementation_version == 3);2277 comptime assert(Compilation.link_hash_implementation_version == 4);
22782278
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+31
...@@ -447,6 +447,7 @@ const usage_build_generic =...@@ -447,6 +447,7 @@ const usage_build_generic =
447 \\ -F[dir] (Darwin) add search path for frameworks447 \\ -F[dir] (Darwin) add search path for frameworks
448 \\ -install_name=[value] (Darwin) add dylib's install name448 \\ -install_name=[value] (Darwin) add dylib's install name
449 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature449 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
450 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
450 \\ --import-memory (WebAssembly) import memory from the environment451 \\ --import-memory (WebAssembly) import memory from the environment
451 \\ --import-table (WebAssembly) import function table from the host environment452 \\ --import-table (WebAssembly) import function table from the host environment
452 \\ --export-table (WebAssembly) export function table to the host environment453 \\ --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;
697699
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-style701 // This array is populated by zig cc frontend and then has to be converted to zig-style
...@@ -908,6 +910,13 @@ fn buildOutputType(...@@ -908,6 +910,13 @@ fn buildOutputType(
908 install_name = args_iter.next() orelse {910 install_name = args_iter.next() orelse {
909 fatal("expected parameter after {s}", .{arg});911 fatal("expected parameter after {s}", .{arg});
910 };912 };
913 } else if (mem.eql(u8, arg, "-pagezero_size")) {
914 const next_arg = args_iter.next() orelse {
915 fatal("expected parameter after {s}", .{arg});
916 };
917 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
918 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
919 };
911 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {920 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
912 linker_script = args_iter.next() orelse {921 linker_script = args_iter.next() orelse {
913 fatal("expected parameter after {s}", .{arg});922 fatal("expected parameter after {s}", .{arg});
...@@ -1647,6 +1656,15 @@ fn buildOutputType(...@@ -1647,6 +1656,15 @@ fn buildOutputType(
1647 linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {1656 linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {
1648 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });1657 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
1649 };1658 };
1659 } else if (mem.eql(u8, arg, "-pagezero_size")) {
1660 i += 1;
1661 if (i >= linker_args.items.len) {
1662 fatal("expected linker arg after '{s}'", .{arg});
1663 }
1664 const next_arg = linker_args.items[i];
1665 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
1666 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
1667 };
1650 } else if (mem.eql(u8, arg, "--gc-sections")) {1668 } else if (mem.eql(u8, arg, "--gc-sections")) {
1651 linker_gc_sections = true;1669 linker_gc_sections = true;
1652 } else if (mem.eql(u8, arg, "--no-gc-sections")) {1670 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
...@@ -2763,6 +2781,7 @@ fn buildOutputType(...@@ -2763,6 +2781,7 @@ fn buildOutputType(
2763 .native_darwin_sdk = native_darwin_sdk,2781 .native_darwin_sdk = native_darwin_sdk,
2764 .install_name = install_name,2782 .install_name = install_name,
2765 .entitlements = entitlements,2783 .entitlements = entitlements,
2784 .pagezero_size = pagezero_size,
2766 }) catch |err| switch (err) {2785 }) catch |err| switch (err) {
2767 error.LibCUnavailable => {2786 error.LibCUnavailable => {
2768 const target = target_info.target;2787 const target = target_info.target;
...@@ -5048,6 +5067,18 @@ pub fn cmdChangelist(...@@ -5048,6 +5067,18 @@ pub fn cmdChangelist(
5048 try bw.flush();5067 try bw.flush();
5049}5068}
50505069
5070fn eatIntPrefix(arg: []const u8, radix: u8) []const u8 {
5071 if (arg.len > 2 and arg[0] == '0') {
5072 switch (std.ascii.toLower(arg[1])) {
5073 'b' => if (radix == 2) return arg[2..],
5074 'o' => if (radix == 8) return arg[2..],
5075 'x' => if (radix == 16) return arg[2..],
5076 else => {},
5077 }
5078 }
5079 return arg;
5080}
5081
5051fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {5082fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
5052 return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {5083 return std.fmt.parseUnsigned(u64, arg[prefix_len..], 0) catch |err| {
5053 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });5084 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });