关于PLT与GOT跳转的技术问询:`jmp DWORD PTR [ebx+0xc]`如何将控制权转移至GOT?
32位ELF动态链接中PLT跳转GOT时EBX为0的问题分析
看起来你在调试32位ELF程序的动态链接流程时卡在了关键节点:进入puts@plt后执行jmp DWORD PTR [ebx+0xc]时,EBX的值居然是0,导致跳转地址完全不符合预期。我们来一步步拆解这个问题,找到疏漏点:
核心原理:EBX在32位动态链接中的作用
在32位x86的ELF动态链接机制里,EBX寄存器是专门用来存储GOT(全局偏移表)基地址的。所有PLT中的跳转指令都依赖EBX+偏移量来定位GOT条目,这是位置无关代码(PIC)实现动态符号寻址的核心逻辑。
为什么你的EBX是0?—— 看main函数里的GOT基址初始化流程
从你提供的main函数反汇编代码来看,GOT基址是在main函数执行过程中主动设置的,关键步骤如下:
11ac: call 11d9 <__x86.get_pc_thunk.ax> ; 将当前PC值存入EAX寄存器 11b1: add eax,0x2e4f ; 通过偏移量计算出GOT的基地址 11c0: mov ebx,eax ; 把GOT基地址存入EBX,这一步是关键! 11c2: call 1030 <puts@plt> ; 调用puts@plt,此时EBX已经正确初始化
正常情况下,当执行到call puts@plt时,EBX应该已经被设置为GOT的起始地址(你的程序中GOT起始于0x4000),所以[ebx+0xc]就是0x400c——也就是GOT中对应puts的条目。
你调试时EBX为0,大概率是以下原因之一:
- 断点设置时机错误:你可能在
main函数还没执行到mov ebx,eax时,就提前进入了PLT(比如误将断点打在了程序启动的初始化阶段)。 - 调试操作失误:调试过程中不小心修改了EBX的值,或者跳过了设置EBX的关键指令。
- 第一次调用PLT的特殊流程:第一次调用
puts@plt时,GOT中的0x400c条目其实指向的是puts@plt内部的push 0x0指令(地址1036),这是动态链接器的解析流程:- 执行
jmp DWORD PTR [ebx+0xc]跳转到1036 - 执行
push 0x0(这个0是puts在重定位表中的索引) - 跳转到PLT的通用解析入口
1020,触发动态链接器解析puts的真实地址 - 解析完成后,动态链接器会把
puts的真实地址写入GOT的0x400c条目,下次调用就直接跳转到真实地址
- 执行
验证方法
你可以在调试时做以下操作来确认问题:
- 在
main函数的mov ebx,eax指令(地址11c0)处设置断点,执行完这条指令后查看EBX的值,应该等于0x4000(你的GOT起始地址)。 - 接着单步执行到
call puts@plt,进入PLT后再查看EBX,此时应该还是0x4000,[ebx+0xc]就是0x400c,对应GOT中的条目。
总结
你的流程疏漏点在于没有确认EBX是否已经被正确初始化——正常调用puts@plt时,EBX必须已经被main函数设置为GOT基址。如果调试时EBX为0,说明你在执行到call puts@plt之前,GOT基址的初始化步骤没有被正确执行。
内容的提问来源于stack exchange,提问作者user3488903
相关产品推荐
相关产品推荐

