ELF linker: support common-page-size and max-page-size lld opts

These linker flags are required to build static ELF binaries that
can run under the Blink emulator:

https://github.com/jart/blink/issues/14
This commit is contained in:
Frank Denis 2023-01-05 21:21:29 +01:00 committed by Andrew Kelley
parent c28c38d1e5
commit 6ad92108e2
5 changed files with 46 additions and 0 deletions

View File

@ -155,6 +155,12 @@ link_z_relro: bool = true,
/// Allow relocations to be lazily processed after load.
link_z_lazy: bool = false,
/// Common page size
link_z_common_page_size: ?u64 = null,
/// Maximum page size
link_z_max_page_size: ?u64 = null,
/// (Darwin) Install name for the dylib
install_name: ?[]const u8 = null,
@ -1338,6 +1344,14 @@ fn make(step: *Step) !void {
try zig_args.append("-z");
try zig_args.append("lazy");
}
if (self.link_z_common_page_size) |size| {
try zig_args.append("-z");
try zig_args.append(builder.fmt("common-page-size={d}", .{size}));
}
if (self.link_z_max_page_size) |size| {
try zig_args.append("-z");
try zig_args.append(builder.fmt("max-page-size={d}", .{size}));
}
if (self.libc_file) |libc_file| {
try zig_args.append("--libc");

View File

@ -979,6 +979,8 @@ pub const InitOptions = struct {
linker_z_now: bool = true,
linker_z_relro: bool = true,
linker_z_nocopyreloc: bool = false,
linker_z_common_page_size: ?u64 = null,
linker_z_max_page_size: ?u64 = null,
linker_tsaware: bool = false,
linker_nxcompat: bool = false,
linker_dynamicbase: bool = false,
@ -1842,6 +1844,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.z_nocopyreloc = options.linker_z_nocopyreloc,
.z_now = options.linker_z_now,
.z_relro = options.linker_z_relro,
.z_common_page_size = options.linker_z_common_page_size,
.z_max_page_size = options.linker_z_max_page_size,
.tsaware = options.linker_tsaware,
.nxcompat = options.linker_nxcompat,
.dynamicbase = options.linker_dynamicbase,
@ -2637,6 +2641,8 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
man.hash.add(comp.bin_file.options.z_nocopyreloc);
man.hash.add(comp.bin_file.options.z_now);
man.hash.add(comp.bin_file.options.z_relro);
man.hash.add(comp.bin_file.options.z_common_page_size orelse 0);
man.hash.add(comp.bin_file.options.z_max_page_size orelse 0);
man.hash.add(comp.bin_file.options.hash_style);
man.hash.add(comp.bin_file.options.compress_debug_sections);
man.hash.add(comp.bin_file.options.include_compiler_rt);

View File

@ -121,6 +121,8 @@ pub const Options = struct {
z_nocopyreloc: bool,
z_now: bool,
z_relro: bool,
z_common_page_size: ?u64,
z_max_page_size: ?u64,
tsaware: bool,
nxcompat: bool,
dynamicbase: bool,

View File

@ -1390,6 +1390,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
man.hash.add(self.base.options.z_nocopyreloc);
man.hash.add(self.base.options.z_now);
man.hash.add(self.base.options.z_relro);
man.hash.add(self.base.options.z_common_page_size orelse 0);
man.hash.add(self.base.options.z_max_page_size orelse 0);
man.hash.add(self.base.options.hash_style);
// strip does not need to go into the linker hash because it is part of the hash namespace
if (self.base.options.link_libc) {
@ -1594,6 +1596,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
// LLD defaults to -zrelro
try argv.append("-znorelro");
}
if (self.base.options.z_common_page_size) |size| {
try argv.append("-z");
try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size}));
}
if (self.base.options.z_max_page_size) |size| {
try argv.append("-z");
try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size}));
}
if (getLDMOption(target)) |ldm| {
// Any target ELF will use the freebsd osabi if suffixed with "_fbsd".

View File

@ -495,6 +495,8 @@ const usage_build_generic =
\\ lazy Don't force all relocations to be processed on load
\\ relro (default) Force all relocations to be read-only after processing
\\ norelro Don't force all relocations to be read-only after processing
\\ common-page-size=[bytes] Set the common page size for ELF binaries
\\ max-page-size=[bytes] Set the max page size for ELF binaries
\\ -dynamic Force output to be dynamically linked
\\ -static Force output to be statically linked
\\ -Bsymbolic Bind global references locally
@ -744,6 +746,8 @@ fn buildOutputType(
var linker_z_origin = false;
var linker_z_now = true;
var linker_z_relro = true;
var linker_z_common_page_size: ?u64 = null;
var linker_z_max_page_size: ?u64 = null;
var linker_tsaware = false;
var linker_nxcompat = false;
var linker_dynamicbase = false;
@ -1325,6 +1329,10 @@ fn buildOutputType(
linker_z_relro = true;
} else if (mem.eql(u8, z_arg, "norelro")) {
linker_z_relro = false;
} else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
} else {
warn("unsupported linker extension flag: -z {s}", .{z_arg});
}
@ -1923,6 +1931,10 @@ fn buildOutputType(
stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
fatal("unable to parse stack size '{s}': {s}", .{ next_arg, @errorName(err) });
};
} else if (mem.startsWith(u8, z_arg, "common-page-size=")) {
linker_z_common_page_size = parseIntSuffix(z_arg, "common-page-size=".len);
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
} else {
warn("unsupported linker extension flag: -z {s}", .{z_arg});
}
@ -3042,6 +3054,8 @@ fn buildOutputType(
.linker_z_origin = linker_z_origin,
.linker_z_now = linker_z_now,
.linker_z_relro = linker_z_relro,
.linker_z_common_page_size = linker_z_common_page_size,
.linker_z_max_page_size = linker_z_max_page_size,
.linker_tsaware = linker_tsaware,
.linker_nxcompat = linker_nxcompat,
.linker_dynamicbase = linker_dynamicbase,