Emdebian の g++-4.7 クロス コンパイラ for armhf を使用して arm-linux 用にクロスコンパイルしたコードの一部で、dladdr に関する問題が発生しました。問題は、dladdr に渡す関数ポインターが実行可能ファイル内でも呼び出される関数である場合、dli_fname は、シンボルの元の共有ライブラリではなく、実行可能ファイルへのパスを返すことです。
コンパイルされた例:
/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;
}
結果: printf は ./main から取得されます
main() の本体を次のように変更すると
int main() {
std::cout<<"printf comes from "<<findLibName((void*)printf)<<"\n";
return 0;
}
結果: printf は /lib/arm-linux-gnueabihf/libc.so.6 から取得されます
関数ポインターを dladdr に渡す関数が実行可能ファイル内で呼び出された場合、次の行に沿ったエントリがあることに気付きました
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
実行可能ファイルの .rel.plt セクションに作成されます。dladdr は、GOT を通じて見つけられる libc.so.6 からの正しいアドレスではなく、PLT から printf のこのアドレスを見つけているようです。dladdr のマニュアル ページでは、コードを位置に依存しないようにコンパイルするとこれが修正されるはずですが、このコンパイラではそうではないようです。参考までに、上記の同じコードは、g++-4.7 を使用する x86_64 Linux で期待どおりに動作します。