Undefined symbol error in a shared library loaded at runtime - c++

(I know various iterations of this question are asked here routinely but I didn't find anything that helped)
I'm trying to write a simple dynamic library and load it at runtime.
The library files:
mul.h
int mul(int a, int b);
mul.cpp
#include "mul.h"
int mul(int a, int b) {
return a * b;
}
Then I have this Makefile:
mul.cpp: mul.h
mul_lib: mul.cpp
g++ -Wall -fPIC -shared $< -o bin/libmul.so
bin/test.o: mul_lib
g++ test.cpp -ldl -o bin/test
So I have created an .so file, and I checked using nm that there's a symbol for mul... or rather what I assume is the symbol for mul:
>nm -D bin/libmul.so
w __cxa_finalize
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
00000000000010f9 T _Z3mulii
In test.cpp, I'm trying to load this library with dlopen:
typedef int (*mul_func)(int a, int b);
void* mul_lib = dlopen("bin/libmul.so", RTLD_NOW);
if (!mul_lib) {
/* fail to load the library */
fprintf(stderr, "Error: %s\n", dlerror()); // we don't exit here, library loaded
return 2;
}
mul_func* func = (mul_func*)dlsym(mul_lib, "mul");
if (!func) {
fprintf(stderr, "Error: %s\n", dlerror()); // we exit here
return 2;
}
(*func)(2, 4);
dlclose(mul_lib);
But I'm getting bin/libmul.so: undefined symbol: mul
I don't understand why. The symbol is present in the object file, it seems, and it's loaded correctly (I assume), so why is the symbol absent?

Turns out declaring a function like this works:
extern "C" int mul(int a, int b);
For more information on why, see this comment.

Related

ldd does not show the dependency which make then needs

I have the program which needs v2xmvtest.so. When i try to build it via make i get undefined reference to *
Seems like that function from libssl1.0. (If i install it, it's built fine)
But i do not see the place where these function are used. More than that, when i try ldd v2xmvtest.so it does show only libvssl1.1 dependency.
Summary:
Is there a way to find out where those finctions from libvssl1.0 are used in the program ? (i have source code of the v2xmvtest.so and try to search, but there no any of these)
I need a description why ldd does not show me libssl1.0 dependency, but during linkning it's needed
Thank you!
Libraries are not required to fully define used symbols. For instance you can have lib.cpp:
int foo();
int bar(int x)
{
return x + foo();
}
and it compiles even foo is actually not defined yet:
g++ lib.cpp -shared -o lib.so
Then you can have main.cpp:
#include <iostream>
int bar(int);
int foo()
{
return 10;
}
int main()
{
std::cout << bar(42) << std::endl;
}
which defines foo and compiles successfully with lib.so:
g++ main.cpp lib.so -o main
The foo function in lib.so is expected just to be provided when the application is linked and is not specified where exactly from, even not necessary from a library.
You can check for undefined symbols in a library using nm tool:
nm -C -u lib.so
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
U foo()
w __cxa_finalize##GLIBC_2.17
w __gmon_start__
And finally you can force gcc to ensure no undefined symbols are used by the object files by compiling with -Wl,-z,defs linker flag:
g++ lib.cpp -shared -Wl,-z,defs -o lib.so
...
lib.cpp:(.text+0x24): undefined reference to `foo()'

Find static library unresolved dependencies before linking executable

So let's say we have static library mylib.a, which contains compiled cpp files.
file1.cpp:
int do_stuff();
int func_unres()
{
int a = do_stuff();
return a;
}
file2.cpp:
int do_other_stuff();
int func_res()
{
int a = do_other_stuff();
return a;
}
file3.cpp:
int do_other_stuff()
{
return 42;
}
So, as we can see here, no file contains definition of do_stuff function.
Library created this way:
g++ -c file1.cpp -o file1.o
g++ -c file2.cpp -o file2.o
g++ -c file3.cpp -o file3.o
ar r mylib.a file1.o file2.o file3.o
Now we try to make some binary with this library. Simple example main file:
#include <iostream>
int func_res();
int main()
{
std::cout << func_res() << std::endl;
}
Compiling:
g++ main.cpp mylib.a -o my_bin
Everything works just fine.
Now consider case of main file like this:
#include <iostream>
int func_unres();
int main()
{
std::cout << func_unres() << std::endl;
}
In this case binary won't link, cause func_unres requires function do_stuff to be defined.
Is there a way to find out that static library requires symbol which no object file in the library contains before linking it with executable, which uses such symbol?
EDIT:
The question is not how to simple list such symbols, but to get an output with linker like error.
Like if i linked this library with executable using all of symbols it should contain.
It seems that as pointed in comments and in How to force gcc to link an unused static library, linker option --whole-archive is enough to force resolve all symbols and output linker error for all unresolved symbols in static library. So referring the question examples, compiling and linking this way first main file, which doesn't refer undefined symbol, will output linker error anyway:
g++ main.cpp -Wl,--whole-archive mylib.a -Wl,--no-whole-archive
Linking fails despite main doesn't use func_unres:
mylib.a(file1.o): In function func_unres(): file1.cpp:(.text+0x9):
undefined reference to do_stuff()
Second option --no-whole-archive is used so the rest of required libraries' symbols will not be force resolved like this.

shared library with Undefined Behavior Sanitizer (clang++)

I have a problem while running an executable file with dlopen function used to open shared and sanitized library with a one simple function.
I use precompiled Clang 3.9.0 for Ubuntu 14.04.
My question is: Is it possible to run it properly, so I can look for undefined behavior errors in the library while running an executable ? If the answers is yes, then how ?
I have two files:
//simpledll.cpp
#include <cstdio>
int hehe(int argc) {
int k = 0x7fffffff;
k += argc;
return 0;
}
//dlopen.cpp
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main() {
void* handle;
handle = dlopen("simpledll.so", RTLD_LAZY);
if(!handle) {
fprintf(stderr, "%s\n", dlerror());
}
int (*function)(int) = reinterpret_cast<int (*)(int)> (dlsym(handle, "_Z4hehei"));
if (function == nullptr)
fprintf(stderr, "Nope\n");
else
function(1000); // this yields signed integer overflow
return 0;
}
I have tried to get it to work in two steps (both have failed)
Step I
Compile the executable with:
clang++ dlopen.cpp -ldl --std=c++11 -o dlopen
Compile the library with:
clang++ -fsanitize=undefined -shared -o simpledll.so -fPIC simpledll.cpp
Result:
./dlopen: symbol lookup error: simpledll.so: undefined symbol: __ubsan_handle_add_overflow
Step II (idea from this forum)
Compile the executable as in Step I,
Compile the library with:
clang++ -fsanitize=undefined -shared -Wl,--whole-archive -L/usr/local/lib/clang/3.9.0/lib/linux/ -lclang_rt.ubsan_standalone_cxx-x86_64 -Wl,--no-whole-archive -lclang_rt.ubsan_standalone-x86_64 -Wl,--no-whole-archive -o simpledll.so -fPIC simpledll.cpp
Result:
==11478==Sanitizer CHECK failed: /home/development/llvm/3.9.0/final/llvm.src/projects/compiler-rt/lib/ubsan/ubsan_init.cc:61 ((UBSAN_MODE_UNKNOWN)) != ((ubsan_mode)) (0, 0)
Note that in Step II, if we substitute the function in the shared library with the one that has no undefined behavior code, the program runs without a CHECK failed error. This indicates that UBSAN has found an undefined behavior code, however it was unable to report it properly.
Regards,
Jaszczur

How to export specific symbol from executables in GNU/Linux

While loading dynamic libraries by ::dlopen(), exporting symbols from executables can be done by -rdynamic option, but it exports all the symbols of the executable, which results in bigger binary size.
Is there a way to export just specific function(s)?
For example, I have testlib.cpp and main.cpp as below:
testlib.cpp
extern void func_export(int i);
extern "C" void func_test(void)
{
func_export(4);
}
main.cpp
#include <cstdio>
#include <dlfcn.h>
void func_export(int i)
{
::fprintf(stderr, "%s: %d\n", __func__, i);
}
void func_not_export(int i)
{
::fprintf(stderr, "%s: %d\n", __func__, i);
}
typedef void (*void_func)(void);
int main(void)
{
void* handle = NULL;
void_func func = NULL;
handle = ::dlopen("./libtestlib.so", RTLD_NOW | RTLD_GLOBAL);
if (handle == NULL) {
fprintf(stderr, "Unable to open lib: %s\n", ::dlerror());
return 1;
}
func = reinterpret_cast<void_func>(::dlsym(handle, "func_test"));
if (func == NULL) {
fprintf(stderr, "Unable to get symbol\n");
return 1;
}
func();
return 0;
}
Compile:
g++ -fPIC -shared -o libtestlib.so testlib.cpp
g++ -c -o main.o main.cpp
I want func_export to be used by the dynamic library, but hide the func_not_export.
If link with -rdynamic,
g++ -o main -ldl -rdynamic main.o
, both functions are exported.
If not link with -rdynamic,
g++ -o main_no_rdynamic -ldl main.o
, I got runtime error Unable to open lib: ./libtestlib.so: undefined symbol: _Z11func_exporti
Is it possible to achieve the requirement that only export the specific function?
Is there a way to export just specific function(s)?
We needed this functionality, and added --export-dynamic-symbol option to the Gold linker here.
If you are using Gold, build a recent version and you'll be all set.
If you are not using Gold, perhaps you should -- it's much faster, and has the functionality you need.

Cannot link to shared library

I'm trying to compile a minimal shared library and link to it and have been failing for two hours now. Here is ALL the code:
// rect.h
class Rect{
private:
int width_, height_;
public:
Rect(int width, int height);
int width();
int height();
};
// rect.cpp
#include "rect.h"
Rect::Rect(int width, int height)
:width_(width), height_(height){}
int Rect::width() { return width_; }
int Rect::height() { return height_; }
// client.cpp
#include "rect.h"
#include <iostream>
int main() {
std::cout << Rect(1,2).width();
return 0;
}
And this is how I try to compile it:
$ g++ -shared -o librect.so rect.cpp
$ g++ -L. -lrect -Wl,-rpath,'.' client.cpp -o client
/tmp/cc0Xe7ms.o: In function `main':
client.cpp:(.text+0x1a): undefined reference to `Rect::Rect(int, int)'
client.cpp:(.text+0x26): undefined reference to `Rect::width()'
collect2: error: ld returned 1 exit status
The library compiles just fine and the Rect class is properly exported from what I can tell:
$ nm -D librect.so
0000000000201028 B __bss_start
w __cxa_finalize
0000000000201028 D _edata
0000000000201030 B _end
0000000000000738 T _fini
w __gmon_start__
00000000000005b8 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000714 T _ZN4Rect5widthEv
0000000000000724 T _ZN4Rect6heightEv
00000000000006f0 T _ZN4RectC1Eii
00000000000006f0 T _ZN4RectC2Eii
The strangest thing is that this compiles fine and works on my work computer (Kubuntu 12.10 64bit) but fails to link properly on any other machine I've tried (4 in total, all 64-bit Ubuntu/Kubuntu 12.04 and 12.10)
I tried everything I could think of. Passing the verbose option to the linker shows that the librect.so is indeed found successfully.
Does anybody have a clue what the problem might be?
The libraries have to go after the local translation units:
g++ -L. -Wl,-rpath,'.' client.cpp -o client -lrect
# ^^^^^^
It has to do with how unresolved symbols are looked up by the linker; search the internet for a plethora of information on this if you're curious.