Where do I see what parts of LLVM a library contain? - c++

I know how to see which libraries a certain component correponds to with the command:
llvm-config --libs core
Now, suppose I get a linker error and wants to include another library to resolve it.
Say, the linker can't resolve some symbol A. Then how do I:
1) Find the library that contains the specific symbol, like e.g. LLVMCore.lib.
2) Look up contents of libraries to see what symbols it defines?
I don't understand how to do this reading the documentation.

As you have already discovered a proper LLVM-way to do this would be using llvm-config by indicating the components you intend to link against or use, e.g.
llvm-config --cxxflags --ldflags --system-libs --libs core
Other common non-llvm specific methods that you can use to find a symbol: on a Win platform (use VS native tools cmd or equivalent environment-set one):
for %f in (*.lib) do (dumpbin.exe /symbols %f | findstr /C:"your_symbol")
if you can't deal with findstr's limitations GNU grep might be a better choice.
If you have unix tools installed and in your PATH you can also use
for %f in (*.lib) do (nm -gC %f | findstr /C:"your_symbol")
as baddger964 suggests.
On a unix system:
for lib in $(find . -name \*.so) ; do nm -gC $lib | grep my_symbol | grep -v " U " ; done
(search *.so libraries in this directory for my_symbol; extern-only, demangle and exclude undefined symbols)
Given the above question 2 is trivial.

One way to see symbols of your lib is to use the nm command :
nm -gC mylib.so

Related

Linking in a static library failes, but linking a shared library succeeds

I can build my application against the shared library but I'm getting the unresolved symbol errors when linking it against the static version of the same library:
I can build my application this way:
g++ -lutils application.cpp -o application.exe
The above command links in the shared version of an utils library.
I'm trying link against the static version of the library like this:
g++ -l:utils.a application.cpp -o application.exe
Both times I'm using
export LD_LIBRARY_PATH=path/to/utils:$LD_LIBRARY_PATH
to inform g++ where utils.a is placed.
The unresolved symbol reported by ld is present in the output of the nm:
nm --defined-only path/to/utils.a
and is marked with the "T" (meaning that it is from the code section).
I'm trying to figure out what can be the reason of the problem.
Is it correct to use LD_LIBRARY_PATH to specify where to search for utils.a?
What is the exact command to verify that a static library defines (resolves) the symbol? Is the command
nm --defined-only path/to/utils.a
enough or should I use any additional options like
nm --defined-only --demangle path/to/utils.a
e.g.?
Just option -static should be enough for compiler. In case only one library has to be static, then -static- and lib name is short name not file name.
Is it correct to use LD_LIBRARY_PATH to specify where to search for utils.a?
As mentioned by #user10605163, LD_LIBRARY_PATH is not to find path to static library at compile and link time. It is an environment variable used in some Linux distribution to search shared libraries during run time. Please find more documentation here It is useful for build and test environment but not a recommended way of linking in production systems.
What is the exact command to verify that a static library defines (resolves) the symbol? Is the command nm --defined-only path/to/utils.a
Yes, that is correct. However based on the information provided this error is not likely an error with symbols not present in utils(as it worked with shared library), but with the linking.
Refer GNU documentation GCC link options
Excerpt:
-l library : Search the library named library when linking. The linker searches a standard list of directories for the library. The directories searched include several standard system directories plus any that you specify with -L.
Also, with -l link option you need to provide the library name (without 'lib' and extension) or full file name.
-lutils or -llibutils.a
You can also provide direct full path here only, if required.

g++ undefined reference although symbol is present in *.so file

I found a number of similar questions (e.g. this, that or this), but none of them helped me solve my problem. I have a *.so file (from the core of gnss-sdr) that, as indicated by:
$nm libgnss_system_parameters_dyn.so | c++filt |grep Gps_Eph
contains the symbol Gps_Ephemeris::Gps_Ephemeris(), which is supposed to be a constructor.
I've written some minimal code:
#include <iostream>
#include <core/system_parameters/gps_ephemeris.h>
int main(int argc,const char* argv[])
{
Gps_Ephemeris ge;
return 0;
}
which I compile with:
g++ main.cpp -std=c++0x -I some_include_path -L some_lib_path -l gnss_system_parameters_dyn`
The linker then complains:
/tmp/ccHCvldG.o: In function `main':
main.cpp:(.text+0x33): undefined reference to `Gps_Ephemeris::Gps_Ephemeris()'
collect2: error: ld returned 1 exit status
I also tried cmake, but the line it generated was similar to that (it just added -rdynamic before linking), and it still generated the exact same linker error.
Note that both the library and my minimal code are being compiled with the same compiler (g++-5), with the exact same flags and the same c++0x standard.
Addressing the answer by Maxim Egorushkin, the line:
nm --demangle --defined-only --extern-only libgnss_system_parameters.so |grep Gps_Eph
doesn't output anything. However, the symbol is defined in the static library (i.e. the *.a library):
00000000000006b0 T Gps_Ephemeris::Gps_Ephemeris()
00000000000006b0 T Gps_Ephemeris::Gps_Ephemeris()
Knowing that both are generated by cmake, in the following way:
add_library(lib_name SHARED ${sources_etc}) #for the *.so
add_library(lib_name_2 ${sources_etc}) #for the *.a
there should be no difference in symbols contained/defined in those libraries, right? I didn't notice anything in cmake's documentation on add_library. Am I missing something obvious?
The pedantically correct way to check that a .so exports a symbol is nm --demangle --dynamic --defined-only --extern-only <lib.so> | grep <symbol>.
Without --defined-only your command also shows undefined symbols.
Without --extern-only it also shows symbols with internal linkage which are unavailable for linking.
It looks like you need to link another library because Gps_Ephemeris::Gps_Ephermeris() is not resolved by linking libgnss_system_parameters_dyn.so. A good way to start is that library's documentation and examples.
I have found in the past that this type of error is caused by the lack of proper extern "C" { ... } bracketing in an include file.

How to print symbol list for .so file in OSX?

I have an .SO file (note, not .a, not .dylib and not .o) and I need to get symbol information from it on OSX.
I have tried
nm -gU lib.so
However, nothing is printed out.
I can't use otool because it's not an object file, and readelf does not exists on OSX. How do I get the symbol information?
Please note, that I am using this .so file in another project, and there is symbol information. I am able to load the library, and reference functions from it. However, I have yet to find a tool on OSX to let me print the symbol information from it.
As asked,
file lib.so
ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, stripped
Try using c++filt piped from nm:
nm lib.so | c++filt -p -i
c++filt - Demangle C++ and Java symbols.
-p
--no-params
When demangling the name of a function, do not display the types of
the function's parameters.
-i
--no-verbose
Do not include implementation details (if any) in the demangled
output.
EDIT: Based upon the new (ARM) info provided in the question, try using symbols instead:
symbols lib.so -arch arm | awk '{print $4}'
I've used awk to simplify output; remove to output everything.
Manual page : Symbols
https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/nm.1.html
Nm displays the name list (symbol table) of each object file in the argument list. If an argument is
an archive, a listing for each object file in the archive will be produced. File can be of the form
libx.a(x.o), in which case only symbols from that member of the object file are listed. (The paren-
theses have to be quoted to get by the shell.) If no file is given, the symbols in a.out are listed.

How do I find where a symbol is defined among static libraries

Suppose you work with a codebase comprising several tools and libraries and you want to port (or resurrect) some component within such codebase but any clue about where symbols lie within the various libs is either lost or will take ages to find out by looking at the code itself (yes improved documentation can avoid such issues but is quite demanding). What is the fastest way to discover in which library you can find symbols used in the code?
Assuming a linux box, the nm tool, listing names in library files, comes to the rescue.
It can be used to do an extensive search as follows: one can first find all the libraries available (assuming the project have been successfully compiled without the component you are adding) with a find, then such find can be enclosed in a loop where you call nm on all discovered libraries; the output you then grep for discarding "U" references (undefined symbols, aka where else the symbol is being used). On a single bash line that gives:
for lib in $(find base_path -name \*.a) ; do echo $lib ; nm $lib | grep my_symbol | grep -v " U " ; done
where:
base_path is the root of your codebase
my_symbol is the symbol you are looking for
The echo generates a list of all libraries found, which is not so clean since it outputs names of libs not holding the symbol, but it was the fastest way I found to have a direct reference to the library so when you see a:
base_path/component/libA.a
0000000000000080 D my_symbol
You have found your usual suspect.
Using nm, it is possible to list the symbols defined in a binary, and the --defined-only switch ignores undefined references.
Option 1: find
In a single command:
find $path -name \*.a -exec bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}" \;
where $path is the root of the file tree containing the binaries, and $symbol is the name of the symbol you are looking for.
Option 2: find + GNU parallel
Running nm on all files can take time, so it could be helpful to process the results of find in parallel (using GNU parallel):
find $path -name \*.a | parallel "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"
Option 3: fd
And at last, my favourite. Using the fd tool, that has a simpler syntax than find, is generally faster, and processes the results in parallel by default:
fd '.*\.a$' -x bash -c "nm --defined-only {} 2>/dev/null | grep $symbol && echo {}"
Simple benchmark
Searching for the gz_write symbol in /usr/lib on my laptop:
find takes around 23 seconds
find | parallel takes around 10 seconds
fd takes around 8 seconds
Using nm's --defined-only switch is helpful here since it will remove the undefined references. Below is a csh script that may be useful to others.
#!/bin/csh
#
#recurse from current dir and output name of any .a files
#that contain the desired symbol.
echo "Search for: $1"
foreach i (`find . -name '*.a'`)
nm --defined-only $i | grep $1
if ($status == 0) then
echo $i
endif
end

Find function signature in Linux

Given a .so file and function name, is there any simple way to find the function's signature through bash?
Return example:
#_ZN9CCSPlayer10SwitchTeamEi
Thank you.
My compiler mangles things a little different to yours (OSX g++) but changing your leading # to an underscore and passing the result to c++filt gives me the result that I think you want:
bash> echo __ZN9CCSPlayer10SwitchTeamEi | c++filt
CCSPlayer::SwitchTeam(int)
doing the reverse is trickier as CCSPlayer could be a namespace or a class (and I suspect they're mangled differently). However since you have the .so you can do this:
bash> nm library.so | c++filt | grep CCSPlayer::SwitchTeam
000ca120 S CCSPlayer::SwitchTeam
bash> nm library.so | grep 000ca120
000ca120 S __ZN9CCSPlayer10SwitchTeamEi
Though you might need to be a bit careful about getting some extra results. ( There are some funny symbols in those .so files sometimes)
nm has a useful --demangle flag that can demangle your .so all at once
nm --demangle library.so
Try
strings <library.so>
nm -D library.so | grep FuncName