There are linker script wrappers for libelf.so and libdw.so to pull in the static archives when build under DTS. But they don't work when specified on the gcc command line with -lelf or -ldw. The work when given as input scripts directly. For example taken test_elf.c: #include <elf.h> #include <libelf.h> int main (int argc, char **argv) { return (elf_version (EV_CURRENT) == EV_CURRENT) ? 0 : 1; } $ scl enable devtoolset-7 bash $ $ gcc -lelf -o test_elf test_elf.c /tmp/cckNkFo4.o: In function `main': test_elf.c:(.text+0x15): undefined reference to `elf_version' collect2: error: ld returned 1 exit status But given the linker wrapper script directly as input does work: $ gcc -o test_elf test_elf.c /opt/rh/devtoolset-7/root/usr/lib64/libelf.so $ ./test_elf $ echo $? 0
Better workaround, put the -lelf last: $ gcc -o test_elf test_elf.c -lelf $ ./test_elf $ echo $? 0
Consensus seems to be that this isn't really a bug, just a slight difference caused by the implementation of the library wrapper scripts that needs documenting because things work slightly differently between the base RHEL toolchain and the DTS toolchain that uses linker script wrappers for libraries. The issue seen comes from DTS using wrapper scripts for various libraries to define some or all symbols through static archives and the follow ld linker "rule" (see the ld(1) manual page): The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again. The base RHEL toolchain doesn't normally use static archives but only shared library objects. When using the shared library object a symbol definition will be resolved at runtime by loading the shared library. But DTS defines some (or all) symbols in core libraries through a linker script wrapper that pulls in symbols through archive. This is done to make sure an executable produced by the DTS toolchain can be used as is on base RHEL without the user needing to install DTS shared libraries just to run the executable. This does mean that the user has to be careful that objects defining symbols are put on the linker (or compiler) command line after those objects that use those symbols. Most build systems (like automake) already make sure libraries used by a program are listed last on the command line. An example is the following program that uses the elf_version symbol from the libelf.so library. #include <elf.h> #include <libelf.h> int main (int argc, char **argv) { return (elf_version (EV_CURRENT) == EV_CURRENT) ? 0 : 1; } With the base RHEL toolchain this could be build as follows: $ gcc -lelf -o test_elf test_elf.c This produces a executable that dynamically links against libelf.so and resolves the elf_version symbol at runtime. But with the DTS toolchain the libelf.so file is actually a linker wrapper script that pulls in some symbol definitions through an static archive. So having the -lelf argument too early on the command line will result in: $ scl enable devtoolset-7 bash $ gcc -lelf -o test_elf test_elf.c /tmp/ccFlPTwb.o: In function `main': test_elf.c:(.text+0x15): undefined reference to `elf_version' collect2: error: ld returned 1 exit status The correct way to build this program is to have the -lelf argument at the end. $ gcc -o test_elf test_elf.c -lelf This will work with both the base RHEL toolchain and the DTS toolchain.
Finished: https://access.redhat.com/documentation/en-us/red_hat_developer_toolset/7/html-single/user_guide/index#sect-GCC-Specifics https://access.redhat.com/documentation/en-us/red_hat_developer_toolset/7/html-single/user_guide/index#sect-binutils-Specifics