zig
zig copied to clipboard
LLD with LTO enabled incorrectly drops _tls_index symbol, causing undefined reference errors
I have reduced this error to this minimal example:
main.zig:
const std = @import("std");
const c = @cImport({
@cInclude("test.h");
});
pub fn main() !void {
const num = c.getNum();
std.debug.print("Num: {}!", .{num});
}
test.h:
int getNum(void);
test.c:
int getNum(void) {
return 3;
}
Build command: zig build-exe main.zig test.c -I.
Error:
lld-link: warning: ignoring debug info with an invalid version (0) in zig-cache\o\ee8a465508ce3f1d05048c0482c74ec9\main.obj
lld-link: error: undefined symbol: _tls_index
>>> referenced by main.exe.lto.obj:(std.debug.panicExtra)
>>> referenced by main.exe.lto.obj:(std.debug.panicExtra)
>>> referenced by main.exe.lto.obj:(std.debug.panicExtra)
error: LLDReportedFailure
This error does not occur in Debug or other release modes or when not using C source files.
Thank you for your help.
bisected to 0d4b6ac7417d1094ac972981b0241444ce2380ba (when LTO was enabled by default)
(and, indeed, compiling with "-fno-lto" links successfully.)
moreover:
removing -OPT:lldlto=3 from the linker command line
lld-link -ERRORLIMIT:0 -NOLOGO -DEBUG -OPT:lldlto=3 -STACK:16777216 -MACHINE:X64 [...]
still fails.
But if I do:
zig build-exe main.zig test.c -lc -target x86_64-windows-gnu -OReleaseFast -fno-lto --verbose-link(1) -> succeedszig build-exe main.zig test.c -lc -target x86_64-windows-gnu -OReleaseFast -flto --verbose-link(2) -> fails- And then I take the lld-link command from (2) and only change the
mingw32.libfile to use the one from (1) -> succeeds.
It looks like undefined symbol (_tls_index) comes from std.debug.panicExtra. When I do not call panic() in my program it links correctly even with LTO. When I call panic (everything else stays the same) I get:
PS C:\Development\projects\zig-gamedev\samples\triangle1> zig build run -Drelease-fast=true lld-link: warning: ignoring debug info with an invalid version (0) in C:\Development\projects\zig-gamedev\samples\triangle1\zig-cache\o\97e13fadba1c57b3f280b218317fa311\triangle1.obj lld-link: error: undefined symbol: _tls_index referenced by C:\Development\projects\zig-gamedev\samples\triangle1\zig-cache\o\97e13fadba1c57b3f280b218317fa311\triangle1.exe.lto.obj:(std.debug.panicExtra.43)
I looked into this today. The problem is that LLD is deleting the _tls_index symbol even though there are references to it. This is a bug in LLD. Thank you to @xxxbxxx for the workaround in #8674. However this issue will remain open until the workaround is removed. The next step is to file a bug report upstream for LLD. This issue will remain open to track the upstream bug report.
Alternatively, if Zig's self-hosted COFF linker catches up to LLD (including LTO), and does not have this issue, then we can close it.
Related problem:
LTO on Windows when using iostream causes this problem:
lld-link: error: undefined symbol: __declspec(dllimport) _create_locale
>>> referenced by /home/andy/Downloads/zig/test/standalone/c_compiler/zig-cache/o/3e7e3316fe912a4cafa8cc2731441c56/test_cpp.exe.lto.obj:(std::__1::DoIOSInit::DoIOSInit())
>>> referenced by /home/andy/Downloads/zig/test/standalone/c_compiler/zig-cache/o/3e7e3316fe912a4cafa8cc2731441c56/test_cpp.exe.lto.obj:(std::__1::__cloc())
lld-link: error: undefined symbol: __declspec(dllimport) _free_locale
>>> referenced by /home/andy/Downloads/zig/test/standalone/c_compiler/zig-cache/o/3e7e3316fe912a4cafa8cc2731441c56/test_cpp.exe.lto.obj:(std::__1::DoIOSInit::DoIOSInit())
>>> referenced by /home/andy/Downloads/zig/test/standalone/c_compiler/zig-cache/o/3e7e3316fe912a4cafa8cc2731441c56/test_cpp.exe.lto.obj:(std::__1::__time_put::~__time_put())
>>> referenced by /home/andy/Downloads/zig/test/standalone/c_compiler/zig-cache/o/3e7e3316fe912a4cafa8cc2731441c56/test_cpp.exe.lto.obj:(std::__1::codecvt<wchar_t, char, int>::~codecvt())
Can be observed by changing false to true here:
https://github.com/ziglang/zig/blob/fb99808008f2ad67122b26c0ad31ca6a0c2456cc/test/standalone/c_compiler/build.zig#L37
I think we need to disable LTO by default until these issues can be worked out. Related: #9844
I will re-open for the time being until I investigate an issue reported by @rtldg in PR #12631:
I feel bad about posting on this since I'm using Zig as a cross-compiler for Rust, but this seems to be causing my builds to fail with lld-link: error: <root>: undefined symbol: _tls_index. Defining the variable _tls_index instead causes things like this
lld-link: error: duplicate symbol: __tls_index
>>> defined at testcpp.lib(test.o)
>>> defined at mingw32.lib(tlssup.obj)
One of the old zig versions I was using did compile & link my projects fine so this pr seems to be where the undefined symbol stuff started.
(zig-windows-x86_64-0.10.0-dev.3602+df507edff from 2022-08-18)
Also an example project of this where I'm using cargo-zigbuild which acts as a wrapper for cross-compiling along with the i686-pc-windows-gnu toolchain for Rust.
Just wondering if I should post this elsewhere for help.
I have the same problem when I'm cross-compiling DuckDB from Ubuntu 22.04.1/WSL with zig build -Drelease-fast -Dtarget=x86_64-windows-gnu. My zig version is 0.10.0-dev.4247+3234e8de3 revision 5764 via snap and with previous versions I didn't have any problem but now I will get the following error messages:
LLD Link... lld-link: error: undefined symbol: __declspec(dllimport) _create_locale
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::__cloc())
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::DoIOSInit::DoIOSInit())
lld-link: error: undefined symbol: __declspec(dllimport) _free_locale
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::__time_put::~__time_put())
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::codecvt<wchar_t, char, int>::~codecvt())
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::DoIOSInit::DoIOSInit())
lld-link: error: undefined symbol: __declspec(dllimport) rand_s
>>> referenced by /home/kimmo/duckdb-zig-build/zig-cache/o/72ea7a324da959e6bd5a316e3ca95f9f/duckdb.exe.lto.obj:(std::__1::random_device::operator()())
And when I'm compiling in Ubuntu zig build -Drelease-fast I will get a couple of warnings which I didn't get earlier:
LLD Link... warning(link): unexpected LLD stderr:
ld.lld: warning: /home/kimmo/duckdb-zig-build/zig-cache/o/5208cc9f7b021f0408edd11ea1860d9e/libsqlite_api.a: archive member '/home/kimmo/duckdb-zig-build/zig-cache/o/82aef94128cf22e4fc9cc80ce2dcdf76/libduckdb_static.a' is neither ET_REL nor LLVM bitcode
ld.lld: warning: /home/kimmo/duckdb-zig-build/zig-cache/o/5208cc9f7b021f0408edd11ea1860d9e/libsqlite_api.a: archive member '/home/kimmo/duckdb-zig-build/zig-cache/o/985183138eeb191e1a0ce14167cfbb63/libutf8proc.a' is neither ET_REL nor LLVM bitcode
little test with master, (after https://github.com/ziglang/zig/pull/12631)
pub fn main() !void { }
zig build-exe repro.zig -target x86_64-windows-gnu -flto
->
LLD Link... lld-link: error: undefined symbol: _tls_index
>>> referenced by /var/home/xavier/src/zig/build15/stage3/lib/std/debug.zig:337
>>> repro.exe.lto.obj:(std.debug.panicImpl)
>>> referenced by /var/home/xavier/src/zig/build15/stage3/lib/std/debug.zig:339
>>> repro.exe.lto.obj:(std.debug.panicImpl)
>>> referenced by /var/home/xavier/src/zig/build15/stage3/lib/std/debug.zig:374
>>> repro.exe.lto.obj:(std.debug.panicImpl)
(the eror lines are usages of panic_stage, declared as threadlocal var panic_stage: usize = 0; )
@kubkon maybe the symbol forcing should also be done when not linking libc?
something like this?
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 7c4c369a6..a3f341c10 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -2011,10 +2011,6 @@ 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) {
@@ -2061,6 +2057,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
+
+ if (target.os.tag == .windows) {
+ // 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", {});
+ }
}
return comp;
Downgrading to 0.9.1 fixed issue with _create_locale for now
Hi,
This fixes _tls_index() issue for me but I still get undefined symbol link errors for _create_locale() and _free_locale() when building zig-gamedev with LTO enabled on Windows.
Should I create a separate issue?
Hello,
I am having the same problem as @michal-z above, although cross-compiling from Linux to Windows
Zig version: 0.11.0-dev.1568+c9b957c93 OS: Linux x86_64
build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = std.zig.CrossTarget.parse(.{
.arch_os_abi = "x86_64-windows-gnu"
}) catch unreachable;
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "test",
.root_source_file = .{ .path = "src/main.c" },
.target = target,
.optimize = optimize,
});
exe.linkLibC();
exe.install();
// Change to false and it will compile
exe.want_lto = true;
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
src/main.c
#include <locale.h>
int main() { _create_locale(LC_ALL, "de-CH"); }
Output of zig build:
error: lld-link: undefined symbol: __declspec(dllimport) _create_locale
note: referenced by /tmp/test2/zig-cache/o/8866c47da50eafcdde02827d3ac87d84/test.exe.lto.obj:(main)
error: test...
error: The following command exited with error code 1:
/usr/lib/zig/zig build-exe /tmp/test2/src/main.c -lc --cache-dir /tmp/test2/zig-cache --global-cache-dir /home/potato/.cache/zig --name test -target x86_64-windows-gnu -mcpu x86_64 -flto --enable-cache
error: the following build command failed with exit code 1:
/tmp/test2/zig-cache/o/74e6bd1ebb7036fb38ef1ab1e25f47c0/build /usr/lib/zig/zig /tmp/test2 /tmp/test2/zig-cache /home/potato/.cache/zig
Yeah, something is still broken when cross-compiling for Windows within WSL, but im unable to localize it. :/
The error is undefined symbol: _tls_index.
Hmm, I just randomly found out that it only happens when exe.single_threaded = true in my case.
Found a fix for my case: I had to define STBI_NO_THREAD_LOCALS before importing stb_image.h.