With reference to the following code
test_linker.cpp
int main() {
srand(time(0));
for (int i = 0; i < 10; ++i) {
cout << rand() % 10 << endl;
}
return 0;
}
urandom.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <dlfcn.h>
int rand() throw() {
// get the original rand() function
static auto original_rand = (decltype(&rand)) dlsym(RTLD_NEXT,"rand");
cout << "Call made to rand()" << endl;
return original_rand();
}
When I try to compile the code with the following command
g++ -std=c++11 -Wall -Werror -Wextra -Wvla -pedantic -O3 urandom.cpp -c
g++ -std=c++11 -Wall -O3 test_linker.cpp urandom.o -ldl
everything works fine, but when I move the -ldl
flag to being before the files, the linker throws an error saying
urandom.cpp:(.text+0xaf): undefined reference to `dlsym'
Question 1 Could someone explain why this would happen? I generally do not care about the order of flags in a compilation command.
Question 2 Also is it wrong to keep the function pointer to the original rand()
function a static variable? I do not know how exactly dynamic linking works and I am afraid that maybe the function address is moved around in memory at runtime. The manual pages said that the dlsym()
function with the RTLD_NEXT
handle is an expensive computation so I just wanted to lazily evaluate this once.
Note : I am compiling this on a Linux distribution and the Linux dynamic linker is involved so I will go ahead and tag this with Linux also.
-ldl
is a library designation for the linker. It tells the linker to find and link a file named libdl.so
(or sometimes libdl.a
). It has the same effect as placing a full path to the library in question in the same position of the command line.
Library and object order on the command line does matter. Normally if library A calls library B, B should be placed after A on the command line. All libraries should normally go after all object files. This is covered extensively in several SO questions and answers like this one.
As for the second question, no, an address of a function doesn't change at run time unless you dlopen
a shared library, then unload it, then dlopen
it again. In your case, since you don't dlopen
the library, it is safe to keep the function address in a static variable. Of course if you run multiple threads you need to ensure thread safety somehow (mutex it out, or use thread-local storage).