authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-25 12:38:56+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-25 16:23:01-04:00
logd5233ee85ce13cba3dd03e4c0c938cee193b9b19
tree3824be936b8854e15916159dd8eb5636fd84168c
parentba346ecfe9b8ee246e084183f34fa9ed941f9fa3

add ability to pass force undefined symbols to the linker

This commit enables `-u <symbol>` for ELF and `-include:<symbol>` 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.

5 files changed, 20 insertions(+), 9 deletions(-)

src/Compilation.zig+5-3
...@@ -1165,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1165,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1165 break :blk false;1165 break :blk false;
1166 } else if (options.c_source_files.len == 0) {1166 } else if (options.c_source_files.len == 0) {
1167 break :blk false;1167 break :blk false;
1168 } else if (options.target.os.tag == .windows and link_libcpp) {
1169 // https://github.com/ziglang/zig/issues/8531
1170 break :blk false;
1171 } else if (options.target.cpu.arch.isRISCV()) {1168 } else if (options.target.cpu.arch.isRISCV()) {
1172 // Clang and LLVM currently don't support RISC-V target-abi for LTO.1169 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
1173 // Compiling with LTO may fail or produce undesired results.1170 // Compiling with LTO may fail or produce undesired results.
...@@ -1793,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1793,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1793 .headerpad_size = options.headerpad_size,1790 .headerpad_size = options.headerpad_size,
1794 .headerpad_max_install_names = options.headerpad_max_install_names,1791 .headerpad_max_install_names = options.headerpad_max_install_names,
1795 .dead_strip_dylibs = options.dead_strip_dylibs,1792 .dead_strip_dylibs = options.dead_strip_dylibs,
1793 .force_undefined_symbols = .{},
1796 });1794 });
1797 errdefer bin_file.destroy();1795 errdefer bin_file.destroy();
1798 comp.* = .{1796 comp.* = .{
...@@ -1943,6 +1941,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1943,6 +1941,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1943 for (mingw.always_link_libs) |name| {1941 for (mingw.always_link_libs) |name| {
1944 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});1942 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});
1945 }1943 }
1944
1945 // LLD might drop some symbols as unused during LTO and GCing, therefore,
1946 // we force mark them for resolution here.
1947 try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, "_tls_index", {});
1946 }1948 }
1947 // Generate Windows import libs.1949 // Generate Windows import libs.
1948 if (target.os.tag == .windows) {1950 if (target.os.tag == .windows) {
src/link.zig+6
...@@ -175,6 +175,12 @@ pub const Options = struct {...@@ -175,6 +175,12 @@ pub const Options = struct {
175 lib_dirs: []const []const u8,175 lib_dirs: []const []const u8,
176 rpath_list: []const []const u8,176 rpath_list: []const []const u8,
177177
178 /// List of symbols forced as undefined in the symbol table
179 /// thus forcing their resolution by the linker.
180 /// Corresponds to `-u <symbol>` for ELF and `/include:<symbol>` for COFF/PE.
181 /// TODO add handling for MachO.
182 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
183
178 version: ?std.builtin.Version,184 version: ?std.builtin.Version,
179 compatibility_version: ?std.builtin.Version,185 compatibility_version: ?std.builtin.Version,
180 libc_installation: ?*const LibCInstallation,186 libc_installation: ?*const LibCInstallation,
src/link/Coff.zig+4
...@@ -1133,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -1133,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
1133 }1133 }
1134 }1134 }
11351135
1136 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1137 try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
1138 }
1139
1136 if (is_dyn_lib) {1140 if (is_dyn_lib) {
1137 try argv.append("-DLL");1141 try argv.append("-DLL");
1138 }1142 }
src/link/Elf.zig+5
...@@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1448 try argv.append(entry);1448 try argv.append(entry);
1449 }1449 }
14501450
1451 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1452 try argv.append("-u");
1453 try argv.append(symbol);
1454 }
1455
1451 switch (self.base.options.hash_style) {1456 switch (self.base.options.hash_style) {
1452 .gnu => try argv.append("--hash-style=gnu"),1457 .gnu => try argv.append("--hash-style=gnu"),
1453 .sysv => try argv.append("--hash-style=sysv"),1458 .sysv => try argv.append("--hash-style=sysv"),
src/mingw.zig-6
...@@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
93 "-D_WIN32_WINNT=0x0f00",93 "-D_WIN32_WINNT=0x0f00",
94 "-D__MSVCRT_VERSION__=0x700",94 "-D__MSVCRT_VERSION__=0x700",
95 });95 });
96 if (std.mem.eql(u8, dep, "tlssup.c") and comp.bin_file.options.lto) {
97 // LLD will incorrectly drop the `_tls_index` symbol. Here we work
98 // around it by not using LTO for this one file.
99 // https://github.com/ziglang/zig/issues/8531
100 try args.append("-fno-lto");
101 }
102 c_source_files[i] = .{96 c_source_files[i] = .{
103 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{97 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
104 "libc", "mingw", "crt", dep,98 "libc", "mingw", "crt", dep,