After spending almost an hour on filtering output of
clang -v hello_world.c
I got the following linking command:
ld -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
/usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o \
hello_world.o /usr/lib/x86_64-linux-gnu/libc.so \
/usr/lib/x86_64-linux-gnu/crtn.o
Is there an easier way to find out that -lc will expand to /usr/lib/x86_64-linux-gnu/libc.so?
I need to know which files are used so I can copy them to another system for cross compiling.
edit
Looks like I should use the cross-compile toolchain. From clang docs:
https://clang.llvm.org/docs/CrossCompilation.html
When you have extracted your cross-compiler from a zip file into a
directory, you have to use --sysroot=. The path is the root
directory where you have unpacked your file, and Clang will look for
the directories bin, lib, include in there.
Where can I get that zip file they refer to? I'm interested in x86_64-linux-gnu target.
This will list all the files linked to libc.so.6:
for i in `find . -type f -executable`
do
j=$(ldd $i | grep libc.so.6 | wc -l)
if [ $j -gt 0 ]
then
echo $i
fi
done
In case you want to find out what the path of libc.so.6 is, stated in the original question something similar to:
ldd `which ld` | sed 's/^[[:space:]]libc.so.6[[:space:]]=>[[:space:]]\(.*\)[[:space:]](.*)/\1/p' | grep --color=never libc.so
will type the path, you can obviously replace the expression after ldd with any filename.
From the comments, there is a way with clang directly though it will generate a lot of noise which is significantly harder to exclude compared to the ldd way.
clang -Wl,--verbose hello_world.c
will tell the linker to be verbose and it will eventually tell you all the library paths tried for each library.
Related
XML::LibXML is a Perl library. LibXML.so is a part of the library. I'm trying to make XML::LibXML use custom built libxml2. But providing LD_LIBRARY_PATH doesn't make any difference:
$ ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f66af5e9000)
$ LD_LIBRARY_PATH=/home/yuri/_/libxml2/.libs ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f2d26ae3000)
$ ldd /usr/lib/python3.7/site-packages/libxml2mod.so | grep libxml2
libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f878cbc8000)
$ LD_LIBRARY_PATH=/home/yuri/_/libxml2/.libs ldd /usr/lib/python3.7/site-packages/libxml2mod.so | grep libxml2
libxml2.so.2 => /home/yuri/_/libxml2/.libs/libxml2.so.2 (0x00007f6f8f5d8000)
What am I doing wrong? Is there a way to handle it? The goal is to make Perl script use custom built libxml2 (to investigate some issue).
UPD
$ find /usr/lib -name libxml2.so.2
/usr/lib/libxml2.so.2
/usr/lib/vmware-installer/2.1.0/lib/lib/libxml2.so.2
/usr/lib/vmware-installer/2.1.0/lib/lib/libxml2.so.2/libxml2.so.2
/usr/lib/vmware-vmrc/5.5/lib/libxml2.so.2
/usr/lib/vmware-vmrc/5.5/lib/libxml2.so.2/libxml2.so.2
$ find /usr/local/lib -name libxml2.so.2
tl;dr
ExtUtils::MakeMaker hardcodes paths of the shared libraries in the binaries by means of RPATH entry in .dynamic section. But you can preload the needed library,
$ LD_PRELOAD=path/to/custom/libxml2/.libs/libxml2.so.2 ldd ./blib/arch/auto/XML/LibXML/LibXML.so
or make the loader ignore RPATH entry,
$ LD_LIBRARY_PATH=path/to/custom/libxml2/.libs /usr/lib/ld-linux-x86-64.so.2 --inhibit-rpath /abs/path/to/LibXML.so /abs/path/to/perl ./1.pl
or convert RPATH entry into RUNPATH one,
$ chrpath --convert blib/arch/auto/XML/LibXML/LibXML.so
or delete RPATH entry,
$ chrpath --delete blib/arch/auto/XML/LibXML/LibXML.so
or specify XMLPREFIX variable,
$ perl Makefile.PL XMLPREFIX=path/to/custom/libxml2/build
Under the hood
ExtUtils::Liblist::ext() takes a list of libraries to be linked with, like -lxml2 -lz -llzma -licui18n -licuuc -licudata -lm -ldl, and turns them it into four or five variables, that make their way into the generated Makefile. One of those is LD_RUN_PATH. It contains all the paths where the libraries where found.
$is_dyna is true if the library is dynamic (not ends with .a). $is_perl is true if Perl was not built with it, and %ld_run_path_seen is to not duplicate values in LD_RUN_PATH.
The part that calculates LD_RUN_PATH, that generates part of the Makefile with the variable, and the part that passes it to the linker.
Consequences
LD_RUN_PATH and in its turn RPATH entry in the binary make the loader search for libraries (at runtime) in the directories where they where found (at compile time).
-rpath=dir
Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable "LD_RUN_PATH" will be used if it is defined.
https://jlk.fjfi.cvut.cz/arch/manpages/man/core/binutils/ld.1.en
If a shared object dependency does not contain a slash, then it is searched for in the following order:
o Using the directories specified in the DT_RPATH dynamic section attribute of the binary if present and DT_RUNPATH attribute does not exist. Use of DT_RPATH is deprecated.
o Using the environment variable LD_LIBRARY_PATH, unless the executable is being run in secure-execution mode (see below), in which case this variable is ignored.
https://jlk.fjfi.cvut.cz/arch/manpages/man/core/man-pages/ld.so.8.en
$ perl Makefile.PL
$ make
Result,
$ readelf --dynamic ./blib/arch/auto/XML/LibXML/LibXML.so | grep RPATH
0x000000000000000f (RPATH) Library rpath: [/usr/lib]
$ objdump -x ./blib/arch/auto/XML/LibXML/LibXML.so | egrep RPATH
RPATH /usr/lib
$ LD_LIBRARY_PATH=path/to/custom/libxml2/.libs ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
libxml2.so.2 => /usr/lib/libxml2.so.2 (0x00007f6cfabb2000)
--dynamic - display contents of the .dynamic section, -x - display all headers.
Solution
One way to remedy this is to preload needed instance of libxml2,
$ LD_PRELOAD=path/to/custom/libxml2/.libs/libxml2.so.2 ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
path/to/custom/libxml2/build/lib/libxml2.so.2 (0x00007fe183aeb000)
Another is to tell Makefile.PL search for libxml2 in the desired location (at compile time).
$ perl Makefile.PL XMLPREFIX=path/to/custom/libxml2/build
$ make
Result,
$ readelf --dynamic ./blib/arch/auto/XML/LibXML/LibXML.so | grep RPATH
0x000000000000000f (RPATH) Library rpath: [path/to/custom/libxml2/build/lib:/usr/lib]
$ objdump -x ./blib/arch/auto/XML/LibXML/LibXML.so | egrep RPATH
RPATH path/to/custom/libxml2/build/lib:/usr/lib
$ ldd ./blib/arch/auto/XML/LibXML/LibXML.so | grep libxml2
libxml2.so.2 => path/to/custom/libxml2/build/lib/libxml2.so.2 (0x00007fe183aeb000)
On a side note
Should you care to debug XML::LibXML, you can run make with OPTIMIZE variable (add -B to make make rebuild everything in case the library has already been built),
$ make OPTIMIZE='-g3 -O0'
There's also -O2, and no -g in LDDLFLAGS, but not sure if that matters much.
Alternatively, WriteMakeFile takes OPTIMIZE parameter, so you can add a line here,
'OPTIMIZE' => '-g3 -O0'
Or you can add the variable here, and pass it to Makefile.PL,
$ perl Makefile.PL OPTIMIZE='-g3 -O0'
If you install your custom built version of libxml in /usr/local/lib, I think the XML::LibXML module should load the custom one rather than the one in /usr/lib (Assuming you have sudoers or root permission to install it).
I'm not sure why Python seems to use a different lookup path for libraries than Perl does, though. Maybe the full path to libxml library is hardcoded in XML::LibXML's LibXML.so? If the XML::LibXML module was linked with -l/usr/lib/libxml2.so instead of -lxml2 that would be the problem.
I am trying to manually do all the compilation steps of my program. In the last step where I use the linker command ld, I need to specify the object file for library(stdio as I have used printf in my code) then only I can make and .exe file. Where does this object file reside?
I'd suggest that you run gcc -v your_file.c. That will let you see exactly what commands your linker is using. You probably don't have an stdio.o file to link against. Instead this is included in the C runtime library and the exact file will depend on your system configuration.
stdio is part of the C standard library. The exact location of the standard library is system-specific, but it is often in a file called libc.a or libc.so.
In my machine this can be found in:
/usr/lib/x86_64-linux-gnu/libc.a
/usr/lib/x86_64-linux-gnu/libc.so
You can ask ld for the search directory: ld --verbose | grep SEARCH_DIR.
libc.a is an ar (man) archive, and you can extract stdio.o from the libc.a archive using ar command:
$ # list archive member with `ar t`
$ ar t /usr/lib/x86_64-linux-gnu/libc.a | grep ^stdio
stdio.o
$ # extract stdio.o with `ar x`
$ ar x /usr/lib/x86_64-linux-gnu/libc.a stdio.o
its probably under root
Somthing like /usr/lib or /usr/lib***
I have 25 object files which are combined to form one shared library. I have generated the shared library with gcc and while I was looking for exposed symbols with nm -D libmylib.so, I found two undesirable exposed symbols with the name of i and y which are in .bss section. I have tried to find them in my source files but i cant find them so if anyone can tell me whether there is some way to find that which .o file exactly has these undesired exposed symbols? Can I do it with nm or do I need another tool?
Any help would be appreciated.
Once the shared library is linked, you can no longer tell which parts of it came from which object file.
You can search the individual objects from which you build the library:
find . -name '*.o' -print0 | xargs -0 nm -A | egrep ' (i|y)$'
You can ask the linker to tell you when they are defined:
$(CC) -fPIC -shared -o libmy.so $(OBJS) -Wl,-y,i,-y,y
If you built the library from objects compiled with -g, you may ask GDB where i and y came from:
gdb -q libmy.so
(gdb) info var ^i$
(gdb) info var ^y$
In the directory with your object files you can run:
find . -name '*.o' -exec nm -D {} \; -print
This should print symbols and then file name
Is there a tool around that will list all the global variables in a C program? More specifically, is there a simple commandline tool that will do this, i.e. not a heavyweight IDE, CASE, graphical toolkit system etc., but just something that can be run like foo *.c?
ctags -R -x --sort=yes --c-kinds=v --file-scope=no file "c:\my sources" > c:\ctagop.txt
If you happen to compile the file on most unixes you have nm that just lists you all linker symbols. These symbols are classified in different groups (a bit platform dependent) so you should easily find out which the variables are.
Try ctags. Or, gcc with -aux-info. There is also gccxml and libclang but those two aren't very simple.
to list all globals (linux/gnu) for program 'foo':
if the program is compiled with -g (gcc -g -o foo main.c)
nm foo | grep " B " | sed -e "s/^[^B]*B//g"
will list all globals, nm lists the objects, grep seperates out the global variables, and sed cleans up the presentation.
Actually most stuff I compile is with Makefiles so it is CFLAGS=-g -pg -Wextra in the Makefile, so the executable can be scanned until a 'make dist'
user1717828 on stackechange provided the grep template
I am compiling a big project. This project is using shared libraries, especially lapack ones.
I would want to be sure, for a given function, in which shared library the system finds it.
Here the nm output:
$ nm -DC ~/bin/app | grep potrf
U dpotrf_
As expected, dpotrf_ is undifined.
Here the result with objdump:
$ objdump -TR ~bin/app | grep potrf
0000000000925428 R_X86_64_JUMP_SLOT dpotrf_
So objdump find something! Is there any option to show in which shared lib it finds it? Or another program to do that?
ldd is definitely a starting point to find the candidate libraries. Here's what I have in my .bashrc for such purposes (not beautiful, but serves my purposes).
Basically, I do nm on all libraries (.a, .so) in a subdirectory. If nm produces an output for the searched symbol, I print the library name and the relevant lines from nm. Your last step would then be to search for lines starting with "T" as these are the ones defining your symbol as program code (text).
# run nm on a set of objects (ending with the 1st parameter) and
# grep the output for the 2nd parameter
function nmgrep ()
{
for i in $( find \. -name \*$1 ); do
if [[ ! -e $i ]]; then
continue;
fi
nm $i | grep $2 > /tmp/foo.tmp;
if [[ -s /tmp/foo.tmp ]]; then
echo $i;
cat /tmp/foo.tmp | grep $2
fi
rm /tmp/foo.tmp
done
}
# find symbols definied/referenced in libs
function libgrep ()
{
nmgrep .a $#
nmgrep .so $#
}