llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.82k stars 11.46k forks source link

Linker options in Clang config files break `clang` invocation #67209

Open thesamesam opened 11 months ago

thesamesam commented 11 months ago

Setting certain linker options like -Wl,-z,now or -Wl,-z,lazy in /etc/clang/clang.cfg breaks clang and clang -v, giving both noise in the output as well as affecting its exit code.

This is unexpected, especially given this is the way distros have been recommended to set default flags.

(It also tries to create an a.out.)

$ cat /tmp/test
-Wl,-z,now

$ clang --no-default-config -v ; echo $?
clang version 17.0.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm/17/bin
System configuration file directory: /etc/clang
Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/13
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
0

$ clang --no-default-config --config /tmp/test -v ; echo $?
clang version 17.0.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm/17/bin
Configuration file: /tmp/test
System configuration file directory: /etc/clang
Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/13
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Selected multilib: .;@m64
 "/usr/lib/llvm/17/bin/x86_64-pc-linux-gnu-ld" -pie --hash-style=gnu --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/13 -L/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/lib -L/lib -L/usr/lib -z now -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/crtn.o
x86_64-pc-linux-gnu-ld: error: undefined symbol: main
>>> referenced by /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/Scrt1.o:(_start)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
1
thesamesam commented 11 months ago

cc @MaskRay @mgorny

llvmbot commented 11 months ago

@llvm/issue-subscribers-clang-driver

Setting certain linker options like `-Wl,-z,now` or `-Wl,-z,lazy` in `/etc/clang/clang.cfg` breaks `clang` and `clang -v`, giving both noise in the output as well as affecting its exit code. This is unexpected, especially given this is the way distros have been recommended to set default flags. (It also tries to create an `a.out`.) ```console $ cat /tmp/test -Wl,-z,now $ clang --no-default-config -v ; echo $? clang version 17.0.1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm/17/bin System configuration file directory: /etc/clang Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/13 Candidate multilib: .;@m64 Candidate multilib: 32;@m32 Selected multilib: .;@m64 0 $ clang --no-default-config --config /tmp/test -v ; echo $? clang version 17.0.1 Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm/17/bin Configuration file: /tmp/test System configuration file directory: /etc/clang Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/13 Candidate multilib: .;@m64 Candidate multilib: 32;@m32 Selected multilib: .;@m64 "/usr/lib/llvm/17/bin/x86_64-pc-linux-gnu-ld" -pie --hash-style=gnu --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o a.out /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/Scrt1.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/crti.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/crtbeginS.o -L/usr/lib/gcc/x86_64-pc-linux-gnu/13 -L/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/lib -L/lib -L/usr/lib -z now -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-pc-linux-gnu/13/crtendS.o /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/crtn.o x86_64-pc-linux-gnu-ld: error: undefined symbol: main >>> referenced by /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../lib64/Scrt1.o:(_start) clang: error: linker command failed with exit code 1 (use -v to see invocation) 1 ```
MaskRay commented 11 months ago

The clang -v --no-default-config --config=./test error is like the error we will get with clang -v --no-default-config -Wl,-z,now, and the model seems to match GCC. Do you have an estimate how many packages use -v without an input file/-Wl?

% gcc -v -fasm
% gcc -v -Wl,-z,now   # exit code 1
...
ld.lld: error: undefined symbol: main
>>> referenced by /usr/lib/gcc/x86_64-linux-gnu/12/../../../x86_64-linux-gnu/Scrt1.o:(_start)
collect2: error: ld returned 1 exit status
% clang -v -fasm
...
clang: warning: argument unused during compilation: '-fasm' [-Wunused-command-line-argument]
% clang -v -Wl,-z,now # exit code 1
...
ld.lld: error: undefined symbol: main
>>> referenced by /lib/x86_64-linux-gnu/Scrt1.o:(_start)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
thesamesam commented 11 months ago

We patch -Wl,-z,now into GCC's spec files and it doesn't have this behaviour. I don't have an estimate though. I do worry about configure tests being subtly confused by it rather than outright failing.

FWIW, see also https://bugs.gentoo.org/914468, where the (attempted) creation of a.out from this caused problems for us too.

MaskRay commented 11 months ago

Do you know how the package invokes clang -v? bugs.gentoo.org/914468 isn't clear to me.

If the package wants to retrieve the version, clang --version is better.

% fclang --version -Wl,-z,now
clang version 18.0.0
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /tmp/Rel/bin
ionenwks commented 11 months ago
$(NV_COMPILER_VERSION_HEADER):
        @echo \#define NV_COMPILER \"`$(CC) -v 2>&1 | tail -n 1`\" > $@

Thankfully exit code does nothing there, it just caused sandbox issues. Could indeed be swapped for --version but I worry more about cases that are going to be sneaky (i.e. not abort like it did here, but just silently fail some tests).

cbricart commented 11 months ago

seconding the attempt of creation of a.out : is that not even prone to some malicously prepared symlink attack…?

thesamesam commented 8 months ago

I realise I wasn't explicit before.

This also happens on bare clang, which is especially confusing:

$ clang
/usr/bin/x86_64-pc-linux-gnu-ld.bfd: /usr/lib/gcc/x86_64-pc-linux-gnu/14/../../../../lib64/Scrt1.o: in function `_start':
(.text+0x17): undefined reference to `main'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ clang --no-default-config -Wl,-z,now
x86_64-pc-linux-gnu-ld: error: undefined symbol: main
>>> referenced by /usr/lib/gcc/x86_64-pc-linux-gnu/14/../../../../lib64/Scrt1.o:(_start)
clang: error: linker command failed with exit code 1 (use -v to see invocation)

We get people who are - understandably! - confused by this because they're worried about their Clang being broken, as it doesn't say "no input files".

bwDraco commented 8 months ago

I just got out of an IRC chat with @thesamesam. This error sent me on a wild goose chase, leading me to think that my LLVM installation was broken. What got me really confused was that actual programs continued to compile as expected, from "Hello, world!" to large apps like LibreOffice, so we might have a bit of a UX issue here...

moha-gh commented 2 months ago

Are there any updates on this? We are also affected by the unexpected behaviour (in our case when adding -Wl,-dynamic-linker=... to the config file). As of now, we need to resort to add that flag via CMake, which is unfortunate given that using clang(++) directly shows different behaviour then.

BwL1289 commented 1 month ago

Also experiencing and looking for an update.