I've been running into a problem with dladdr in some of my code that I've cross-compiled for arm-linux using Emdebian's g++-4.7 cross compiler for armhf. The problem seems to be that if the function pointer you pass to dladdr is a function that is also called within the executable, dli_fname will return the path to the executable instead of the shared library that the symbol comes from.
Example compiled via:
/usr/bin/arm-linux-gnueabihf-g++-4.7 main.cpp -o main -ldl -fPIC
#include <dlfcn.h>
#include <iostream>
#include <stdio.h>
#include <string>
std::string findLibName(void* funcPtr) {
Dl_info info;
if (dladdr(funcPtr,&info) != 0) {
return std::string(info.dli_fname);
} else {
return "";
}
}
int main() {
printf("printf comes from %s\n",findLibName((void*)printf).c_str());
return 0;
}
Result: printf comes from ./main
If I change the body of main() to be
int main() {
std::cout<<"printf comes from "<<findLibName((void*)printf)<<"\n";
return 0;
}
Result: printf comes from /lib/arm-linux-gnueabihf/libc.so.6
I've noticed that if the function whose function pointer you pass to dladdr is called within the executable, an entry along the lines of
Relocation section '.rel.plt' at offset 0x63c contains 14 entries:
Offset Info Type Sym.Value Sym. Name
00010be8 00000d16 R_ARM_JUMP_SLOT 00008730 printf
is created in the .rel.plt section of the executable and it appears that dladdr is finding this address of printf from the PLT rather than the correct address from libc.so.6 that it would find through the GOT. The dladdr man page suggests that compiling the code to be position independent should fix this but that doesn't seem to be the case with this compiler. For reference, the same code shown above works as expected on x86_64 Linux with g++-4.7.