I met some trouble when using LD_PRELOAD to load my so.
The steps are as following:
libtest.c:
void fun()
{
return
}
gcc -o libtest.so libtest.c -fPIC --shared
export LD_PRELOAD=pwd/libtest.so
main.c
extern void fun();
void main()
{
fun()
}
gcc -o main -L. main.c -ltest
Then ldd main
ldd main
linux-vdso.so.1=>(0x00007ffff7ffd000)
/home/shiyanlou/Code/libtest.so(0x00007ffff7df9000)
libtest.so=>not found
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6 (0x00007ffffa29000)
/lib64/ld-linux-x86-64.so.2 (0x0000555555554000)
execute main ./main
it promotes:
error while loading shared library:libtest.so. cannot open shared object file:No such file or directory.
I wonder that why it prompts that libtest.so cannot be found After I exported LD_PRELOAD variable. However, I also tried to use LD_PRELOAD to specify a different shared lib(not "libc.so") to inject malloc function, it works!
Why LD_PRELOAD only works for the shared lib that was not used when linking???
You need to create 2 versions of the *.so. One which has default behavior and is loaded and hard linked via "-ltest".
Now build your default libtest.so and prove with nm -B the symbol you are expecting to intercept is dynamically linked.
Now build main.c into main.o, then check main.o with nm to also see it has an extern unsatisfied linkage requirement on the symbol.
Now link ./main with main.o and libtest.so and then run it.
The ./main needs to run with this copy by default, demonstrate the default behavior and also show the correct path to the correct DSO via ldd command.
...
Now you take the step to create the LD_PRELOAD version.
You shall call this libtest2.so. You do not use the -ltest2
The point is that whoever built ./main does not know about libtest2.so at all, there is no hard linkage dependency.
libtest2.so has alternative behavior, like make foo() returns a different string/number) and the goal now is to intercept this 2nd version at runtime, so the 1st version is not called by default (or at all). By using the LD_PRELOAD environment.
LD_PRELOAD=./libtest2.so ./main
...
Good luck.
I copied and rename the DSO as libtest2.so and reset LD_PRELOAD to the renamed DSO(with absolute path), It also prompt that libtest.so could not be found.
I think that the reason why it prompt so is that the libtest.so which is used for hard dependency could not be loaded.
That is to say while LD_PRELOAD has been loaded, but hard dependency could not be satisfied, so it could not execute ./main either.
Now I can conclude that when execute ./main, hard dependency DSO must be satisfied because every hard dependency DSO also must be loaded(although this DSO shall be totally replaced!), otherwise it will prompt that the DSO could not be found!
Thanks for your help #Darryl Miles
I think the reason why your example not working is that your libtest.so does not have the correct soname.
If you compile your libtest.c with the following command
$ gcc -o libtest.so libtest.c -fPIC -shared -Wl,-soname,libtest.so
then you should be able to execute your main with PRELOAD.
Related
I'm attempting to do a release of some software and am currently working through a script for the build process. I'm stuck on something I never thought I would be, statically linking LAPACK on x86_64 linux. During configuration AC_SEARCH_LIB([main],[lapack]) works, but compilation of the lapack units do not work, for example undefiend reference to 'dsyev_' --no lapack/blas routine goes unnoticed.
I've confirmed I have the libraries installed and even compiled them myself with the appropriate options to make them static with the same results.
Here is an example I had used in my first experience with LAPACK a few years ago that works dynamically, but not statically: http://pastebin.com/cMm3wcwF
The two methods I'm using to compile are the following,
gcc -llapack -o eigen eigen.c
gcc -static -llapack -o eigen eigen.c
Your linking order is wrong. Link libraries after the code that requires them, not before. Like this:
gcc -o eigen eigen.c -llapack
gcc -static -o eigen eigen.c -llapack
That should resolve the linkage problems.
To answer the subsequent question why this works, the GNU ld documentation say this:
It makes a difference where in the command you write this option; the
linker searches and processes libraries and object files in the order
they are specified. Thus, foo.o -lz bar.o' searches libraryz' after
file foo.o but before bar.o. If bar.o refers to functions in `z',
those functions may not be loaded.
........
Normally the files found this way are library files—archive files
whose members are object files. The linker handles an archive file by
scanning through it for members which define symbols that have so far
been referenced but not defined. But if the file that is found is an
ordinary object file, it is linked in the usual fashion.
ie. the linker is going to make one pass through a file looking for unresolved symbols, and it follows files in the order you provide them (ie. "left to right"). If you have not yet specified a dependency when a file is read, the linker will not be able to satisfy the dependency. Every object in the link list is parsed only once.
Note also that GNU ld can do reordering in cases where circular dependencies are detected when linking shared libraries or object files. But static libraries are only parsed for unknown symbols once.
My system is an older NAS running 2.6.32. I have found that when using -static for any subsequent library, it will also try to statically link any other library that I might need.
When I add the -Wl,-Bdynamic flag first and then explicitly name those libraries using -lc, such as "-Wl,-Bdynamic -lc -lstdc++" then it works. So what happens is that libc and others fail to be statically linked.
The static libc on the system is called /opt/lib/libc_nonshared.a.
The contents of /opt/lib/libc.so is this:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
The gcc version is 4.2.3. The current build command I am facing adds -dynamic at the end but this doesn't help much. When I add some static library directly using its .a name, and not using a -l flag, then there is no issue.
The problem seems to be that the dynamic library of libc came with the NAS, but the static version sits in /opt/lib.
I run:
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
I get:
/opt/lib/gcc/arm-none-linux-gnueabi/4.2.3/../../../../arm-none-linux-gnueabi/bin/ld: cannot find -lc
collect2: ld returned 1 exit status
make: *** [hamming] Error 1
when I try to use static libc as is. Were I to perform a 'hack' to link libc_nonshared.a to libc.a, it suddenly does find it. But complains:
hamming.c:54: undefined reference to `malloc'
hamming.c:54: undefined reference to `memset'
And a zillion other errors of course. As mentioned above, /opt/libc.so contains the reference to both files (dynamic and static).
For libstdc++ only a .la file exists.
The -static linker flag does not take any argument. It is a boolean
flag that simply directs the linker to link no shared libraries, as
documented
-static
Do not link against shared libraries...
There is no need to explicitly direct the linker to link shared (dynamic)
libraries when it has a choice because that is the default bevaiour. If
you simply link, e.g.
gcc -o prog ... -lfoo ...
then the linker will link the first of libfoo.so (shared) or libfoo.a
(static) that it finds in any of the specified (-Ldir) or default
search directories, searched in commandline sequence. If it finds both
libfoo.so and libfoo.a in the same directory then it will choose
libfoo.so. Thus shared and static libraries may be freely intermixed
without any special options.
Specify -static only if you wish to link only static libraries.
If you wish to insist on linking a particular libfoo.a even when
libfoo.so is in the same directory and would be chosen by default,
use the explicit form of the -l option: -l:libfoo.a
Later
gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -o hamming
This command is failing with:
ld: cannot find -lc
because the linker (ld) cannot find a static library libc.a in
any of the specified linker search directories (-L. -L/opt/lib) or
the default linker search directories. If you wish instead to link
/opt/lib/libc_nonshared.a then your command should be:
>gcc hamming.c -static -L. -L/opt/lib -l:matrix.a -lc_nonshared -o hamming
However, you have not explained why you want to link this program statically
(-static) in the first place, which is not the usual way and will require you to have installed
static versions of all libraries required for the linkage - both those
you explicitly link and the default libraries that gcc will add for C language
linkage (Standard C library, GCC runtime library).
Supposing you have a static library called (oddly) matrix.a (rather
than normally, libmatrix.a) that is located in /some/dir/, then the
normal way to compile and link your program would be:
gcc hamming.c -L/some/dir -l:matrix.a -o hamming
I suggest you start with that and deviate only as problems compel
you to.
The discovery of an /opt/lib/libc.so containing:
OUTPUT_FORMAT(elf32-littlearm)
GROUP ( /lib/libc.so.6 /opt/lib/libc_nonshared.a )
is misleading you. This is not your shared libc. A shared library
is a binary. This is a linker script, and it says that your shared libc
is in fact /lib/libc.so.6. The linker will almost certainly find and use it by default.
I find that the -L flag must be given when using -rpath. For instance:
gcc -o test test.o -L. -lmylib -Wl,-rpath=.
Why is the -L flag needed? What information more than the information from the h-files are needed at compile time?
If I remove -L. I get the following message:
gcc -o test test.o -lmylib -Wl,-rpath=.
/usr/bin/ld: cannot find -lmyLib
It's perfectly ok to remove both flags, though. Like this:
gcc -o test test.o -lmylib
Provided that libmyLib can be found in /usr/lib, that is. Why isn't -L needed now?
This is a follow-up question to https://stackoverflow.com/a/8482308/1091780.
Even dynamic libraries required a degree of static linkage; the linker needs to know what symbols should be supplied by the dynamic library. The key difference is that the dynamic library provides the definition at runtime, whilst with fully static library provides the definition at link time.
For this reason, -L is needed to specify where the file to link against is, just as -l specifies the specific library. The . indicates the current directory.
-rpath comes into play at runtime, when the application tries to load the dynamic library. It informs the program of an additional location to search in when trying to load a dynamic library.
The reason -L/usr/lib doesn't need to be specified is because the linker is looking there by default (as this is a very common place to put libraries).
A clarification of OMGtechy's answer.
If the linker does not check which symbols are provided by a library, it can never tell you if any symbols are missing at compile time. They might be in one of the libraries loaded at run-time. You could never know. There is no connection at compile time between the header files of a library and the .so file.
I need an help!! I am trying to build a standalone executable ie without ANY dynamic linking.
I wrote a small test program, generated a relocatable object file for it called test.o. When I try to build the standalone executable using GNU linker I get the below error:
$ld -static -o test test.o /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/libc.a /usr/lib/gcc/i486-linux-gnu/4.4/libgcc.a /usr/lib/gcc/i486-linux-gnu/4.4/libgcc_eh.a
/usr/lib/gcc/i486-linux-gnu/4.4/libgcc_eh.a(unwind-dw2-fde-glibc.o): In function _Unwind_Find_FDE':
(.text+0x190b): undefined reference todl_iterate_phdr'
How to resolve the undefined symbol dl_iterate_phdr. In which archive this symbol is present?
Thanks!!!
EDIT1:
Just in case if I am not very clear, my motive is to generate a standalone executable ie an executable which is completely ready for execution while it gets loaded into memory i.e.) all symbol resolution and relocation is done by program linker itself instead of dynamic linker. Is it possible to generate such an executable?
FINAL UPDATE:
Now I got it to get complied with ld directly using the below command:
$ld -static -o test /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbeginT.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o test.o --start-group /usr/lib/gcc/i486-linux-gnu/4.4.3/libgcc.a /usr/lib/gcc/i486-linux-gnu/4.4.3/libgcc_eh.a /usr/lib/libc.a --end-group
man ld says --start-group archives --endgroup is used to resolve circular references!! Also i find symbol dl_iterate_phdr is defined in libc.a.
Thanks all for your help!!
When I try to build the standalone executable using GNU linker
Don't. Use of ld to link any user-space program is most often a bug. Your link line is certainly incorrect.
Use compiler driver to do the heavy lifting for you. This should work:
gcc -static -o test test.o
I am looking to use ld since I wanted to build a standalone executable
What makes you believe that GCC-built executable is less stand-alone than ld-built one? Whatever it is, you are mistaken: gcc simply invokes ld with correct arguments.
If you're getting this error when targeting android, you need to link against libdl.so (-ldl)
gcc -o main main.c -L . -static-libgcc -Wl,-static -lhello -lc
I have a C project using several object files that needs to be linked in a specific order to find all needed symbols.
For example this command works fine (lib2.o depends on lib1.o etc.)
gcc -o my_app main.o lib1.o lib2.o lib3.o -lm
but
gcc -o my_app main.o lib3.o lib2.o lib1.o -lm
ends with undefined reference to `my_variable' errors.
This is a known behavior and can be solved for example by adding these objects to GROUP section in a linker script.
Now I'd like to share these object as a static library with my colleagues. So...
ar -rcs mylib.a lib1.o lib2.o lib3.o
gcc -o my_app main.o mylib.a -lm
Unfortunately this gives the same undefined reference errors like the specifying the objects in incorrect order.
I have not found any linker or archiver options to make it working and also no solution by googling even if I think that this problem should be relatively common.
Do please anybody know a solution?
regards
Jan
This might be a link order problem. When the GNU linker sees a library, it discards all symbols that it doesn't need. It also does that in the sequential order form left to right.
Recent versions of gcc/ld default to linking with --as-needed flag.
This means if you write -lmylib.a before the C file the library will automatically get excluded (the order matters when testing if things are "needed" like this)
You can fix this with either:
gcc -L. -o example example.c -lmylib.a
gcc -L. -Wl,--no-as-needed -o example example.c -lmylib.a
The latter of which passes --no-as-needed to the linker, which would cause the library to still be linked, even if you didn't call any function external from it.
Your error implies that the problem is in one of your lib?.o files [lib{later}.o depends on lib{earlier}.o]
How did you manage to compile them?
Were there any compilation warnings?
It has been a while since I used C, but I think that you will need to include dependent libraries within the library that has the dependency - this may be the reason why you can't find too many references to the problem, because it does not really exist.