Difference in commands to create executables from shared library - c

What is the difference between the launch and launch1 executable created by the following
commands:
gcc main.o ./my_lib/libshared_secure.so -o launch
and
gcc main.o -L ./my_lib -lshared_secure -o launch1
Here main.o is the object code of the main function and libshared_secure.so is a shared
library. I expected that both launch and launch1 would be same but I was incorrect. Why
are the two executables different and which part of the above commands causes these
differences?
The difference was that in executing launch I didn't have to set and export LD_LIBRARY_PATH variable to the path of libshared_secure.so but I had to do that in executing launch1.

readelf -d launch | grep libshared_secure.so
Will report [./my_lib/libshared_secure.so]. However, for launch1 it will be [libshared_secure.so]. Linker will try to load given libraries in system directories and in directories relative to your current working directory (so, if you'll launch binary from some other place (not ./launch but e.g. ../launch from subdirectory) - it will not find library without LD_LIBRARY_PATH).
Other functionality is rpath - linker could take directory to look into, and write it into ELF header, without need to specify LD_LIBRARY_PATH. This avoids problem with current working directory because you could use paths relative to binary directory, not your current one. E.g. gcc -Wl,-rpath='$ORIGIN/my_lib' -Lmy_lib -lshared_secure main.o will link your binary with libshared_secure.so but will add relative entry to rpath.

Related

Is the GCC link option truly necessary when linking to a static library?

I've been playing around with GCC lately and have been experimenting with the linking options. I'm somewhat confused why the link option -l is necessary when statically linking to an archive file. It seems like you can just toss the .a file as if it were an ordinary object file.
For example, take the following make file:
test1 : main.c libfunc.a
gcc main.c -L. -lfunc -o main.out
test2 : main.c libfunc.a
gcc main.c libfunc.a -o main.out
libfunc.a : func1.c func2.c
gcc func1.c -c
gcc func2.c -c
ar cr libfunc.a func1.o func2.o
Make target test1 uses GCC's linking options to link to the archive file. Target test2 instead just includes the archive file direct. Building and running each output seem to result in the same executable.
There are several ways you can tell gcc what file(s) to use. An argument of the form -lname (or the two arguments -l name) says “Search for a library named name”. Per the GCC documentation, this argument is passed to the linker (typically the ld command). The linker looks for a file with a name like libname.extension, where extension is one of the known library files extensions such as .a or .so, and it looks for files with those names in a list of library directories it has. You can add directories to search with the -L switch.
When the linker finds the library, it uses it just as if you had specified the path, so the end result is the same whether you specify the library with -l or with its path.
By using the path, you can specify libraries that are not in the known library directories or that have unusual names.
Note that the linker does not process libraries the same way as object files. When the linker processes an object file, it incorporates everything in the object file into the output file being constructed. When the linker processes a library file, it incorporates only those modules within the library that provide a symbol definition for a symbol referenced by a prior module and not yet resolved. For example, if you write a program that uses sqrt but does not use sin, then, when the linker processes libm.a after reading your object module, it will take the sqrt module from the library but not the sin module.

Compiling dynamically linked library in a makefile

I am trying to run my library using a make file. I currently have a dynamic library called libname.so which I created by linking the object files of some of my C files. This library works correctly when I run the following lines of code in my linux shell :
gcc -L. main1.c -lname -o out
LD_LIBRARY_PATH=.
export LD_LIBRARY_PATH
But when I copy these exact lines of code in to a make file and name the make file title for this function 'names' and then run 'make names' in linux shell, I get the following error:
./out: error while loading shared libraries: libname.so: cannot open shared object file: No such file or directory
Then once again when I run the final two lines of code shown at the end of the makefile function again then run the out file, it is fixed and the program works again.
I just need to figure out how to make it work directly from the makefile.
LD_LIBRARY_PATH=.
export LD_LIBRARY_PATH
These two lines do not influence the creation of the program in any way because you type the lines after creating the program.
These lines are not used for building your program, but they influence running the program (by typing ./out).
If you compile your program using gcc directly (not using make) and open a new terminal, you also have to type these two lines (again) before you run the program.
It does not matter how you build the program (by typing gcc manually or by running make):
After opening a new terminal, you will need to type these two lines before you run the program.
However, the dynamic linker does not only use the path information from LD_LIBRARY_PATH but also from the DT_RUNPATH information in the executable.
Unlike the LD_LIBRARY_PATH variable which is set on one console (or terminal) only, the DT_RUNPATH information is stored directly in the executable file.
As described in another question on this site, you can set the DT_RUNPATH information using the -Wl,-rpath=<value> switch:
gcc -L. main1.c -lname -o out -Wl,-rpath=.
If you do this, the dynamic linker will search your library (libname.so, if I understand correctly) in the current directory.
Note:
. really means: In the current directory; it does not mean: In the same directory as the executable file!
If your program is stored in the directory ./somedir and you type somedir/out, the file ./libname.so is searched, not the file ./somedir/libname.so.
This is both the case for the -Wl,-rpath= method and for the LD_LIBRARY_PATH= mehtod.

Can't link dynamic library when running C language with root privileges?

I have a C language file named testFunc.c that uses the dynamic library libCfunc.so. This library is placed under the path /home/cuiyujie/workspace/library/lib.
I added this path to library path export LD_LIBRARY_PATH=/home/cuiyujie/workspace/library/lib:$LD_LIBRARY_PATH
When I use the following command to compile, it can be compiled normally.
gcc testFunc.c -lCfunc -lm -O0 -g -o testFunc
But when I run it, if I use ./testFunc, it can run normally.
But if I use sudo ./testFunc, he will get the following error.
./testFunc: error while loading shared libraries: libCfunc.so: cannot
open shared object file: No such file or directory
I found on Google that when root is used, the value of the LD_LIBRARY_PATH variable is ignored.
I used the following command to recompile. Specify the library path when compiling.
gcc testFunc.c -L/home/cuiyujie/workspace/library/lib -lCfunc -lm -O0 -g -o testFunc
When I continue to run with the sudo ./testFunc command, the same error still appears.
The reason why I need to execute with root is because I need to read some inquiries that only root privileges can read. I want to get the physical address of certain variables, so I need to read the mapping file of the process, which requires root privileges.
The linker flag -L just tells the linker where to look for the library (or a library stub, if such is used) at link time. It does not influence the library search path at runtime.
For a system wide installed library you'd place the library in a place that's been configured in the global linker search path, set through /etc/ld.so.conf and files in /etc/ld.so.conf.d.
However it is perfectly possible to specify additional search paths specific to certain binaries by means of the so callled rpath. The rpath is set using the (you guessed it) rpath extra linker flag -Wl,-rpath.
Linking the program with
gcc -o … -Wl,-rpath='${ORIGIN}' …
would make the ELF interpreter (the piece of code that loads ELF binaries and does dynamic linkage) to also look for additional libraries right next to the program binary. You can read up on the details of rpaths in the ld.so manpage.
Be aware that rpaths invoke certain security considerations.
LD_LIBRARY_PATH is an environment variable, and all environment variables exist separately for each user.
When you export it under your regular user, but then run the executable as root using sudo, the export does not exist for the new process.
You can preserve the environment of your user with the -E parameter:
sudo -E ./testFunc
or you can specifically preserve the LD_LIBRARY_PATH variable like this:
sudo LD_LIBRARY_PATH=/home/cuiyujie/workspace/library/lib:$LD_LIBRARY_PATH ./testFunc

How can I set an executable's rpath and check its value after building it?

I'm building the following file:
int main()
{
return 0;
}
with the following flags:
g++ -o main -Wl,-rpath,'$ORIGIN' main.cpp
but the rpath flag is doing nothing. When I execute the following commands:
objdump -x main | grep -i rpath
readelf -a main | grep -i rpath
I obtain nothing (RPATH is not defined).
What I'm doing wrong?
EDIT
I have tried to do the above with a different binary using the following cmake flags:
set(CMAKE_SKIP_BUILD_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_INSTALL_RPATH "\$ORIGIN")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
I have moved the executable to a different machine, and placed a dynamic library that it needs to 'dlopen' in the same folder. It has worked (and I'm 100% sure this is because rpath, since before applying the above cmake flags the executable didn't worked).
Still, using the above two commands to check rpath (objdump and readelf) I still don't see anything.
If I didnt miss something here, you are not linking any libs in your build command.
Lets say you want to link libusb.so shared library, which is located in libusb sub-folder of your current folder where is main.cpp.
I will not take any details here, about soname, linkname of lib etc, just to make clear about rpath.
rpath will provide runtime linker path to library, not for linktime, cause even shared library need to be present(accessible) in compile/link time. So, to provide your application loader with possibility to look for needed library in start time, relatively to your app folder, there is $ORIGIN variable, you can see it with readelf but only if you link some library with $ORIGIN in rpath.
Here is example based on your question:
g++ main.cpp -o main -L./libusb -Wl,-rpath,'$ORIGIN/libusb' -lusb
As you see, you need to provide -L directory for compile/link time search, and rpath for runtime linker. Now you will be able to examin all needed libs for your app using readelf and location for search.

How to run c program with .so file

I have gone through all the solutions on StackOverflow as well as Ask Ubuntu.
I have a Go program:
package main
import "C"
//export Getint
func Getint() int {
return 2
}
func main() {}
and I have generated .so file for the same with name t.so and header filet.h`
Now I would like to use this function in my C program.
I have written the code but I don't know how to execute it.
#include <stdio.h>
#include <t.h>
int main()
{
int a;
a=Getint();
printf("number : %d",a);
return 0;
}
When I execute it with
gcc c.c t.so
it generates a.out file
but at the time of running a.out with ./a.out it gives an error:
./a.out
Error while loading shared libraries: t.so: can not open shared object file: no such file or directory exists.
then I tried with:
gcc -c c.c -l t.so
So it generates c.o file and it is not executable.
You should use the linker option -rpath, which tells the linker to add information in the executable program where to find runtime libraries like your .so file.
This can be done using the GCC option -Wl which instructs the GCC frontend program to pass an option to the linker:
$ gcc c.c t.so -Wl,-rpath=$(pwd)
This will pass -rpath=$(pwd) to the linker, and $(pwd) causes the shell to call the pwd command to return the current directory.
As long as you don't move the library the program should work.
You can use the environment variable LD_LIBRARY_PATH too, but it's not recommended.
Most probably your loader cannot find the library. Try to put the path to the directory where the libarry is located to LD_LIBRARY_PATH prior to run your binary.
export LD_LIBRARY_PATH=/path/to/my/library
./a.out
.so files are shared object, meaning object that are available to all applications that need them.. that is, shared. Due to this characteristics, they need to be stored in a well known place. Also, they need to be indexed by the dynamic linker.
In linux for instance you typically have a file /etc/ld.so.conf where all directories where shared object are automatically read from are stored
So your options are:
Put your shared object file in a well known place
Put your shared object file in a place of your choice and let the dynamic linker know about it: in linux you can modify ld.so.conf and run ldconfig to update ld indexes
As other suggested write the path of your .so in the env variable LD_LIBRARY_PATH (since dynamic linker reads it before running your application). This must be done at each environment creation
As other suggested use -rpath when compiling. Note that in this way you cannot move your .so file after the compilation
Personally I prefer installing the .so file in a system library path
You should use LD_LIBRARY_PATH to let the dynamic linker find your shared library in the list. Syntax is similar to PATH a list of directories separted by :.
On OSX this environment variable is called DYLD_LIBRARY_PATH.

Resources