What's the rule of dynamic library searching for ld? - linux

Linux separates the linker-time search path and run-time search path.
For the run-time search path, I found the rule for ld.so in its man page (8 ld.so):
DT_RPATH
environment LD_LIBRARY_PATH
DT_RUNPATH
ld.so.cache
/lib, /usr/lib
But for linker-time search path, no luck for ld :(
Man page for ld (1 ld) says, besides -L option:
The default set of paths searched (without being specified with -L) depends on which emulation mode ld is using, and in some cases also on how it was configured.
The paths can also be specified in a link script with the "SEARCH_DIR" command. Directories specified this way are searched at the point in which the linker script appears in the command line.
Does the "default set of paths" depending on emulation mode mean "SEARCH_DIR"?

misssprite, to look for the linker search path for specific ELF emulation just run ld -m<emulation> --verbose | grep SEARCH_DIR

Speaking about the ld itself, the library path search order is the following:
Directories specified via -L command line flags
Directories in the LIBRARY_PATH environment variable
SEARCH_DIR variables in the linker script.
You can look what directories are specified in the default linker script by running ld --verbose | grep SEARCH_DIR. Note that = in the SEARCH_DIR values will be replaced by the value of --sysroot option if you specify it.
Usually ld is not invoked directly, but via compiler driver which passes several -L options to the linker. In the case of gcc or clang you can print the additional library search directories added by a compiler by invoking it with -print-search-dirs option. Also note that if you specify some machine-specific compiler flags (like e.g -m32 as misssprite mentioned) than the linker may use different linker script according to the chosen ELF emulation. In the case of gcc you can use -dumpspecs option to look how different compiler flags affect the linker invocation. But IMHO the simplest way to look for the linker command line is to compile and link a simple program with -v specified.

misssprite, there is no search for ld.so or ld-linux.so in the binutils's ld linker.
When dynamic program is build with gcc, it uses option -dynamic-linker of ld (collect2) program: http://man7.org/linux/man-pages/man1/ld.1.html
-Ifile, --dynamic-linker=file
Set the name of the dynamic linker. This is only meaningful when
generating dynamically linked ELF executables. The default
dynamic linker is normally correct; don't use this unless you
know what you are doing.")
Usually used as runtime loader for ELF, the "ld-linux.so" is registered as interpreter in the dynamic ELF file, program header INTERP (.interp), check output readelf -l ./dynamic_application. This field is for full path, as I understand.
When there is no gcc (directly called 'ld' program) or no this option was given, ld uses hardcoded string of full path to ld.so; and this default is incorrect for most OS, including Linux:
https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/bfd/elf64-x86-64.c#L510
/* The name of the dynamic interpreter. This is put in the .interp
section. */
#define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
#define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/gold/x86_64.cc#L816
template<>
const Target::Target_info Target_x86_64<64>::x86_64_info =
...
"/lib/ld64.so.1", // program interpreter
const Target::Target_info Target_x86_64<32>::x86_64_info =
...
"/libx32/ldx32.so.1", // program interpreter
Correct dynamic linker/loader path is hardcoded in machine spec files of gcc, grep output of gcc -dumpspecs command for ld-linux for -dynamic-linker option value.

Related

GNU ld: -z origin? -rpath $ORIGIN/../lib?

A legacy makefile that I'm trying to understand has -Wl,-z,origin,-rpath,'$ORIGIN/../lib'
OK, I see -Wl means the following are linker options; the commas will be replaced with spaces.
The manpage for the GNU ld mysteriously only says:
-z keyword
The recognized keywords are:
:
:
origin
Marks the object may contain $ORIGIN.
Likewise the next option -rpath (relative path?) contains this $ORIGIN suggesting it's some kind of key word but $ORIGIN is not otherwise mentioned in the ld man page.
$ORIGIN is mentioned under Substitution Sequences in the ELF specification. DF_ORIGIN is documented as well.
However, while GNU ld supports setting the DF_ORIGIN flag with the -z origin option, the dynamic loader in glibc always honors $ORIGIN, even if the flag is not set. This means that there is no reason to use the link editor flag when building for GNU/Linux.

How to use -rpath in compile to set executables search shared library in its same directory

How to set executables search shared library in its same directory in compile,
I've put the executable file and related .so libraries in the same directory, instead of changubg LD_LIBRARY_PATH or /etc/ld.so.conf,
Is it possible to set -rpath as a variable which is the directory where keeps the executalbe file, and the variable is not a certain path , it's changable.
Is it possible to set -rpath as a variable
Yes: you want DT_RPATH to be set to $ORIGIN, like so:
gcc main.c -Wl,-rpath='$ORIGIN' -lfoo -lbar
Note: you need to single-qoute the $ORIGIN to prevent shell from expanding it -- the RPATH must contain the $ sign.
Another option is to link like so:
gcc main.c ./libfoo.so ./libbar.so
This will only work if libfoo.so and libbar.so do not have DT_SONAME set, and generally is an inferior solution. I am only mentioning it here for completeness.

Linux ld: What's the meaning of `-m` option and the command `ld -melf_32 -Ttext 0 -e startup_32`

I have read the ld manual, the -m emulation option refers to emulate the emulation linker, what's the meaning of the description. And the -T scriptfile option can use scriptfile as the linker script, but what the option -Ttext 0 refers to, is it valid?
-Ttext 0 tells the linker to start the program at address 0
15.3 Linker emulation selection
A linker emulation is a "personality" of the linker, which gives the linker default values for the other aspects of the target system. In particular, it consists of
the linker script
the target
several "hook" functions that are run at certain stages of the linking process to do special things that some targets require
http://ftp.gnu.org/old-gnu/Manuals/binutils/html_node/binutils_20.html

Detect ld flags in m4 files

I have a .m4 file that appends some flags to the linker, one of which sets the rpath flag. This script was originally written for a GNU version of ld that uses -rpath=<value>, however, I'm trying to run the script on OSX, where the version of ld uses -rpath <value>. The end result is that I see this in my config.log:
ld: unknown option: -rpath=path/to/stuff
Is there a way to detect something about how ld expects flags to be passed in from within my .m4 file so I can output the right format depending on the version available?
You could try to detect if linking succeeds with given flag using AC_LINK_IFELSE macro in your script, for example:
AC_MSG_CHECKING([for rpath flag style])
saved_cflags="$CFLAGS"
CFLAGS="$CFLAGS -Wl,-rpath=."
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){ return 0;}])],
[RPATH_FLAG=gnu],
[RPATH_FLAG=none])
CFLAGS="$saved_cflags"
if test "x$RPATH_FLAG" = "xnone"; then
CFLAGS="$CFLAGS -Wl,-rpath,."
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(){ return 0;}])],
[RPATH_FLAG=llvm],
[RPATH_FLAG=none])
CFLAGS="$saved_cflags"
fi
AC_MSG_RESULT([$RPATH_FLAG])
And set proper flag based on this detection.

Does gcc have any options to add version info in ELF binary file?

I mean whether gcc can insert some source code version infor into ELF binary as section or something similar. I do not want to change my source file, but add some info with gcc option in Makefile.
If you don't mind changing your source file just once, add something like this:
const volatile static char version[] = VERSION;
and compile with:
gcc -c -DVERSION='"1.2.3"'
The volatile keeps gcc from removing the string at higher optimization levels.
As written, this won't compile if you forget the -D option, which may be either good or bad depending on your requirements.
You can emit your version info into a text file, then turn that text file into an object file which you then statically link into your executable.
The first step is simple but you have to write some code: a script or something to write your version info in any format you like as a plain text file. Then write a makefile rule to produce say version.o from version.txt, using objcopy. Now you'll have an object file with two useful symbols defined in it: the beginning and end of the textual version info. Add that generated object to your executable, and you'll be able to access the version two ways: by running strings on the binary, or by writing code in the application to print the version string (you'll need to declare the start and end symbols as variables in some header file).
Even if you don't have access to your source anymore, you can link the object with this option:
gcc -Wl,--defsym,VERSION_1_2_3=0 prog.o -o prog
You can check it with hexdump -C prog | less and look for VERSION
Add this to your makefile and be sure to always know when a program was compiled:
BUILD = $(shell date +"%Y%m%d_%H%M%S")
LDLIBS = -Wl,--defsym,BUILD_$(BUILD)=0
With the GNU linker ld You can use
--version-script=version-scriptfile
Read more about the command-line options at:
Using LD, the GNU linker - Options
Read more about creating version scripts at:
Using LD, the GNU linker - Version Script
Let me warn you though, that it is not for the weak-hearted!

Resources