Closed marxin closed 3 weeks ago
The issue is actually caused by the fact that the following section is missing in the output generated by Wild linker:
[ 1] .note.gnu.property NOTE 0000000000400200 000200 000030 00 A 0 0 8
❯ readelf -n /home/marxin/Programming/wild/wild/tests/build/ifunc.c-default.ld
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x00000020 NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature used: x86
x86 ISA used: x86-64-baseline
Hi @marxin. Thanks for the report.
Wild doesn't output exactly the same sections as GNU ld and that's expected. That alone shouldn't cause the test to fail. I'd guess GNU ld has changed some things and linker-diff needs to be changed to accommodate those changes.
I'm stuck on a relatively old version of GNU ld - 2.38. I also set up a docker image, but even that only has 2.40. So I'll need to probably set up a different docker image in order to get something even newer.
linker-diff is reporting more than one failure. So the link
field on the .rela.plt
section is only one of the failures. The other failures are the asm diffs printed above that. Some of them look to be due to wild bypassing the GOT (global offset table) for an ifunc - which doesn't seem like a valid thing to do. I just checked and it's not doing that for me. One possibly clue is the line:
ORIG b8 00 00 00 00 mov $0,%eax // R_X86_64_32 -> `compute_value10`
That shows the relocation from the original input file. It's requesting the absolute address of the function compute_value10
.
If I force my test to fail so as to get the same line, it looks like this:
ORIG e8 00 00 00 00 call 5 // R_X86_64_PLT32 -> `compute_value10`
The compiler requested a reference to the PLT (procedure linkage table) for the function compute_value10
.
So I think the difference is perhaps the version of the compiler that was used. Or perhaps the default flags for the compiler.
Hi @marxin. Thanks for the report.
You're welcome, I'm very much curious about the project!
I'm stuck on a relatively old version of GNU ld - 2.38. I also set up a docker image, but even that only has 2.40. So I'll need to probably set up a different docker image in order to get something even newer.
Please try testing that on opensuse/tumbleweed
which is an openSUSE rolling distro that contains the latest binutils.
So I think the difference is perhaps the version of the compiler that was used. Or perhaps the default flags for the compiler.
Yeah, that's very likely the case. I know openSUSE uses -fPIE
by default and the binutils might also have some non-default configuration options:
❯ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib64/gcc/x86_64-suse-linux/13/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-suse-linux
Configured with: ../configure CFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' CXXFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' XCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' TCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -g' GDCFLAGS=' -O2 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -g' --prefix=/usr --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib64 --libexecdir=/usr/lib64 --enable-languages=c,c++,objc,fortran,obj-c++,ada,go,d,jit,m2 --enable-offload-targets=nvptx-none,amdgcn-amdhsa, --enable-offload-defaulted --without-cuda-driver --enable-host-shared --enable-checking=release --disable-werror --with-gxx-include-dir=/usr/include/c++/13 --with-libstdcxx-zoneinfo=/usr/share/zoneinfo --enable-ssp --disable-libssp --disable-libvtv --enable-cet=auto --disable-libcc1 --enable-plugin --with-bugurl=https://bugs.opensuse.org/ --with-pkgversion='SUSE Linux' --with-slibdir=/lib64 --with-system-zlib --enable-libstdcxx-allocator=new --disable-libstdcxx-pch --enable-libphobos --enable-version-specific-runtime-libs --with-gcc-major-version-only --enable-linker-build-id --enable-linux-futex --enable-gnu-indirect-function --program-suffix=-13 --without-system-libunwind --enable-multilib --with-arch-32=x86-64 --with-tune=generic --with-build-config=bootstrap-lto-lean --enable-link-serialization --build=x86_64-suse-linux --host=x86_64-suse-linux
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.3.0 (SUSE Linux)
I've built a docker image based on openSUSE that successfully reproduces this issue and others. I've been busy this week preparing for a talk, but now that that's out of the way I can hopefully get through some of the bugs.
Great then! May I ask you if the talk will be public, I would be interested then.
I hope so. I believe it was recorded, but I'm not sure when it will get posted. I have however put up a blog post that I wrote in conjunction with the talk. The content is pretty similar. It's at https://davidlattimore.github.io/posts/2024/07/17/testing-a-linker.html
Just an update on progress here... there are various things about openSUSE that make it different than the Pop-OS (Ubuntu-based) system I've primarily been testing on. One difference is that binaries are compiled with -fno-pie
by default. I added support for this a couple of days ago, although I haven't extensively tested it as yet.
Another difference is that the gcc version on openSUSE seems to be gcc-7 by default, which is pretty old. Some of the tests aren't working because the test is using attributes that weren't supported by that version of gcc - e.g. the retain
attribute. I'm fixing this by changing the tests to look explicitly for a newer version of gcc, e.g. gcc-13
and only use gcc
if that isn't found.
I'm also finding various packages that need to be installed in order for some of the tests to work. For example tests that link with -static-pie
need glibc-devel-static
to be installed. I'm updating openuses.Docker
as I find such things.
Lastly there are some false positives from linker-diff that I need to fix. In particular it currently doesn't do a good job when relocation points to somewhere within the bytes of a symbol rather than to the start.
One difference is that binaries are compiled with
-fno-pie
by default. I added support for this a couple of days ago, although I haven't extensively tested it as yet.
Thanks for working on that. I've tested that briefly and it seems it's not working for a simple test-case:
❯ printf '#include<iostream>\nint main() { std::cout << "XXX" << std::endl; return 0; }' | gcc-13 -x c++ - -lstdc++ -B ~/Programming/wild -fpie
~/Programming/wild on use-opensuse-tumbleweed [$?] via 🦀 v1.82.0-nightly
❯ echo $?
0
❯ printf '#include<iostream>\nint main() { std::cout << "XXX" << std::endl; return 0; }' | gcc-13 -x c++ - -lstdc++ -B ~/Programming/wild -fno-pie
~/Programming/wild on use-opensuse-tumbleweed [$?] via 🦀 v1.82.0-nightly
❯ ./a.out
Segmentation fault (core dumped)
❯ valgrind a.out
...
==67944== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==67944== Bad permissions for mapped region at address 0x404F80
==67944== at 0x404F80: ??? (in /home/marxin/Programming/wild/a.out)
==67944== by 0x4B2F1EF: (below main) (in /usr/lib64/libc.so.6)
Another difference is that the gcc version on openSUSE seems to be gcc-7 by default, which is pretty old. Some of the tests aren't working because the test is using attributes that weren't supported by that version of gcc - e.g. the retain attribute. I'm fixing this by changing the tests to look explicitly for a newer version of gcc, e.g. gcc-13 and only use gcc if that isn't found.
Yeah, it's ancient and I would prefer using Tumbleweed (that I have installed on my machine). It's a rolling distro that provides GCC 13 (and will provide GCC 14 by default soonish): #23.
I'm trying to reproduce the segfault. Does it repro for you in the docker image? Here's what I tried:
docker build -t wild-dev-opensuse . -f docker/opensuse.Dockerfile && docker run -it wild-dev-opensuse
Then in the resulting shell:
10292fab3b37:/wild # cargo build
...
Finished `dev` profile [unoptimized] target(s) in 5.37s
10292fab3b37:/wild # printf '#include<iostream>\nint main() { std::cout << "XXX" << std::endl; return 0; }' | gcc-13 -x c++ - -lstdc++ -B target/debug/wild -fno-pie
10292fab3b37:/wild # ./a.out
XXX
10292fab3b37:/wild #
10292fab3b37:/wild # echo $?
0
10292fab3b37:/wild #
Ah, wait, that didn't link with wild - I didn't use -B
correctly
OK, I copied target/release/wild
to /usr/bin/ld
, and can now reproduce the segfault. Thanks, will investigate...
The issue seemed to be due to applying copy relocations to functions, which won't work. I've fixed it to now generate a PLT entry instead of doing a copy relocation when the target of the relocation is a function.
Good news.... After a few more changes, the tests now pass on the openSUSE tumbleweed docker image. Thanks for all your bug reports on this an the other issues BTW :)
Thanks for the fixes ;) I've got one another issue noticed while building mold
with wild
: #24.
Noticed that for the current main branch commit (042615a):