Commit 6ad92108e2

Frank Denis <github@pureftpd.org>
2023-01-05 21:21:29
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
1 parent c28c38d
Changed files (5)
lib/std/build/LibExeObjStep.zig
@@ -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");
src/link/Elf.zig
@@ -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".
src/Compilation.zig
@@ -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);
src/link.zig
@@ -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,
src/main.zig
@@ -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,