Under Windows I have used a program called dependency walker to examine the libraries the application is using. I was wondering how I can achieve this on Linux for a standard binary:
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.0, stripped
Thanks.
Try:
ldd executable
For example:
[me#somebox ~]$ ldd /bin/ls
linux-gate.so.1 => (0xb7f57000)
librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0xb7f4c000)
libselinux.so.1 => /lib/libselinux.so.1 (0xb7f32000)
libacl.so.1 => /lib/libacl.so.1 (0xb7f2b000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7ddc000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0xb7dc4000)
/lib/ld-linux.so.2 (0xb7f58000)
libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0xb7dc0000)
libattr.so.1 => /lib/libattr.so.1 (0xb7dbb000)
[me#somebox ~]$
Note that this will only report shared libraries. If you need to find out what static libraries were linked in at compile time, that's a bit trickier, especially seeing as your executable is 'stripped' (no debugging symbols).
Use ldd
ldd /bin/sh
If you want something a little less raw than iteratively calling ldd and somewhat more like MSVC depends, you should try Visual-ldd. It hasn't been updated in 4 years, but it should still work given that the ELF format hasn't changed. It still won't show you individual symbols inside those libraries - for that you'll need something like nm, and I don't know of any GUI wrapper for that, unfortunately.
Use ldd. It will show the dynamic libraries the binary needs.
Note that the libraries themselves may in turn need more libraries. To get these, you can run ldd on the libraries you got from running ldd on the binary.
Related
I'm developing a ldd-python script.
As far as I know, ELF binary itself has information only about library's SONAME.
How can I get library's full path by this SONAME?
I want to print like this original ldd result:
$ ldd test
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7d28000)
ldd prints this information by running ld.so in special mode (LD_TRACE_LOADED_OBJECTS). So your only options are to run ldd internally and parse it's output or try to model it's behavior in Python (but note that such model would have to be quite complex, especially once you get to setuid binaries).
I'm relatively new to Linux and am having trouble trying to figure out the intricacies of .SO files and how (64-bit) shared libraries(and their versions, dependencies etc) work; and how to link them and use them in a basic C++ program??
The scenario is this: I have a shared library file(single physical file) called libfaidtz.so.3.0.0_debian6_64bit. I have installed Debian(latest version) 64-bit on VMWare. I have installed (I believe) all the basic C++ development tools use apt-get.
Now I wish to write a simple program in C++ that will LINK libfaidtz.so.3.0.0_debian6_64bit, and enable me to call two specific functions "exported" by this .so file. Unfortunately, the environment/system set up on my machine is preventing me from linking to this library successfully.
Can anyone guide me on this please?
I have included below, some pertinent details regarding the .SO file it self. The function I wish to use(from the .SO file) has the following function-prototype(and should work):
int32_t DEF_EXPORT TZ_FAID_Size(int64_t start_time,
int32_t roster_count,
int64_t * roster_from,
int64_t * roster_to,
int32_t * roster_ids,
int32_t & id_cnt);
I'm from a Windows background (Dynamic linking and DLLs-wise) and am struggling to get this .SO file liked and used in a basic C++ test program.
root#debian:/home/maitreya/lib# ldd libfaidtz.so.3.0.0_debian6_64bit
linux-vdso.so.1 => (0x00007fff667ff000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3300a6f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f33007ed000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3300461000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f330024b000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3300f93000)
root#debian:/home/maitreya/lib# nm libfaidtz.so.3.0.0_debian6_64bit
0000000000208c70 d DW.ref.__gxx_personality_v0
0000000000006ebb T TZ_FAID_Process
0000000000006e04 T TZ_FAID_Size
0000000000007447 T TZ_FAID_Version
0000000000208028 a _DYNAMIC
0000000000208230 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
00000000000011ca T _Z15FetchExpiryDatePiS_S_
and so on..
If you look at some of the standard libraries installed on your system you will see that they are soft linked. For example: I have /lib/libgpm.so.2.1.0 with a soft link /lib/libgpm.so.
Try creating a soft link libfaidtz.so to your library and then link with -lfaidtz.
I have a code which was dynamically linked with the mkl library. when running the code, it reports mkl not found.
./bmdl
/g/software/EMTO/5.7/intel_12.1/ser/bin/bmdl: error while loading shared libraries: libmkl_intel_lp64.so: cannot open shared object file: No such file or directory
But when I use ldd to check the dynamically linked libraries in the executable, it shows the mkl library is found
ldd bmdl
libmkl_intel_lp64.so => /g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/libmkl_intel_lp64.so (0x00002b975d76d000)
libmkl_sequential.so => /g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/libmkl_sequential.so (0x00002b975df53000)
libmkl_core.so => /g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/libmkl_core.so (0x00002b975e631000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003785600000)
libm.so.6 => /lib64/libm.so.6 (0x0000003784e00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003784a00000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000378a600000)
libdl.so.2 => /lib64/libdl.so.2 (0x0000003785200000)
/lib64/ld-linux-x86-64.so.2 (0x0000003784600000)
Any idea what could be wrong?
Output from readelf -l ./bmdl
Elf file type is EXEC (Executable file)
Entry point 0x4034b0
There are 8 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001c0 0x00000000000001c0 R E 8
INTERP 0x0000000000000200 0x0000000000400200 0x0000000000400200
0x000000000000001c 0x000000000000001c R 1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000e4eb4 0x00000000000e4eb4 R E 200000
....
More debugging
$ export LD_DEBUG=libs,files
$ ./bmdl
./bmdl: error while loading shared libraries: libmkl_intel_lp64.so: cannot open shared object file: No such file or directory
$ ldd ./bmdl
15133:
15133: file=libtermcap.so.2 [0]; needed by /bin/sh [0]
15133: find library=libtermcap.so.2 [0]; searching
15133: search path=/g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/tls/x86_64:/g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/tls:/g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64/x86_64:/g/software/intelXE/composer_xe_2011_sp1/mkl/lib/intel64:/g/software/intelXE/composer_xe_2011_sp1/lib/intel64/tls/x86_64:/g/software/intelXE/composer_xe_2011_sp1/lib/intel64/tls:/g/software/intelXE/composer_xe_2011_sp1/lib/intel64/x86_64:/g/software/intelXE/composer_xe_2011_sp1/lib/intel64 (LD_LIBRARY_PATH)
....
Seems LD_DEBUG doesn't have effect on running ./bmdl alone.
I just realized the old bmdl has a 'setgid' flag and my new built doesn't have it. Maybe that was the cause?
-rwxr-sr-x 1 root gants 1123992 Jul 23 16:14 /scratch/helpdesk/bmdl
I removed the setgid bit from the old bmdl and running ./bmdl doesn't complain about library not found. Now the question is why setgid can interfere with dynamically linked library?
It happens that setgid with a dynamically linked executable can cause security problems and is greatly limited by GNU glibc. For example, LD_LIBRARY_PATH will be ignored. Maybe the old built never worked before?!
Using MKL reqires env variables including INCLUDE, MKLROOT, LD_LIBRARY_PATH, LIBRARY_PATH, CPATH, FPATH and NLSPATH being properly set.
This can be done by a single script provided by Intel.
If you use intel compiler,
$ source ${intel_dir}/bin/compilervars.sh intel64
If you use MKL only with gcc compiler,
$ source ${intel_dir}/mkl/bin/mklvars.sh intel64
You can add this cmd line to your .bashrc so you don't need to run it every time.
The code is dynamically linked and has the setgid attribute. setgid with a dynamically linked executable can cause security problems and is greatly limited by GNU glibc. For example, LD_LIBRARY_PATH will be ignored. That is why the code keeps on complaining some shared library not found.
But when I use ldd to check the dynamically linked libraries in the executable, it shows the mkl library is found
It is highly improbable that you've told us the whole story, because ldd (on Linux) is just a small shell script around ld-linux.so. If ld-linux.so can find the shared library when invoked by ldd, ld-linux.so should also be able to do that when the executable is invoked directly (ld-linux.so is what actually maps shared libraries when you run a.out).
The only plausible explanations I can think of:
you execute bmdl in a different environment from the one you execute ldd in, or
you have a modified ldd on your PATH, which perhaps modifies the environment before running "real" ldd.
How do I know which linker is used?
readelf -l bmdl
and look for "Requesting program interpreter".
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2].
Very strange.
The next debugging suggestion: set LD_DEBUG=libs,files and see where ld-linux is searching. You can do that for both ldd and bmdl, and see where the difference comes from.
I have a binary which needs some *.so files to execute.
Now when I try to execute it on some older machines it shows
/lib/libc.so.6: version `GLIBC_2.4' not found
how can I change its search path to /lib/i386-linux-gnu/libc.so.6 from /lib/libc.so.6
So I can run two different libc files on a same machine.
Are you on a 32-Bit system and maybe trying to execute a binary that uses the 64 bit glibc?
Modifying the library search path can be done by using LD_LIBRARY_PATH variable, e.g. in a subshell:
(export LD_LIBRARY_PATH=/lib/i386-linux-gnu:${LD_LIBRARY_PATH}; my_program)
You can change the search path by using the LD_LIBRARY_PATH environment variable when calling your binary.
Something along the lines of:
LD_LIBRARY_PATH=/lib/i386-linux-gnu/libc.so.6 ./your_binary
should work. Bear in mind that depending on the shell you're using you might need to call either export or env to set the variable.
You can check if it's working using the following command:
LD_LIBRARY_PATH=/lib/i386-linux-gnu/libc.so.6libc.so.6 ldd ./your_binary
linux-vdso.so.1 => (0x00007fff140e9000)
libselinux.so.1 => /lib/libselinux.so.1 (0x008f9000)
librt.so.1 => /lib/librt.so.1 (0x006f1000)
libacl.so.1 => /lib/libacl.so.1 (0x004e8000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x00129000)
libdl.so.2 => /lib/libdl.so.2 (0x00f25000)
/lib/ld-linux.so.2 (0x003b3b000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00d07000)
libattr.so.1 => /lib/libattr.so.1 (0x00b02000)
You just need to check if libc.so.6 is being resolved to the shared object that you want.
UPDATE: It seems that you want to load a 32 bit shared object for a 64 bit binary. As far as I know there is no way to do this since the target architectures are different and the loader will refuse to load the 32 bit so. If this is your case, this might explain why the loader loads the default libc. Depending on your case, it might be possible to compile the binary as 32 bits, in which case it should run with a 32 bit libc.
If you want to run 32-bit executables on a 64-bit machine, you'll need to install the 32 bit versions. On Fedora or other systems with yum run:
yum install glibc.i686
(note the .i686 suffix, it asks specifically for the 32 bit versions) and try again. The ldd(1) command should help identifying the needed libraries, and yum should be smart enough to find them by the name it gives.
I have a make file for a program that links to libdl.so with the following line -ldl. There are no calls to dlopen or any of the related functions. What is the effect of linking to this library in this way even though you do not use any of the functions?
You'll have to read the documentation for your linker. From info ld on my Linux/ELF/GNU Binutils system (emphasis added):
`--as-needed'
`--no-as-needed'
This option affects ELF DT_NEEDED tags for dynamic libraries
mentioned on the command line after the `--as-needed' option.
Normally the linker will add a DT_NEEDED tag for each dynamic
library mentioned on the command line, regardless of whether the
library is actually needed or not. `--as-needed' causes a
DT_NEEDED tag to only be emitted for a library that satisfies an
undefined symbol reference from a regular object file or, if the
library is not found in the DT_NEEDED lists of other libraries
linked up to that point, an undefined symbol reference from
another dynamic library. `--no-as-needed' restores the default
behaviour.
You can check yourself by running ldd on a test program. On a simple test program, I get:
linux-vdso.so.1 => (0x00007fffd8305000)
libc.so.6 => /lib/libc.so.6 (0x00007f646c669000)
/lib/ld-linux-x86-64.so.2 (0x00007f646c9ca000)
However, if I link with -ldl, I get this:
linux-vdso.so.1 => (0x00007fff644f1000)
libdl.so.2 => /lib/libdl.so.2 (0x00007fb9b1375000)
libc.so.6 => /lib/libc.so.6 (0x00007fb9b1014000)
/lib/ld-linux-x86-64.so.2 (0x00007fb9b1579000)
Even though libdl isn't used by my program. However, if I run GCC with -Wl,--as-needed, libdl will not be linked in. According to my tests, this only works if -Wl,--as-needed is listed on the command line before -ldl.
What are the effects? It means that your binary won't run on systems without the shared library, even though you don't use it. It also means that your binary will break if you upgrade the shared library and uninstall the old one. It's not a big deal because binary compatibility is a bear anyway, but I see no reason not to turn on -Wl,--as-needed for projects in general.
I have coded a small application which uses nothing but STL. It has 8275 bytes of size without linking to any specific libraries:
linux-gate.so.1 => (0x00e1e000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x0015a000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x0044b000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00741000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00250000)
/lib/ld-linux.so.2 (0x00a75000)
Now, when I compile it and link it with boost_thread, it grows to 8290 bytes:
linux-gate.so.1 => (0x009d9000)
libboost_thread.so.1.40.0 => /usr/lib/libboost_thread.so.1.40.0 (0x00e59000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x003a3000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00bc5000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00f8a000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00110000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00bf0000)
librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x00dd8000)
/lib/ld-linux.so.2 (0x00ba3000)
Note that there is no function call on my code to features of boost_thread. However, boost_thread is added anyway as a dependency of my application (as you can see on the output of ldd).
Linking to a shared library is different than linking a static library. The main differences were explained already by #Dietrich Epp, but there's another important detail. Shared libraries define functions void _init() and void _fini(void) which are called upon loading/unloading a shared library; if you don't define them yourself the linker will add default stubs.
Those will be called also if you link your program against a shared library, but don't reference any symbol from the library (and don't add --as-needed linker flag).
Most linkers will simply omit the unused objects from the final binary, exactly as if you hadn't linked with the library in the first place.