zig icon indicating copy to clipboard operation
zig copied to clipboard

LLD with LTO enabled incorrectly drops _tls_index symbol, causing undefined reference errors

Open codepoint92 opened this issue 4 years ago • 9 comments
trafficstars

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.

codepoint92 avatar Apr 14 '21 11:04 codepoint92

bisected to 0d4b6ac7417d1094ac972981b0241444ce2380ba (when LTO was enabled by default)

(and, indeed, compiling with "-fno-lto" links successfully.)

xxxbxxx avatar May 01 '21 19:05 xxxbxxx

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) -> succeeds
  • zig 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.lib file to use the one from (1) -> succeeds.

xxxbxxx avatar May 01 '21 19:05 xxxbxxx

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)

michal-z avatar Aug 13 '21 10:08 michal-z

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.

andrewrk avatar Nov 15 '21 23:11 andrewrk

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

andrewrk avatar Nov 16 '21 19:11 andrewrk

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.

kubkon avatar Sep 07 '22 08:09 kubkon

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

kimmolinna avatar Oct 06 '22 07:10 kimmolinna

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;

xxxbxxx avatar Oct 09 '22 22:10 xxxbxxx

Downgrading to 0.9.1 fixed issue with _create_locale for now

jafri avatar Nov 02 '22 05:11 jafri

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?

michal-z avatar Nov 18 '22 08:11 michal-z

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

ThePotatoChronicler avatar Feb 04 '23 21:02 ThePotatoChronicler

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.

jakeweary avatar Feb 10 '23 05:02 jakeweary

Hmm, I just randomly found out that it only happens when exe.single_threaded = true in my case.

jakeweary avatar Feb 16 '23 10:02 jakeweary

Found a fix for my case: I had to define STBI_NO_THREAD_LOCALS before importing stb_image.h.

jakeweary avatar Feb 16 '23 11:02 jakeweary