Why does dladdr return a path to the executable on position independent code on arm-linux?

1.5k views Asked by At

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.

0

There are 0 answers