mirror of
https://github.com/ziglang/zig.git
synced 2024-11-28 08:02:32 +00:00
macho: implement -headerpad_size option
Includes both traditiona and incremental codepaths with one caveat that in incremental case, the requested size cannot be smaller than the default padding size due to prealloc required due to incremental nature of linking. Also parse `-headerpad_max_install_names`, however, not actionable just yet - missing implementation.
This commit is contained in:
parent
f91503e577
commit
8c1feef4cd
@ -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) {
|
||||
|
@ -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.* = .{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(),
|
||||
|
26
src/main.zig
26
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;
|
||||
|
Loading…
Reference in New Issue
Block a user