From d5233ee85ce13cba3dd03e4c0c938cee193b9b19 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 25 Aug 2022 12:38:56 +0200 Subject: [PATCH] add ability to pass force undefined symbols to the linker This commit enables `-u ` for ELF and `-include:` for COFF linkers for use internally. This means we do not expose these flags to the users just yet, however, we make use of them internally whenever required. One such use case is forcing inclusion of `_tls_index` when linking for Windows with mingw and LTO and dead code stripping enabled. This ensures we add `_tls_index` to the symbol resolver as an undefined symbol and force the linker to include an atom that provides it marking it a dead-code-stripping root - meaning it will not be garbage collected by the linker no matter what. --- src/Compilation.zig | 8 +++++--- src/link.zig | 6 ++++++ src/link/Coff.zig | 4 ++++ src/link/Elf.zig | 5 +++++ src/mingw.zig | 6 ------ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 03d7962ccc771bb412f0d1c72fe7e5074fb354f5..353a2f1ca3492899f3d724092b45d869603f64eb 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1165,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { break :blk false; } else if (options.c_source_files.len == 0) { break :blk false; - } else if (options.target.os.tag == .windows and link_libcpp) { - // https://github.com/ziglang/zig/issues/8531 - break :blk false; } else if (options.target.cpu.arch.isRISCV()) { // Clang and LLVM currently don't support RISC-V target-abi for LTO. // Compiling with LTO may fail or produce undesired results. @@ -1793,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .headerpad_size = options.headerpad_size, .headerpad_max_install_names = options.headerpad_max_install_names, .dead_strip_dylibs = options.dead_strip_dylibs, + .force_undefined_symbols = .{}, }); errdefer bin_file.destroy(); comp.* = .{ @@ -1943,6 +1941,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { for (mingw.always_link_libs) |name| { try comp.bin_file.options.system_libs.put(comp.gpa, name, .{}); } + + // LLD might drop some symbols as unused during LTO and GCing, therefore, + // we force mark them for resolution here. + try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, "_tls_index", {}); } // Generate Windows import libs. if (target.os.tag == .windows) { diff --git a/src/link.zig b/src/link.zig index a85969d61eb7bf6d9f30f79c4caabe00e2dc1737..b46ea51013b7957684bf8d9d8e650dbac0d2fce9 100644 --- a/src/link.zig +++ b/src/link.zig @@ -175,6 +175,12 @@ pub const Options = struct { lib_dirs: []const []const u8, rpath_list: []const []const u8, + /// List of symbols forced as undefined in the symbol table + /// thus forcing their resolution by the linker. + /// Corresponds to `-u ` for ELF and `/include:` for COFF/PE. + /// TODO add handling for MachO. + force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), + version: ?std.builtin.Version, compatibility_version: ?std.builtin.Version, libc_installation: ?*const LibCInstallation, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 6536fbd1ace38753f65630f0f07bd7f436ed04f0..c30544d3b7c7296dfdbf86c192fb5707c9b2f11f 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1133,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) ! } } + for (self.base.options.force_undefined_symbols.keys()) |symbol| { + try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol})); + } + if (is_dyn_lib) { try argv.append("-DLL"); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ade4f62f91e21e2a1e8fd366316f9f6496089418..293771dd2a8fcc83fc889f66b83e7b0729788a4b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append(entry); } + for (self.base.options.force_undefined_symbols.keys()) |symbol| { + try argv.append("-u"); + try argv.append(symbol); + } + switch (self.base.options.hash_style) { .gnu => try argv.append("--hash-style=gnu"), .sysv => try argv.append("--hash-style=sysv"), diff --git a/src/mingw.zig b/src/mingw.zig index e99a1af8fc6b5a72b5b4693fea629929275916df..b50cc4b00994b102853e3d1f4c7c128f53e95bff 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { "-D_WIN32_WINNT=0x0f00", "-D__MSVCRT_VERSION__=0x700", }); - if (std.mem.eql(u8, dep, "tlssup.c") and comp.bin_file.options.lto) { - // LLD will incorrectly drop the `_tls_index` symbol. Here we work - // around it by not using LTO for this one file. - // https://github.com/ziglang/zig/issues/8531 - try args.append("-fno-lto"); - } c_source_files[i] = .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "crt", dep, -- 2.54.0