Commit 8c1feef4cd
Changed files (5)
lib
std
lib/std/build.zig
@@ -1593,6 +1593,14 @@ pub const LibExeObjStep = struct {
/// search strategy.
search_strategy: ?enum { paths_first, dylibs_first } = null,
+ /// (Darwin) Set size of the padding between the end of load commands
+ /// and start of `__TEXT,__text` section.
+ headerpad_size: ?u64 = null,
+
+ /// (Darwin) Automatically Set size of the padding between the end of load commands
+ /// and start of `__TEXT,__text` section to a value fitting all paths expanded to MAXPATHLEN.
+ headerpad_max_install_names: bool = false,
+
/// Position Independent Code
force_pic: ?bool = null,
@@ -2661,6 +2669,13 @@ pub const LibExeObjStep = struct {
.paths_first => try zig_args.append("-search_paths_first"),
.dylibs_first => try zig_args.append("-search_dylibs_first"),
};
+ if (self.headerpad_size) |headerpad_size| {
+ const size = try std.fmt.allocPrint(builder.allocator, "{x}", .{headerpad_size});
+ try zig_args.appendSlice(&[_][]const u8{ "-headerpad_size", size });
+ }
+ if (self.headerpad_max_install_names) {
+ try zig_args.append("-headerpad_max_install_names");
+ }
if (self.bundle_compiler_rt) |x| {
if (x) {
src/link/MachO.zig
@@ -69,10 +69,8 @@ page_size: u16,
/// and potentially stage2 release builds in the future.
needs_prealloc: bool = true,
-/// We commit 0x1000 = 4096 bytes of space to the header and
-/// the table of load commands. This should be plenty for any
-/// potential future extensions.
-header_pad: u16 = 0x1000,
+/// Size of the padding between the end of load commands and start of the '__TEXT,__text' section.
+headerpad_size: u64,
/// The absolute address of the entry point.
entry_addr: ?u64 = null,
@@ -295,6 +293,11 @@ pub const min_text_capacity = padToIdeal(minimum_text_block_size);
/// start of __TEXT segment.
const default_pagezero_vmsize: u64 = 0x100000000;
+/// We commit 0x1000 = 4096 bytes of space to the header and
+/// the table of load commands. This should be plenty for any
+/// potential future extensions.
+const default_headerpad_size: u64 = 0x1000;
+
pub const Export = struct {
sym_index: ?u32 = null,
};
@@ -400,6 +403,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
const use_llvm = build_options.have_llvm and options.use_llvm;
const use_stage1 = build_options.is_stage1 and options.use_stage1;
const needs_prealloc = !(use_stage1 or use_llvm or options.cache_mode == .whole);
+ // TODO handle `headerpad_max_install_names` in incremental context
+ const explicit_headerpad_size = options.headerpad_size orelse 0;
+ const headerpad_size = if (needs_prealloc)
+ @maximum(explicit_headerpad_size, default_headerpad_size)
+ else
+ explicit_headerpad_size;
const self = try gpa.create(MachO);
errdefer gpa.destroy(self);
@@ -412,6 +421,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
.file = null,
},
.page_size = page_size,
+ .headerpad_size = headerpad_size,
.code_signature = if (requires_adhoc_codesig) CodeSignature.init(page_size) else null,
.needs_prealloc = needs_prealloc,
};
@@ -976,6 +986,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
.dylibs_first => try argv.append("-search_dylibs_first"),
};
+ if (self.base.options.headerpad_size) |headerpad_size| {
+ try argv.append("-headerpad_size");
+ try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{headerpad_size}));
+ }
+
+ if (self.base.options.headerpad_max_install_names) {
+ try argv.append("-headerpad_max_install_names");
+ }
+
if (self.base.options.entry) |entry| {
try argv.append("-e");
try argv.append(entry);
@@ -4453,7 +4472,7 @@ fn populateMissingMetadata(self: *MachO) !void {
const needed_size = if (self.needs_prealloc) blk: {
const program_code_size_hint = self.base.options.program_code_size_hint;
const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
- const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
+ const ideal_size = self.headerpad_size + program_code_size_hint + got_size_hint;
const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
break :blk needed_size;
@@ -4961,7 +4980,9 @@ fn allocateTextSegment(self: *MachO) !void {
sizeofcmds += lc.cmdsize();
}
- try self.allocateSegment(self.text_segment_cmd_index.?, @sizeOf(macho.mach_header_64) + sizeofcmds);
+ // TODO verify if `headerpad_max_install_names` leads to larger padding size
+ const offset = @sizeOf(macho.mach_header_64) + sizeofcmds + self.headerpad_size;
+ try self.allocateSegment(self.text_segment_cmd_index.?, offset);
// Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
var min_alignment: u32 = 0;
@@ -5088,7 +5109,7 @@ fn initSection(
if (self.needs_prealloc) {
const alignment_pow_2 = try math.powi(u32, 2, alignment);
- const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
+ const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.headerpad_size else null;
const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
sect.segName(),
src/Compilation.zig
@@ -907,6 +907,10 @@ pub const InitOptions = struct {
pagezero_size: ?u64 = null,
/// (Darwin) search strategy for system libraries
search_strategy: ?link.File.MachO.SearchStrategy = null,
+ /// (Darwin) set minimum space for future expansion of the load commands
+ headerpad_size: ?u64 = null,
+ /// (Darwin) set enough space as if all paths were MATPATHLEN
+ headerpad_max_install_names: bool = false,
};
fn addPackageTableToCacheHash(
@@ -1748,6 +1752,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.entitlements = options.entitlements,
.pagezero_size = options.pagezero_size,
.search_strategy = options.search_strategy,
+ .headerpad_size = options.headerpad_size,
+ .headerpad_max_install_names = options.headerpad_max_install_names,
});
errdefer bin_file.destroy();
comp.* = .{
src/link.zig
@@ -193,6 +193,12 @@ pub const Options = struct {
/// (Darwin) search strategy for system libraries
search_strategy: ?File.MachO.SearchStrategy = null,
+ /// (Darwin) set minimum space for future expansion of the load commands
+ headerpad_size: ?u64 = null,
+
+ /// (Darwin) set enough space as if all paths were MATPATHLEN
+ headerpad_max_install_names: bool = false,
+
pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
return if (options.use_lld) .Obj else options.output_mode;
}
src/main.zig
@@ -450,6 +450,8 @@ const usage_build_generic =
\\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
\\ -search_paths_first (Darwin) search each dir in library search paths for `libx.dylib` then `libx.a`
\\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a`
+ \\ -headerpad_size [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation
+ \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN
\\ --import-memory (WebAssembly) import memory from the environment
\\ --import-table (WebAssembly) import function table from the host environment
\\ --export-table (WebAssembly) export function table to the host environment
@@ -699,6 +701,8 @@ fn buildOutputType(
var entitlements: ?[]const u8 = null;
var pagezero_size: ?u64 = null;
var search_strategy: ?link.File.MachO.SearchStrategy = null;
+ var headerpad_size: ?u64 = null;
+ var headerpad_max_install_names: bool = false;
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
// This array is populated by zig cc frontend and then has to be converted to zig-style
@@ -924,6 +928,15 @@ fn buildOutputType(
search_strategy = .paths_first;
} else if (mem.eql(u8, arg, "-search_dylibs_first")) {
search_strategy = .dylibs_first;
+ } else if (mem.eql(u8, arg, "-headerpad_size")) {
+ const next_arg = args_iter.next() orelse {
+ fatal("expected parameter after {s}", .{arg});
+ };
+ headerpad_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
+ fatal("unable to parser '{s}': {s}", .{ arg, @errorName(err) });
+ };
+ } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
+ headerpad_max_install_names = true;
} else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
linker_script = args_iter.next() orelse {
fatal("expected parameter after {s}", .{arg});
@@ -1676,6 +1689,17 @@ fn buildOutputType(
pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
+ } else if (mem.eql(u8, arg, "-headerpad_size")) {
+ i += 1;
+ if (i >= linker_args.items.len) {
+ fatal("expected linker arg after '{s}'", .{arg});
+ }
+ const next_arg = linker_args.items[i];
+ headerpad_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
+ fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
+ };
+ } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
+ headerpad_max_install_names = true;
} else if (mem.eql(u8, arg, "--gc-sections")) {
linker_gc_sections = true;
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
@@ -2795,6 +2819,8 @@ fn buildOutputType(
.entitlements = entitlements,
.pagezero_size = pagezero_size,
.search_strategy = search_strategy,
+ .headerpad_size = headerpad_size,
+ .headerpad_max_install_names = headerpad_max_install_names,
}) catch |err| switch (err) {
error.LibCUnavailable => {
const target = target_info.target;