Commit 20cc7af8e6

Andrew Kelley <andrew@ziglang.org>
2021-11-25 02:35:37
stage2: support LLD -O flags on ELF
In 7e23b3245a9bf6e002009e6c18c10a9995671afa I made -O flags to the linker emit a warning that the argument does nothing. That was not correct however; LLD does have some logic that does different things depending on -O0, -O1, and -O2. It defaults to -O1, and it does less optimizations with -O0 and more with -O2. With this commit, e.g. `-Wl,-O1` is supported by the `zig cc` frontend, and by default we pass `-O0` to LLD in debug mode, and `-O3` in release modes. I also fixed a bug in the LLD ELF linker line which was incorrectly passing `-O` flags instead of `--lto-O` flags for LTO.
1 parent 27c5c7f
Changed files (5)
src
test
standalone
install_raw_hex
src/link/Elf.zig
@@ -1349,6 +1349,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         man.hash.add(self.base.options.bind_global_refs_locally);
         man.hash.add(self.base.options.tsan);
         man.hash.addOptionalBytes(self.base.options.sysroot);
+        man.hash.add(self.base.options.linker_optimization);
 
         // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
         _ = try man.hit();
@@ -1425,10 +1426,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         if (self.base.options.lto) {
             switch (self.base.options.optimize_mode) {
                 .Debug => {},
-                .ReleaseSmall => try argv.append("-O2"),
-                .ReleaseFast, .ReleaseSafe => try argv.append("-O3"),
+                .ReleaseSmall => try argv.append("--lto-O2"),
+                .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"),
             }
         }
+        try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{
+            self.base.options.linker_optimization,
+        }));
 
         if (self.base.options.output_mode == .Exe) {
             try argv.append("-z");
src/Compilation.zig
@@ -736,6 +736,7 @@ pub const InitOptions = struct {
     linker_tsaware: bool = false,
     linker_nxcompat: bool = false,
     linker_dynamicbase: bool = false,
+    linker_optimization: ?u8 = null,
     major_subsystem_version: ?u32 = null,
     minor_subsystem_version: ?u32 = null,
     clang_passthrough_mode: bool = false,
@@ -1140,6 +1141,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
         const strip = options.strip or !target_util.hasDebugInfo(options.target);
         const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target);
         const omit_frame_pointer = options.omit_frame_pointer orelse (options.optimize_mode != .Debug);
+        const linker_optimization: u8 = options.linker_optimization orelse switch (options.optimize_mode) {
+            .Debug => @as(u8, 0),
+            else => @as(u8, 3),
+        };
 
         // We put everything into the cache hash that *cannot be modified during an incremental update*.
         // For example, one cannot change the target between updates, but one can change source files,
@@ -1450,6 +1455,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .tsaware = options.linker_tsaware,
             .nxcompat = options.linker_nxcompat,
             .dynamicbase = options.linker_dynamicbase,
+            .linker_optimization = linker_optimization,
             .major_subsystem_version = options.major_subsystem_version,
             .minor_subsystem_version = options.minor_subsystem_version,
             .stack_size_override = options.stack_size_override,
src/link.zig
@@ -99,6 +99,7 @@ pub const Options = struct {
     tsaware: bool,
     nxcompat: bool,
     dynamicbase: bool,
+    linker_optimization: u8,
     bind_global_refs_locally: bool,
     import_memory: bool,
     initial_memory: ?u64,
src/main.zig
@@ -635,6 +635,7 @@ fn buildOutputType(
     var linker_tsaware = false;
     var linker_nxcompat = false;
     var linker_dynamicbase = false;
+    var linker_optimization: ?u8 = null;
     var test_evented_io = false;
     var test_no_exec = false;
     var stack_size_override: ?u64 = null;
@@ -1488,11 +1489,13 @@ fn buildOutputType(
                     if (i >= linker_args.items.len) {
                         fatal("expected linker arg after '{s}'", .{arg});
                     }
-                    warn("ignoring linker arg -O{s} because it does nothing", .{
-                        linker_args.items[i],
-                    });
+                    linker_optimization = std.fmt.parseUnsigned(u8, linker_args.items[i], 10) catch |err| {
+                        fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
+                    };
                 } else if (mem.startsWith(u8, arg, "-O")) {
-                    warn("ignoring linker arg {s} because it does nothing", .{arg});
+                    linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| {
+                        fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
+                    };
                 } else if (mem.eql(u8, arg, "--gc-sections")) {
                     linker_gc_sections = true;
                 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
@@ -2309,6 +2312,7 @@ fn buildOutputType(
         .linker_tsaware = linker_tsaware,
         .linker_nxcompat = linker_nxcompat,
         .linker_dynamicbase = linker_dynamicbase,
+        .linker_optimization = linker_optimization,
         .major_subsystem_version = major_subsystem_version,
         .minor_subsystem_version = minor_subsystem_version,
         .link_eh_frame_hdr = link_eh_frame_hdr,
test/standalone/install_raw_hex/build.zig
@@ -35,7 +35,7 @@ pub fn build(b: *Builder) void {
         ":1001140000000000000000000000000000000000DB",
         ":1001240000000000000000000000000000000000CB",
         ":1001340000000000000000000000000000000000BB",
-        ":10014400830202006C020100090000002102010088",
+        ":1001440083020200F401010009000000FE01010025",
         ":100154000900000001000000000000000000000091",
         ":1001640000080002008001010004000010000000EB",
         ":100174000000000000000000000000001F0000005C",
@@ -44,17 +44,17 @@ pub fn build(b: *Builder) void {
         ":1001A40000000000000000001F000000000000002C",
         ":1001B400000000000000000000000000000000003B",
         ":1001C400000000000000000000000000000000002B",
-        ":1001D4005B02010010000000F40101002C0000008B",
-        ":1001E4003F0201001B0000002B020100130000006D",
-        ":1001F40072656D61696E646572206469766973699C",
-        ":100204006F6E206279207A65726F206F72206E653E",
-        ":100214006761746976652076616C756500636F72D9",
-        ":100224007465782D6D3400696E646578206F75741B",
-        ":10023400206F6620626F756E647300696E74656703",
-        ":1002440065722063617374207472756E6361746582",
-        ":10025400642062697473006469766973696F6E20DF",
-        ":100264006279207A65726F00636F727465785F6D6E",
-        ":100274003400000081B00091FFE700BEFDE7D0B577",
+        ":1001D4000802010010000000190201002C000000B8",
+        ":1001E400460201001B00000062020100130000002F",
+        ":1001F400636F727465785F6D3400636F72746578D1",
+        ":100204002D6D34006469766973696F6E206279209C",
+        ":100214007A65726F0072656D61696E6465722064DF",
+        ":1002240069766973696F6E206279207A65726F20CE",
+        ":100234006F72206E656761746976652076616C758E",
+        ":100244006500696E746567657220636173742074F8",
+        ":1002540072756E6361746564206269747300696E9B",
+        ":10026400646578206F7574206F6620626F756E64A4",
+        ":100274007300000081B00091FFE700BEFDE7D0B538",
         ":1002840002AF90B00391029007A800F029F80399F7",
         ":100294000020069048680490FFE7049906980190AE",
         ":1002A40088420FD2FFE7019903980068405C07F881",
@@ -89,7 +89,7 @@ pub fn build(b: *Builder) void {
         ":1001140000000000000000000000000000000000DB",
         ":1001240000000000000000000000000000000000CB",
         ":1001340000000000000000000000000000000000BB",
-        ":10014400830202006C020100090000002102010088",
+        ":1001440083020200F401010009000000FE01010025",
         ":100154000900000001000000000000000000000091",
         ":1001640000080002008001010004000010000000EB",
         ":100174000000000000000000000000001F0000005C",
@@ -98,17 +98,17 @@ pub fn build(b: *Builder) void {
         ":1001A40000000000000000001F000000000000002C",
         ":1001B400000000000000000000000000000000003B",
         ":1001C400000000000000000000000000000000002B",
-        ":1001D4005B02010010000000F40101002C0000008B",
-        ":1001E4003F0201001B0000002B020100130000006D",
-        ":1001F40072656D61696E646572206469766973699C",
-        ":100204006F6E206279207A65726F206F72206E653E",
-        ":100214006761746976652076616C756500636F72D9",
-        ":100224007465782D6D3400696E646578206F75741B",
-        ":10023400206F6620626F756E647300696E74656703",
-        ":1002440065722063617374207472756E6361746582",
-        ":10025400642062697473006469766973696F6E20DF",
-        ":100264006279207A65726F00636F727465785F6D6E",
-        ":100274003400000081B00091FFE700BEFDE7D0B577",
+        ":1001D4000802010010000000190201002C000000B8",
+        ":1001E400460201001B00000062020100130000002F",
+        ":1001F400636F727465785F6D3400636F72746578D1",
+        ":100204002D6D34006469766973696F6E206279209C",
+        ":100214007A65726F0072656D61696E6465722064DF",
+        ":1002240069766973696F6E206279207A65726F20CE",
+        ":100234006F72206E656761746976652076616C758E",
+        ":100244006500696E746567657220636173742074F8",
+        ":1002540072756E6361746564206269747300696E9B",
+        ":10026400646578206F7574206F6620626F756E64A4",
+        ":100274007300000081B00091FFE700BEFDE7D0B538",
         ":1002840002AF90B00391029007A800F029F80399F7",
         ":100294000020069048680490FFE7049906980190AE",
         ":1002A40088420FD2FFE7019903980068405C07F881",