Expose symbols to dynamic linker when linking with native library in Rust - rust

I am building a binary executable in Rust and it needs to link to a native library, say foo.a. foo.a contains a symbol void bar(void), which I would like to expose to the dynamic linker as a callback function that can be called by functions in a dlopen-style dynamically loaded library.
This can be done in ld by supplying -rdynamic if we use C source.
gcc -rdynamic -o a_dynamic main.c foo.c
What is the proper way of doing this in Rust? I have tried using cargo:rustc-flags=-rdynamic in build.rs, as well as
#![feature(link_args)]
#[link_args = "-rdynamic"]
Neither seems to work.

As of today, Rust toolchain discourages passing arbitrary flags to the linker. The closest we can do as a proper way is using cargo rustc and manually add the linking arguments.
cargo rustc -- -C link-args='-rdynamic'

Related

g++ -static flag replaces the dynamic library loader [duplicate]

This question already has answers here:
Use both static and dynamically linked libraries in gcc
(3 answers)
Closed 5 years ago.
First of all I would like to give some background information to avoid the XY Problem.
I am trying to compile a c++ program using makefiles and g++. I also have to build any dependencies statically into the program, but not the 'system libraries' (libz.so, libdl.so, libstdc++.so, libm.so, libpthread.so, libc.so and libgcc.so).
To achieve this I specify -static as linker flag, then all dependencies that have to be statically linked and then I use the -Wl, -Bdynamic option, that should tell the linker to link every library, after this option, to be linked in dynamically including the 'system libraries' because they get linked last.(please correct me if I am wrong.)
LDFLAGS += -Lpath/to/dependencies
# These libs should be linked statically
LDFLAGS += -static
LDFLAGS += -llib1
LDFLAGS += -llib2
LDFLAGS += -llib3
# Libs after this should be linked dynamically.
LDFLAGS += -Wl, -Bdynamic
LDFLAGS += -lz # If i dont specify these three libraries (z, pthread, dl)
LDFLAGS += -lpthread # I get undefined reference errors
LDFLAGS += -ldl
When I call make, the program compiles and links just fine, but when I try to execute it I get the error: bash: ./program: No such file or directory.
But the file DOES exist.
When I remove the -static flag from the linker, the program can be excecuted just fine, but the dependencies are linked dynamically, which is not what I want :(.
So when I call file on the program, that was made with the -static flag, I get this:
program: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib/libc.so.1, for GNU/Linux 4.9.0, not stripped
The problem seems to be that the interpreter is set to /usr/lib/libc.so.1 and not to /lib/ld-linux.so.2 as it should usually be. At least it is, when I compile without the -static option.
What I found out is that the 'interpreter' is in reality the shared library loader and from what I read, I now assume that the bash tells me it can not find the program because the library loader is just wrong (Even though I don't quite understand the details of this).
So basically my question is: Why does the library loader get set to libc.so when I specify the -static option to the linker and how can I tell the linker to use the correct library loader when -static is specified?
Your error is mixing -static and -Bdynamic as both compiler and linker flags. Don't do that. If you use -Wl, gcc just blindly pass these flags to the linker, but if you don't, it rearranges the entire link line. (check what it does with gcc -v).
The mix creates an inconsistent and erroneous link command. I have no idea why gcc doesn't at least warn about that, but it doesn't, and silently sets the dynamic loader to a non-existent file.
You want to use -Wl,-Bstatic and -Wl,-Bdynamic consistently throughout. Not -Bstatic and -Bdynamic, as gcc logic is different from that of ld.
This will create a correct dynamically linked executable with some static libs linked in.

How to resolve extern variable from dlopen'd library

Is it possible have a global variable defined inside an application, accessed by a shared library that has been loaded with dlopen()?
I have it declared as an extern but when the app loads and tries to use it I get an undefined symbol error.
I am loading the library with flags set to RTLD_LAZY | RTLD_GLOBAL.
You have to you build your application where you have a global variable with -rdynamic option for g++. This option instructs the linker (ld) to add all symbols, not only used ones, to the dynamic symbol table of your application.
This is an example how I build my test C++ application that loads a shared library. The shared library uses a global variable in main.cpp. So I have added -rdynamic when build my main application:
g++ -rdynamic -m64 -g main.cpp -o main -ldl
When g++ finds -rdynamic it passes the flag -export-dynamic to the ELF linker (ld).
This is from man ld (which actually creates the dynamic symbol table):
If you use "dlopen" to load a dynamic object which needs to refer back
to the symbols defined by the program, rather than some other dynamic
object, then you will probably need to use this option when linking
the program itself.
Useful links:
http://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Link-Options.html
http://linux.die.net/man/1/ld

Any way to make LD record shared library name only, no subdirs?

I am linking a Linux executable referencing a shared library:
g++ Debug/file.o Debug/MyLib.so -o Debug/MyApp -Wl,--rpath='$ORIGIN'
The problem is that the generated MyApp file references "Debug/MyLib.so" so if I run it from the Debug directory, it does not find it. Thus, specifying -Wl,--rpath='$ORIGIN' does not help.
Is there a way to tell the GNU LD to use the 'Debug/MyLib.so' file, but record it as just 'MyLib.so' inside the executable?
If don't want to change the name of your library, you can use the soname option when
you create it.
For example:
build the library
$> g++ -fpic -c mylib.cpp
$> g++ -shared -o subdir/mylib.so mylib.o -Wl,-soname=mylib.so
build the program
g++ -o subdir/main main.cpp -Lsubdir -l:mylib.so -Wl,-rpath='$ORIGIN'
(Don't forget the colon after the -l option)
You're linking inappropriately for a shared library. You should rename the library to libMyLib.so, and link your executable using:
g++ Debug/file.o -o Debug/MyApp -Wl,--rpath='$ORIGIN' -LDebug -lMyLib
What the -LDebug says is search in the Debug directory for libraries at link time, and then the -lMyLib says look for a library called libMyLib.so (or libMyLib.a) in the paths that -L specifies, plus the standard library search path.
The standard naming convention for libraries under linux/unix is libLibraryName, and the linker knows when you ask to link to a library using -l, that it should look for a file prefixed lib thatname
When you used it in the prior form, it actually recorded the absolute library that was used when linking, rather than the normal mechanism of just recording the name of the library, and relying on the runpath to resolve the path to the library.

Mixing static libraries and shared libraries

I have a project where I have one static library libhelper.a and another with my actual shared object library, libtestlib.so. My goal is to link libhelper.a into libtestlib.so. Is that possible on Linux/BSD? When I tried and created a test program I got the following errors:
./prog1:/usr/local/lib/libtestlib.so.1.0: undefined symbol ''
My guess is that this is occurring because libhelper.a was not compiled with -fPIC while libtestlib.so was. What is the proper way to build programs that use shared libraries that also have dependancies on static libraries?
Thanks!
My goal is to link libhelper.a into libtestlib.so. Is that possible on Linux?
Sure. This should do:
gcc -shared -fPIC -o libtestlib.so $(OBJS) \
-Wl,--whole-archive -lhelper -Wl,--no-whole-archive
libhelper.a was not compiled with -fPIC
It's best to rebuild libhelper.a with -fPIC. If that's not possible, above command will still work on Linux/ix86, but not on e.g. Linux/x86_64.
What is the proper way to build programs that use shared libraries that also have dependancies on static libraries?
If you include libhelper.a into libtestlib.so as above, then simple:
gcc main.c -ltestlib
is all you need. If you insist on linking with libhelper.a, then you must tell the end-user that he must link with e.g.
gcc main.c -ltestlib -lhelper
There is no way to specify that libtestlib.so depends on libhelper.a.

Trying to statically link Boost

I am working in Linux, Eclipse CDT, g++, with Boost library. Having existing program which uses Boost thread, I try to link it statically instead of dynamically. /usr/local/lib directory contains the following files:
libbost_thread.a
libbost_thread.so
libbost_thread.1.41.0
Dynamic linking works:
g++ -o"MyProgram" ./main.o -lboost_thread
Static linking:
g++ -static -o"MyProgram" ./main.o -lboost_thread
produces huge number of messages like:
undefined reference to `pthread_mutex_init'
How can I link statically to the Boost library?
For pthread_mutex_init, you want to compile/link with -pthread option:
g++ -static -pthread -o"MyProgram" ./main.o -lboost_thread
The problem is that functions like pthread_mutex_init are in a separate library. Dynamic libraries can include the metadata for the fact that it needs the separate library (so libboost_thread.so includes the fact that it needs libpthread).
But static libraries don't have that information. So you need to provide the reference to any necessary libraries when you link statically.
As for using -pthread instead of -lpthread, it's slightly preferable because it not only links the necessary library, but provides any other options that should be used (such a -D_REENTRANT to the compiler).
Try adding -lpthread to your invocation.
On Linux a dynamic library may automatically depend on other dynamic libraries so that when you link it, you get the other libraries for free. When linking statically, there is no such system and you have to specify the other libraries manually.

Resources