Is there a way to load user library's from specific location ONLY on running the binary - c

I have a shared library's libmyworld.so in /opt/my_prog/lib and also in /home/user1/lib
Irrespective of the order I specified in LD_LIBRARY_PATH (LD_LIBRARY_PATH=/home/user1/lib;/opt/myprog/lib); my binary SHOULD always look for libmyworld.so FIRST in /opt/my_prog/lib;
Can this be done using GCC during compilation time? without modifying my_prog binary. Thanks in advance.

The search order for dynamic libraries in Linux (from ld.so man page) is the following
Using the DT_RPATH dynamic section attribute of the binary
if present and DT_RUNPATH attribute does not exist. Use of
DT_RPATH is deprecated.
Using the environment variable LD_LIBRARY_PATH. Except if
the executable is a setuid/setgid binary, in which case it
is ignored.
Using the DT_RUNPATH dynamic section attribute of the binary
if present.
From the cache file /etc/ld.so.cache which contains a
compiled list of candidate libraries previously found in the
augmented library path. If, however, the binary was linked
with -z nodeflib linker option, libraries in the default
library paths are skipped.
In the default path /lib, and then /usr/lib. If the binary
was linked with -z nodeflib linker option, this step is
skipped.
When linking, to set
DT_RUNPATH: use -Wl,--enable-new-dtags -Wl,-R$(RUNPATH)
DT_RPATH: use -Wl,--disable-new-dtags -Wl,-R$(RPATH)
In theory, it is better to use DT_RUNPATH as the LD_LIBRARY_PATH, on which the user has a control, has precedence. But here you want to avoid the user control, so use the DT_RPATH. In you link line:
-Wl,--disable-new-dtags -Wl,-R/opt/my_prog/lib

You can always launch your binary (here called foo) with
$ LD_LIBRARY_PATH=/opt/my_prog/lib foo
or make a shell script with the line above.

While compiling your source code use the below command
gcc -o [desired_executable_file_name] -L [Your shared library path] -l [your shared library name] -I [Header file path]
for example in your case
gcc -o my_word_exe -L /opt/my_prog/lib -lmyworld -I [header path if their]
Then it"ll take libmyworld.so in /opt/my_prog/lib this path

Use LD_PRELOAD.
LD_PRELOAD=/home/lib/libmyworld.so mybinary
The advantage is that you don't fiddle with LD_LIBRARY_PATH - your binary may depend on other shared libraries and it may need proper LD_LIBRARY_PATH/ld.so.conf/whatever.
PS. This is the least invasive and flexible solution, because does not affect loading of other libraries and does not hardcode paths in the user executable.

Related

ldd says "not found" for one file, and found for another

I'm trying to gather all the dependencies needed by some .so file. I use the Recursive ldd script, but that doesn't really matter for the manner of sake.
I want to put all the .so files in one directory, say it's in
/home/user/project/lib
I'm having a weird experience: Say there's a file libmat.so which I want to gather all its dependencies. So I ran
/home/user/project/lib$ ldd libmat.so
...
libmwboost_system.so.1.65.1 => /home/user/project/lib/libmwboost_system.so.1.65.1
libmwboost_filesystem.so.1.65.1 => /home/user/project/lib/libmwboost_filesystem.so.1.65.1
...
So we see that ldd recognized the libmwboost_system.so.1.65.1 file in the current directory.
Turns out that libmwboost_filesystem.so.1.65.1.so also depends on libmwboost_system.so.1.65.1,
But when I run:
/home/user/project/lib$ ldd libmwboost_filesystem.so.1.65.1
...
libmwboost_system.so.1.65.1 => not found
...
How come ldd can find it when I run in on libmat.so and can't when I run it on libmwboost_filesystem.so.1.65.1 ?
I would be glad if someone could provide an explanation in the context of the linking process. As far as I know, when you link a file against a library, you use the following flags:
~$ gcc my_program.c -Lpath/to/solib/for/static/linker -lnameoflib -wl,-rpath=path/to/solib/for/dynamic/linker
This -Wl,-rpath flag embeds in the executable the path of the library that the dynamic linker will search for at run time. In the case of a shared library that depends on other libraries - does it work the same?
Ok so that's how it works:
When linking a binary - whether it's an executable or another shared library - against a shared library, the static linker embeds in the binary the names of the libraries we linked against. Those libraries will be loaded by the dynmaic linker - ld.so - once the program is run by the user.
Now the question is where the dynamic linker will search for these libraries at runtime. Briefly, according to the man page of ld.so, when the dynamic linker first inspects the binary to resolve its dependencies, it goes through the strings of the dependencies. If a string contains a slash "/" then the string is interpreted as a path. This can happen if the library name was specified with a slash at link time, like this:
~$ gcc prog.c ../path/to/library.so
In this case, the string embeded in the executable will be: ../path/to/library.so and the dynamic linker will search it relatively to the location of the binary.
If not, it will search for the library in a list of locations (the whole list is specified in the man page). The first location is the directories specified in the DT_RUNPATH section attribute of the binary. This can be set at link time using the -Wl,-rpath flag:
~$ gcc prog.c -Lpath/of/lib/ -lmylib -Wl,-rpath=path/of/lib
In this case, the path/of/lib will be searched for the library by the dynamic library.
You can inspect this attribute using readelf:
~$ readelf -d binary | grep RUNPATH
In my case, the libmat.so library contained a RUNPATH attribute set to $ORIGIN, meaning that libraries will be searched in the same location of the binary library. Whereas, the libmwboost_filesystem.so.1.65.1 didn't have this attribute set, that is why ldd didn't find the library.
ldd is just using ld.so to try and load the libraries, and shows where it found them, according to the search path specified in the ld.so man page.

How does Solaris decide the library path?

On Solaris, I can use crle command to configure library path like this:
crle -c /var/ld/ld.config -l /lib:/usr/lib:/usr/local/lib:/opt/DSI/32
I can also use the traditional LD_LIBRARY_PATH method, like this:
LD_LIBRARY_PATH="/export/home/donald/mysql-5.0.91-installed/lib/mysql/:/lib:/usr/lib"
How does Solaris decide the library path? For example, does Solaris select from crle path first, then LD_LIBRARY_PATH? I try to google, but can't find the answers.
The answer is in the manual (man ld.so.1).
The runtime linker uses a prescribed search path for locat-
ing the dynamic dependencies of an object. The default
search paths are the runpath recorded in the object, fol-
lowed by a series of defaults. For 32-bit objects, the
defaults are /lib followed by /usr/lib. For 64-bit objects,
the defaults are /lib/64 followed by /usr/lib/64. These
defaults component can be modified using a configuration
file that is created with crle(1). The runpath is specified
when the dynamic object is constructed using the -R option
to ld(1). The environment variable LD_LIBRARY_PATH can be
used to indicate directories to be searched before the
default directories.
So, the order is:
LD_LIBRARY_PATH
shared object RPATH
crle defaults

Unable to compile a c application that reads smartcard

I am trying to compile an example c application that is using pkcs#11 to finds all
the private keys on the token, and print their label and id, but getting following errors
/tmp/ccAqQ7UI.o: In function initialize':
pkcs11_example1.c:(.text+0x8e5): undefined reference to C_Initialize'
/tmp/ccAqQ7UI.o: In function `get_slot':
The example is taken from here
compilling by using following command;
`gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so`
I am not sure which library i should link after -L.
Can anyone guide how to compile this and are there some libraries required to link.
C_Initialize and other 60+ functions with "C_" prefix are cryptoki functions defined in PKCS#11 specification. They are usually implemented in standalone library provided by HSM vendor. Looking at your code samples I would say that you need to directly link also PKCS#11 library or you can modify the code to dynamically load PKCS#11 library in runtime with LoadLibrary or dlopen and then acquire pointers to all cryptoki functions via the C_GetFunctionList call. You can also take a look at pkcs11-logger the source code for an example on how to do that.
The link command you give, gcc pkcs11_example1.c -o slots -L /usr/lib/opensc-pkcs11.so, is wrong.
-L takes just path, which is added to paths where libs are searched from, but /usr/lib is default so you don't need this switch at all.
You are missing -l, which takes the library name without lib prefix or .so suffix, so looks like you need -lopensc-pkcs11.
So, first make sure your library file really is /usr/lib/libopensc-pkcs11.so (note lib prefix!) possibly with verion numbers following. Then change build options so link command becomes
gcc pkcs11_example1.c -o slots -lopensc-pkcs11

Why shared library path is hardcoded in execuatble?

Recently I got a test binary. When I checked it using objdump, I observed that it includes hard coded library path. Why it is needed to to hardcode the path like that? Shouldn't the path be taken from SHELL environment variables or -L parameter instead ?
objdump -p testprog
The output includes the hardcoded path to shared libraries:
....
NEEDED /home/test/lib/liba.so
NEEDED /home/test/lib/libb.so
NEEDED /home/test/lib/libc.so
....
This is probably because those three .so files had no SONAME on the host where your test program was built. Tell the person who built it to rebuild liba.so with -Wl,soname,liba.so and similar for the other two, then relink the main program.

Inhibit default library paths with gcc

Is there a way to inhibit the default library path search with gcc? -nostdinc does this for the include path search, but -nostdlib, either by omission or by design, only inhibits the -lc -lgcc etc. but not the library search paths.
You should be able to do this with spec files (although fiddling with these seems like something of a dark art to me...).
If you look at the output of gcc -dumpspecs, the link_command spec is the one that builds the actual command that is invoked. Digging through some of the other specs it references, the link_libgcc spec, which is usually defined (for native compilers at least) as:
*link_libgcc:
%D
is the culprit:
%D
Dump out a -L option for each directory that GCC believes might contain startup files. If the target supports multilibs then the current multilib directory will be prepended to each of these paths.
You can override it by creating a file (e.g. my.specs) which substitutes paths of your choice:
*link_libgcc:
-L/foo/bar -L/blah/blah
and then passing -specs=my.specs to gcc.
Supposing the underlying loader is ld you might be able to redirect its whole load path with
--sysroot=directory
(I don't remember the option that you have to use to pass loader arguments to gcc, but there is one...)
You could either have "directory" be something bogus, where no libraries are found, or mimic the directory layout for your own project.
You can try -nodefaultlibs to avoid all the default libraries, then use -L and -l to add-back the libraries you want in the directories you want.
Directories specified on the command-line with the -L option should have priority over the default directories.
How about just setting the LIBRARY_PATH environment variable?
If I understand the question correctly, you want to do something like forcing the linker to look at a local library path before the default path, so you can just explicitly set that variable to control the order.

Resources