When executing ldd on a file, it returns a hex number in parentheses vor every library it found.
For example:
root#server> ldd wpa_supplicant
linux-gate.so.1 => (0xb779b000)
libnl.so.1 => /usr/lib/libnl.so.1 (0xb774d000)
libssl.so.1.0.0 => not found
libcrypto.so.1.0.0 => not found
libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xb7748000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb75ed000)
libm.so.6 => /lib/i686/cmov/libm.so.6 (0xb75c7000)
/lib/ld-linux.so.2 (0xb779c000)
If the hex number is not the one of the library the executable once got linked against, a version information error may occur.
I got two questions:
Where does this value originate?
How can I find out which hex value the executable is looking for? (i.e. the one it originally got linked against)
The hexadecimal numbers are the memory addresses the respective library gets loaded into. See https://stackoverflow.com/a/5130690/637284 for further explanation.
Related
I am trying to find the shared library which imported an external symbol. Currently I can get all imported symbols by using nm or many alternatives such as using radare2. I can also get the libraries which the binary is dependent on by using ldd. However, I got stuck at this point since I cannot find an efficient way to get which external symbol in my binary is dependent on which shared library. So, for example how can I find the shared library which exports the function named foo or printf or anything in an efficient way? I provide an example:
Output of nm -D myfile
w __cxa_finalize
U foo
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U __libc_start_main
U printf
U puts
Output of ldd
linux-vdso.so.1 (0x00007ffd30904000)
libfoo.so => /home/user/Desktop/dynamic_link_example/libfoo.so (0x00007f1b08aaf000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1b088a1000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1b08abb000)
So, for example how can I find the shared library which exports the function named foo or printf or anything in an efficient way?
You can run your program with env LD_DEBUG=bindings ./a.out. This will produce a lot of output, which you can grep for foo and printf.
Note that the answer to "which external symbol in my binary is dependent on which shared library" is "whichever library defines this symbol first".
So if today your binary depends on lifoo.so for foo and on libc.so.6 for printf, nothing stops you from running with a different libfoo.so tomorrow, and that different version of libfoo.so may define different symbols. If the new version of libfoo.so defines printf, that would cause the answer to your question for symbol printf to change from libc.so.6 to libfoo.so.
im using the below as a wrapper for the open() syscall on my system... i've compiled this into a .so file.... and put it in /etc/ld.so.preload. it appears to be working well...
int open(__const char *pathname, int flags, mode_t mode)
{
printf("in open %s\n ", pathname);
//other stuff
}
it works for all binaries... vim, touch, cat, less, head, etc.... EXCEPT... the "ls" command!!
I don't understand why.
if i use "sudo ls", it ends up using the wrapper again correctly....
so what's so special about "ls" that the shared library loader decides it can skip my open() wrapper function...?
vagrant#vagrant-ubuntu-trusty-64:/vagrant$ ldd /bin/ls
linux-vdso.so.1 => (0x00007fffacbcd000)
/usr/lib/x86_64-linux-gnu/libtracing.so (0x00007f09b0bce000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f09b09ab000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f09b07a3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f09b03de000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f09b01da000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f09aff9c000)
/lib64/ld-linux-x86-64.so.2 (0x00007f09b0dd0000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f09afd97000)
i can see that its linked (my so is the 2nd one called libtracing.so).
this doesnt happen with any of the other commands i run sudo or not, they all seem to work.
is this something special because of libselinux? anyone have any thoughts?
[root#wdctc1281 bin]# ldd node
linux-vdso.so.1 => (0x00007fffd33f2000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f70f7855000)
librt.so.1 => /lib64/librt.so.1 (0x00007f70f764d000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f70f7345000)
libm.so.6 => /lib64/libm.so.6 (0x00007f70f7043000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f70f6e2d000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f70f6c10000)
libc.so.6 => /lib64/libc.so.6 (0x00007f70f684f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f70f7a61000)
What does the first line and last line mean? They don't look like the normal
xxxx.so => /lib64/xxxxx.so (0xxxxxxxxxxxxxxxxxxxx)
format.
the first line is the VDSO. this is described in depth in the vdso(7) manpage. basically it's a shared library that's embedded in your kernel and automatically loaded whenever a new process is exec-ed. that's why there's no filesystem path on the right side -- there is none! the file only exists in the kernel memory (well, not 100% precise, but see the man page for more info).
the last line is the ELF interpreter. this is described in depth in the ld.so(8) manpage. the reason it has a full path is because your program has the full path hardcoded in it. the reason it doesn't have an entry on the right side is that it's not linked against (directly) and thus no search was performed. you can check this by running:
$ readelf -l node | grep interpreter
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
$ scanelf -i node
ET_EXEC /lib64/ld-linux-x86-64.so.2 node
all the other lines are libraries you've linked against. you can see those by looking at DT_NEEDED tags when you run readelf -d on the file. since those files lack full paths, the ld.so needs to perform a dynamic path search for it. that's actually what the lines are telling you: "libdl.so.2 is needed, so when i searched for it, i found it at /lib64/libdl.so.2 (and was loaded into memory at address 0x00007f70f7855000)"
ldd filename shows you the program shared libraries used by the file.
libc.so.6, for example, is libc shared object version 6, which sits in /lib64 and its memory location is 0x00007f70f684f000.
The last line talks about ld-linux-x86-64.so version 2 under /lib64. This fellow will find and load shared libraries node needs. It will prep those libraries and run them. So, speaking in very crude terms, ld-linux-x86-64 is the runner. libc.so.6 and others are loaded and ldd shows the location of those shared libraries and memory locations. That is my understanding.
I have an executable on my Linux box which I know has been compiled either with OpenMPI or MPICH libraries.
Question: how to determine which one?
The following diagnostic procedure assumes that MPICH/MPICH2 and Open MPI are
the only possible MPI implementations that you may have linked with. Other
(especially commercial) MPI implementations do exist and may have different
library names and/or library symbols.
First determine if you linked dynamically:
% ldd my_executable
linux-vdso.so.1 => (0x00007ffff972c000)
libm.so.6 => /lib/libm.so.6 (0x00007f1f3c6cd000)
librt.so.1 => /lib/librt.so.1 (0x00007f1f3c4c5000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f1f3c2a7000)
libc.so.6 => /lib/libc.so.6 (0x00007f1f3bf21000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1f3c969000)
If you see libmpich.so in that list, then you have dynamically linked to
MPICH (or MPICH2). If you see libmpi.so then you have linked with Open MPI.
If neither is present, then you probably just linked statically. In that case
we need to examine the binary to look for distinguishing symbols:
% ( nm my_executable | grep MPIR_Free_contextid >/dev/null ) && echo "MPICH"
% ( nm my_executable | grep ompi_comm_set_name >/dev/null ) && echo "Open MPI"
Open MPI applications react to MCA parameters, that can be passed in environment variables. Just run the executable in singleton mode (i.e. without mpirun/mpiexec) with something like sysinfo_base_verbose set to 30:
$ OMPI_MCA_sysinfo_base_verbose=30 ./program
If you get an output like:
[hostname:pid] mca: base: components_open: Looking for sysinfo components
then this is more than robust indication that the executable uses Open MPI.
How can I tag ELF libs with build IDs?
I downloaded a precompiled library that has a sha1 sum in it:
user#localhost ~/tmp $ file foo.so.0
foo.so.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x7e3374eb34cafb69d3dca8b126f4aa33d44bb465, stripped
user#localhost ~/tmp $ ldd foo.so.0
linux-vdso.so.1 (0x00007fff955b1000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f436d3c9000)
libc.so.6 => /lib64/libc.so.6 (0x00007f436d022000)
/lib64/ld-linux-x86-64.so.2 (0x0000003000000000)
From http://fedoraproject.org/wiki/RolandMcGrath/BuildID
ld: new option --build-id:
This adds an option to ld to synthesize a .note.gnu.build-id section with type SHT_NOTE and flags SHF_ALLOC (read-only data), that contains an ELF note header and the build ID bits. This then goes into the link as if it were part of the first object file (so it may be placed or merged by the linker script). The build ID bits are determined as the very last thing ld does before writing out the linked file. You can give --build-id=style chose md5, uuid (128 random bits), or 0xabcdef (your chosen bytes in hex). Just --build-id defaults to md5, which computes an 128-bit MD5 signature based all the ELF header bits and section contents in the file--i.e., an ID that is unique among the set of meaningful contents for ELF files and identical when the output file would otherwise have been identical.
The Linux binutils-2.17.50.0.17 release includes this, in f8test1.