我使用 sh4 gcc 编译器作为共享库构建了非常简单的 hello world 代码:
#include <stdio.h>
void hello()
{
printf("Hello world!\n");
}
但是当我将 .so 文件加载到反汇编器(IDA 或 Ghidra)中时,我实际上无法找到 puts 被调用的位置。即使 hello() 函数存在:
但是在它应该实际调用 printf/puts 的地方,有一些地址加载操作指向不存在的地址:
我可以在导入部分看到 puts,但是除了一些数据之外没有引用的代码来自 .LOAD 部分的参考。
尽管如此,我将代码构建为可执行文件,而不是共享库。puts thunk 在函数中变得可见:

好像导入 thunk 不是为共享库传播,而是为可执行文件传播。
我试图自己找到问题,所以我在两个二进制文件上都运行了 readelf。看来这取决于重定位数据。这是可执行文件转储:
'PLT' relocation section at offset 0x4002d0 contains 48 bytes:
Offset Info Type Sym.Value Sym. Name + Addend
0041103c 000002a4 R_SH_JMP_SLOT 00400380 puts@GLIBC_2.2 + 0
00411040 000001a4 R_SH_JMP_SLOT 00000000 __gmon_start__ + 0
00411044 000005a4 R_SH_JMP_SLOT 004003b8 __libc_start_main@GLIBC_2.2 + 0
00411048 000003a4 R_SH_JMP_SLOT 004003d4 abort@GLIBC_2.2 + 0
这是它查找共享模块的方式:
'PLT' relocation section at offset 0x364 contains 36 bytes:
Offset Info Type Sym.Value Sym. Name + Addend
00011010 000001a4 R_SH_JMP_SLOT 00000000 __cxa_finalize@GLIBC_2.2 + 0
00011014 000003a4 R_SH_JMP_SLOT 00000000 puts@GLIBC_2.2 + 0
00011018 000004a4 R_SH_JMP_SLOT 00000000 __gmon_start__ + 0
Sym.Value 为零,并且 Ghidra 和 IDA 都无法确定 thunk 指向的位置。所以问题是:
- 共享模块有什么特别之处,以至于 Sym.Value 为零?
- 当操作系统加载 so 文件时,导入 thunk 如何传播?
- 有没有办法将导入的函数映射到这样的 thunk 中,使它们在 IDA 或 Ghidra 中具有适当的名称?
共享库的构建方式:
sh4-linux-gnu-gcc -c -g -fPIC hello.c -o hello.o
sh4-linux-gnu-gcc hello.o -shared -o libhello.so