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

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

Related

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.

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.

SysGCC toolchain can't find files in sysroot

I set up this toolchain on my Windows machine for my Pi (raspberry-gcc4.6.3-nosysroot.exe) and then I followed the instructions here to synchronize my sysroot.
I use a library called WiringPi in my project, and I have confirmed that it is in the synchronized sysroot:
Then I attempt to compile it:
arm-linux-gnueabihf-gcc -Wall -O -c main.c
But I get the following error:
fatal error: wiringPi.h: No such file or directory
What do I have to do to make the compiler find the header file? I thought the whole point of synchronizing the sysroot was to make this kind of thing work?
You'll have to let gcc know where to look for the include files via the -I argument. In the case above, -IC:\SysGCC\Raspberry\...\usr\local. You may have to add more than one include path, depending on where the required files are scattered. You can also try to set gcc's environment variable(s).
Finding out the correct include path can be a little tedious (see above: should it be local\ or local\include\?). Maybe you can find the environment setting for all default include paths on your Pi and just copy it over to your Windows machine.
Edit: Think I got it: echo | gcc -v -E -

Difference in commands to create executables from shared library

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.

Shared library in /usr/local/lib not found

I don't get it. I usually install third party software into /usr/local so libraries are installed into /usr/local/lib and never had problems linking to these libraries. But now it suddenly no longer works:
$ gcc -lkaytils -o test test.c
/usr/bin/ld.gold.real: error: cannot find -lkaytils
/usr/bin/ld.gold.real: /tmp/ccXwCkYk.o: in function main:test.c(.text+0x15):
error: undefined reference to 'strCreate'
collect2: ld returned 1 exit status
When I add the parameter -L/usr/local/lib than it works but I never had to use this before. Header files in /usr/local/include are found without adding -I/usr/local/include.
I'm using Debian GNU/Linux 6 (Squeeze) which has an entry for /usr/local/lib in /etc/ld.so.conf.d/libc.conf by default and the ldconfig cache knows the library I'm trying to use:
k#vincent:~$ ldconfig -p | grep kaytils
libkaytils.so.0 (libc6,x86-64) => /usr/local/lib/libkaytils.so.0
libkaytils.so (libc6,x86-64) => /usr/local/lib/libkaytils.so
So what the heck is going on here? Where can I check which library paths are searched by gcc by default? Maybe something is wrong there.
gcc -print-search-dirs will tell you what path the compiler checks. /usr/local/lib is simply not among them, so your compile time linker (in this case the new gold ld from binutils) doesn't find the library while the dynamic one (ld-linux.so which reads the cache written by ldconfig) does. Presumably the builds you've done previously added -L/usr/local/lib as necessary in their makefiles (usually done by a ./configure script), or you installed binaries.
This is probably an issue of environment variables - you have something set that's including /usr/local/include but not /usr/local/lib
From the GCC mapage on environment variables
CPATH specifies a list of directories to be searched as if speci‐
fied with -I, but after any paths given with -I options on the com‐
mand line. This environment variable is used regardless of which
language is being preprocessed.
and
The value of LIBRARY_PATH is a colon-separated list of directories,
much like PATH. When configured as a native compiler, GCC tries
the directories thus specified when searching for special linker
files, if it can’t find them using GCC_EXEC_PREFIX. Linking using
GCC also uses these directories when searching for ordinary
libraries for the -l option (but directories specified with -L come
first).
try "printenv" to see what you have set

Resources