zig icon indicating copy to clipboard operation
zig copied to clipboard

ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack

Open leonidborisenko opened this issue 4 years ago • 11 comments

Environment

  • Linux with x86_64 kernel and i386 glibc userspace
  • Zig snapshot from zig-linux-x86_64-0.8.0-dev.1104+5e81b048a.tar.xz tarball
$ zig version
0.8.0-dev.1104+5e81b048a

Minimal reproducible example

// dummy.zig
export fn dummy() c_int {
    return 0;
}
$ zig build-lib dummy.zig -dynamic -target i386-native
zig build-lib output (with `ld.lld` error)
ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by fs.zig:684 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/fs.zig:684)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.fs.Dir.openFile)

ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by os.zig:4504 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/os.zig:4504)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.os.toPosixPath)

ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by debug.zig:1040 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/debug.zig:1040)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.debug.printLineFromFileAnyOs)
error: LLDReportedFailure

Note

It happens only in -O Debug. It doesn't happen in all other -O modes.

Workaround

  • Just add -z notext to build-lib command line arguments, like:
zig build-lib dummy.zig -dynamic -target i386-native -z notext
  • This option could be set in build.zig. As suggested in https://github.com/ziglang/zig/issues/7935#issuecomment-1258071152:

    you can set lib.link_z_notext = true; in your build.zig

See pull request #10056 (and merged commit 2cdffc9).

Zig 0.8.1 didn't include this commit, following downloadable releases should allow this workaround. I've tested it with 0.9.0-dev.1561+5ebdc8c46 (released on 2021-11-03).

Workaround (for Zig versions released before 29-Oct-2021)

Execute `zig ld.lld` manually with added `-z notext`
  1. Find ld.lld invocation arguments.
$ zig build-lib dummy.zig -dynamic -target i386-native --verbose-link
ld.lld -error-limit=0 --gc-sections -m elf_i386 -shared -o libdummy.so -soname libdummy.so zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o /tmp/zig/cache/zig/o/44e6d86d0e734b882fd45d9658d515d8/libc.a /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a
ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by fs.zig:684 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/fs.zig:684)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.fs.Dir.openFile)

ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by os.zig:4504 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/os.zig:4504)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.os.toPosixPath)

ld.lld: error: relocation R_386_PC32 cannot be used against symbol __zig_probe_stack; recompile with -fPIC
>>> defined in /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a(/tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/compiler_rt.o)
>>> referenced by debug.zig:1040 (/tmp/zig/zig-linux-x86_64-0.8.0-dev.1104+5e81b048a/lib/std/debug.zig:1040)
>>>               zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o:(std.debug.printLineFromFileAnyOs)
error: LLDReportedFailure
  1. Execute zig ld.lld manually with added -z notext.
$ zig ld.lld -error-limit=0 --gc-sections -m elf_i386 -shared -o libdummy.so -soname libdummy.so zig-cache/o/dbc73e4dde353bae2e8456cf743e6f42/dummy.o /tmp/zig/cache/zig/o/44e6d86d0e734b882fd45d9658d515d8/libc.a /tmp/zig/cache/zig/o/24934007c007b2d5b7135d2223ee0adf/libcompiler_rt.a -z notext
  1. libdummy.so will be produced.

Conclusions

That begs a question: is it or is it not possible to pass freeform extra arguments to internal zig ld.lld invocation simply by using additional zig build-lib options and/or by using appropriate function in build.zig? (I didn't find a way to do it.)

Also I don't know and can't argue whether passing -z notext is a safe or right solution. Just reporting that it works.

Relevant links

-z notext

TEXTREL

leonidborisenko avatar Feb 02 '21 05:02 leonidborisenko

The R_386_PC32 relocation smells fishy, R_386_PLT32 should be used instead as this is a position-independent code and that's the only external symbol that's not going trough the PLT.

LLVM's code emitting the stack-probe call defaults to CALLpcrel32 (and CALL64pcrel32 for x86-64).

cc @maskray

LemonBoy avatar Feb 02 '21 08:02 LemonBoy

I suspect zig sets dso_local on function declarations for -fpic mode.

MaskRay avatar Feb 02 '21 08:02 MaskRay

AFAICS not really, at least not explicitly.

LemonBoy avatar Feb 02 '21 09:02 LemonBoy

This problem can be reproduced with this small snippet of LLVM IR:

target triple = "i386-unknown-linux-none"

declare void @ext()

define void @dummy() #0 {
Entry:
  %trigger = alloca [4097 x i8], align 1
  call void @ext()
  ret void
}

attributes #0 = { "probe-stack"="probe" }

When compiled with --relocation-model=pic the call to ext is routed trough the PLT (R_386_PLT32) as expected while the stack probe remains PC-relative. This makes me think the stack probe symbol is not a common external symbol and must not be routed trough the PLT (That's reasonable as this this is a stack probe after all).

LemonBoy avatar Mar 19 '21 15:03 LemonBoy

I have encountered this bug today when working on android-x86

ikskuh avatar May 30 '21 12:05 ikskuh

This seems pretty critical. Pretty much disallows using Zig for building shared libraries.

The suggested workaround isn't practical to use since there's no way to pass lld flags from build.zig, and even compiling in release doesn't always work.

Here's a simple example that triggers this bug in ReleaseSafe mode:

const std = @import("std");
export fn hello() void {
    std.debug.print("Hello, world!\n", .{});
}

Compile with zig build-lib -dynamic -target i386-native -lc -OReleaseSafe hello.zig (note: linking libc is the thing that makes this example break in ReleaseSafe - if you don't link libc it only breaks in Debug)

silversquirl avatar Jul 26 '21 17:07 silversquirl

The suggested workaround isn't practical to use since there's no way to pass lld flags from build.zig, and even compiling in release doesn't always work.

Here's a simple example that triggers this bug in ReleaseSafe mode:

Current master allows adding -z notext to build-lib command line arguments, like:

zig build-lib dummy.zig -dynamic -target i386-native -z notext

See pull request #10056 (and merged commit 2cdffc9). I've tested it with 0.9.0-dev.1561+5ebdc8c46 (released on 2021-11-03).

Both my example (from issue report) and yours (from quoted comment, with exactly the same command line arguments as you provided, except added -z notext) could be built just fine and afterwards produced shared libraries work (for me) as expected.

I've updated my original report with this workaround.

Still, I want to stress, that:

Also I don't know and can't argue whether passing -z notext is a safe or right solution. Just reporting that it works.

leonidborisenko avatar Nov 05 '21 12:11 leonidborisenko

What is the status of this? Building shared libraries for android doesn't seem to work

bayo-code avatar Feb 24 '22 03:02 bayo-code

@Hardebayho, in case you never found out, you can set lib.link_z_notext = true; in your build.zig as a workaround.

mlugg avatar Sep 26 '22 13:09 mlugg

@mlugg Yeah, I did find the flag. Thanks

bayo-code avatar Sep 27 '22 07:09 bayo-code

@Hardebayho, in case you never found out, you can set lib.link_z_notext = true; in your build.zig as a workaround.

Thanks for that, let's try integrating it into the Android SDK!

ikskuh avatar Oct 22 '22 09:10 ikskuh