一 如何确定符号所对应的地址?
先看如下一段代码simpleSection.c,对于这段代码的问题是,如果定位到global_init_var2, global_init_var3 的地址呢?
int printf(const char* fromat, ...);
int global_init_var = 84;
int global_init_var2 = 85;
int global_init_var3 = 86;
int global_uninit_var;
void func1(int i)
{
printf("%d\n", i);
}
int main(void)
{
static int static_var = 85;
static int static_var2;
global_init_var2 = 40;
global_init_var3 = 50;
int a = 1;
int b = 1;
func1(static_var + static_var2 + a + b);
return a + b;
}
gcc -c simpleSection.c, 编译完成后用 objdump -s -d simpleSection.o 查看生成的.o文件
这两行对应的分别是global_init_var2 = 40; global_init_var3 = 50; 绿色的 00000000 是虚拟地址,需要进行重定位。那么如何确认这里操作的是global_init_var2, global_init_va3 呢? 这里先给出答案 从重定位表和符号表中共同确定,下面给出确定过程,我们先用 readelf -a simpleSection.o 查看重定位表
绿色框中的0x2b, 0x35 正是.text 段(第二张图)中movl $0x28,0x0(%rip), movl $0x32,0x0(%rip) 的起始地址,接下来再看Sys.value 中对应的值,这两项值是符号表中的index , 下面用 objdump -t simpleSection.o 来查看证明
我们再看.data 段对应的第2,第3项的值,的确是85,86 ,正是 global_init_var2, global_init_var3
二 地址的修正
我们执行 gcc simpleSection.c -o simpleSection 生成elf 可执行文件,用 objdump -s -d simpleSection 查看下 main()函数对应的汇编语言
同simpleSection.o 对应的main()函数来比对,可以看出地址已经不是00000000 了,显然这里的值经过修正,那么这些值又是如何得来的呢? 红圈结尾部分可以看标注的是601038 <global_init_var2), 0x601038 = 0x40556 + 0x2 + 0x8 + 0x200ad8 , 0x40556 是movl 指令的开始地址,2 代表 c7 05 这两个字节, 0x8 是 0x2000ad8, 和 0x 0000000 这8个字节,也就是说这条指令是相对地址,从把0x28 这个立即数传送到 0x200ad8 (相对地址) 即绝对地址为0x601038 的地方, 那接下来再看0x601038 对应的是什么呢?依旧通过objdump -s -d simpleSection ,我们可以看到这个位置位于.data段,0x601038 正是global_init_var2 的地址位置
三 总结
以上的总结过程参考了《程序员的自我修养》这本书,无疑这本书值得一看,但个人认为这本书过于专业,对于符号解析和地址定位的简要过程缺少扼要描述,本博正式对这一过程的补充。