zig cc: recognize more coff linker options

Related: #7874
This commit is contained in:
Andrew Kelley 2021-01-24 14:30:05 -07:00
parent b56e916fa1
commit 0cfa39304b
4 changed files with 120 additions and 8 deletions

View File

@ -468,6 +468,11 @@ pub const InitOptions = struct {
disable_c_depfile: bool = false,
linker_z_nodelete: bool = false,
linker_z_defs: bool = false,
linker_tsaware: bool = false,
linker_nxcompat: bool = false,
linker_dynamicbase: bool = false,
major_subsystem_version: ?u32 = null,
minor_subsystem_version: ?u32 = null,
clang_passthrough_mode: bool = false,
verbose_cc: bool = false,
verbose_link: bool = false,
@ -1035,6 +1040,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
.z_nodelete = options.linker_z_nodelete,
.z_defs = options.linker_z_defs,
.tsaware = options.linker_tsaware,
.nxcompat = options.linker_nxcompat,
.dynamicbase = options.linker_dynamicbase,
.major_subsystem_version = options.major_subsystem_version,
.minor_subsystem_version = options.minor_subsystem_version,
.stack_size_override = options.stack_size_override,
.image_base_override = options.image_base_override,
.include_compiler_rt = include_compiler_rt,

View File

@ -69,6 +69,9 @@ pub const Options = struct {
rdynamic: bool,
z_nodelete: bool,
z_defs: bool,
tsaware: bool,
nxcompat: bool,
dynamicbase: bool,
bind_global_refs_locally: bool,
is_native_os: bool,
is_native_abi: bool,
@ -88,6 +91,8 @@ pub const Options = struct {
each_lib_rpath: bool,
disable_lld_caching: bool,
is_test: bool,
major_subsystem_version: ?u32,
minor_subsystem_version: ?u32,
gc_sections: ?bool = null,
allow_shlib_undefined: ?bool,
subsystem: ?std.Target.SubSystem,

View File

@ -877,6 +877,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
man.hash.addStringSet(self.base.options.system_libs);
man.hash.addOptional(self.base.options.subsystem);
man.hash.add(self.base.options.is_test);
man.hash.add(self.base.options.tsaware);
man.hash.add(self.base.options.nxcompat);
man.hash.add(self.base.options.dynamicbase);
man.hash.addOptional(self.base.options.major_subsystem_version);
man.hash.addOptional(self.base.options.minor_subsystem_version);
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@ -976,6 +981,26 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
try argv.append("-DLL");
}
if (self.base.options.tsaware) {
try argv.append("-tsaware");
}
if (self.base.options.nxcompat) {
try argv.append("-nxcompat");
}
if (self.base.options.dynamicbase) {
try argv.append("-dynamicbase");
}
const subsystem_suffix = ss: {
if (self.base.options.major_subsystem_version) |major| {
if (self.base.options.minor_subsystem_version) |minor| {
break :ss try allocPrint(arena, ",{d}.{d}", .{ major, minor });
} else {
break :ss try allocPrint(arena, ",{d}", .{major});
}
}
break :ss "";
};
try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path}));
if (self.base.options.link_libc) {
@ -1029,35 +1054,51 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
const mode: Mode = mode: {
if (resolved_subsystem) |subsystem| switch (subsystem) {
.Console => {
try argv.append("-SUBSYSTEM:console");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:console{s}", .{
subsystem_suffix,
}));
break :mode .win32;
},
.EfiApplication => {
try argv.append("-SUBSYSTEM:efi_application");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_application{s}", .{
subsystem_suffix,
}));
break :mode .uefi;
},
.EfiBootServiceDriver => {
try argv.append("-SUBSYSTEM:efi_boot_service_driver");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_boot_service_driver{s}", .{
subsystem_suffix,
}));
break :mode .uefi;
},
.EfiRom => {
try argv.append("-SUBSYSTEM:efi_rom");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_rom{s}", .{
subsystem_suffix,
}));
break :mode .uefi;
},
.EfiRuntimeDriver => {
try argv.append("-SUBSYSTEM:efi_runtime_driver");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:efi_runtime_driver{s}", .{
subsystem_suffix,
}));
break :mode .uefi;
},
.Native => {
try argv.append("-SUBSYSTEM:native");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:native{s}", .{
subsystem_suffix,
}));
break :mode .win32;
},
.Posix => {
try argv.append("-SUBSYSTEM:posix");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:posix{s}", .{
subsystem_suffix,
}));
break :mode .win32;
},
.Windows => {
try argv.append("-SUBSYSTEM:windows");
try argv.append(try allocPrint(arena, "-SUBSYSTEM:windows{s}", .{
subsystem_suffix,
}));
break :mode .win32;
},
} else if (target.os.tag == .uefi) {

View File

@ -529,6 +529,9 @@ fn buildOutputType(
var linker_bind_global_refs_locally: ?bool = null;
var linker_z_nodelete = false;
var linker_z_defs = false;
var linker_tsaware = false;
var linker_nxcompat = false;
var linker_dynamicbase = false;
var test_evented_io = false;
var stack_size_override: ?u64 = null;
var image_base_override: ?u64 = null;
@ -549,6 +552,8 @@ fn buildOutputType(
var main_pkg_path: ?[]const u8 = null;
var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
var subsystem: ?std.Target.SubSystem = null;
var major_subsystem_version: ?u32 = null;
var minor_subsystem_version: ?u32 = null;
var system_libs = std.ArrayList([]const u8).init(gpa);
defer system_libs.deinit();
@ -1307,10 +1312,56 @@ fn buildOutputType(
image_base_override = std.fmt.parseUnsigned(u64, linker_args.items[i], 0) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
} else if (mem.eql(u8, arg, "-T")) {
i += 1;
if (i >= linker_args.items.len) {
fatal("expected linker arg after '{s}'", .{arg});
}
linker_script = linker_args.items[i];
} else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
link_eh_frame_hdr = true;
} else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
link_eh_frame_hdr = false;
} else if (mem.eql(u8, arg, "--tsaware")) {
linker_tsaware = true;
} else if (mem.eql(u8, arg, "--nxcompat")) {
linker_nxcompat = true;
} else if (mem.eql(u8, arg, "--dynamicbase")) {
linker_dynamicbase = true;
} else if (mem.eql(u8, arg, "--high-entropy-va")) {
// This option does not do anything.
} else if (mem.eql(u8, arg, "--export-all-symbols")) {
rdynamic = true;
} else if (mem.eql(u8, arg, "--start-group") or
mem.eql(u8, arg, "--end-group"))
{
// We don't need to care about these because these args are
// for resolving circular dependencies but our linker takes
// care of this without explicit args.
} else if (mem.startsWith(u8, arg, "--major-os-version") or
mem.startsWith(u8, arg, "--minor-os-version"))
{
// This option does not do anything.
} else if (mem.startsWith(u8, arg, "--major-subsystem-version=")) {
major_subsystem_version = std.fmt.parseUnsigned(
u32,
arg["--major-subsystem-version=".len..],
10,
) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
} else if (mem.startsWith(u8, arg, "--minor-subsystem-version=")) {
minor_subsystem_version = std.fmt.parseUnsigned(
u32,
arg["--minor-subsystem-version=".len..],
10,
) catch |err| {
fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
};
} else if (mem.startsWith(u8, arg, "--major-os-version=") or
mem.startsWith(u8, arg, "--minor-os-version="))
{
// These args do nothing.
} else {
warn("unsupported linker arg: {s}", .{arg});
}
@ -1800,6 +1851,11 @@ fn buildOutputType(
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
.linker_z_nodelete = linker_z_nodelete,
.linker_z_defs = linker_z_defs,
.linker_tsaware = linker_tsaware,
.linker_nxcompat = linker_nxcompat,
.linker_dynamicbase = linker_dynamicbase,
.major_subsystem_version = major_subsystem_version,
.minor_subsystem_version = minor_subsystem_version,
.link_eh_frame_hdr = link_eh_frame_hdr,
.link_emit_relocs = link_emit_relocs,
.stack_size_override = stack_size_override,