Ald*_*ri 5 x86 assembly gdb computer-architecture cpu-registers
我是计算机体系结构和处理器/内存级别发生的低级问题的新手。我先说。我对计算机所做的工作几乎始终处于高级编程级别。C ++,Java等
话虽这么说,我目前正在阅读一本开始深入研究低级编程内容,汇编,寄存器,指针等的书。我很难理解EIP寄存器的工作原理。
从书中所说,每个内存地址都有一个字节,每个字节都有一个内存地址。
从我读到的有关EIP寄存器的内容来看,它指向处理器要执行的下一组指令。在使用调试工具(GDB)进行本书学习时,如果要检查特定位置的内存,请说:
x / 8xb据说可以让您检查内存地址的前8个字节。但是,如果每个内存地址只有1个字节,我听不懂。有人可以帮我理解吗?我一直在寻找关于此寄存器如何工作和起作用的详尽解释,但我真的找不到任何东西
让我们从一个具体的 x86 特定示例开始。
00000000000020b0 <foo>:
20b0: 89 d1 movl %edx, %ecx
20b2: 89 f8 movl %edi, %eax
20b4: 0f af c6 imull %esi, %eax
20b7: 31 d2 xorl %edx, %edx
20b9: f7 f1 divl %ecx
20bb: c3 ret
Run Code Online (Sandbox Code Playgroud)
为了简单起见以及本示例,将内存视为一个巨大的字节“数组”,并将内存地址视为此类“数组” 0的索引。当某个东西位于给定的内存地址时,这本质上意味着它的第一个字节位于该地址,它的第二个字节(如果它不仅仅是一个字节大)位于下一个地址,依此类推。例如,从地址1foo开始,跨度 12 个字节。这意味着从到(含)的每个地址都指向函数中的一个字节。0x20B00x20B00x20BB
x86 中的程序计数器称为RIP(EIP如果是 32 位),指向下一条指令2。例如,如果当前正在执行的指令是 处的指令0x20B2,RIP则将包含值0x20B4。由于 x86 的 CISC 性质,指令大小有所不同,因此RIP不一定每次都会增加固定的量。
00000000000020b0 <foo>:
20b0: 89 d1 movl %edx, %ecx
EX->20b2: 89 f8 movl %edi, %eax
PC->20b4: 0f af c6 imull %esi, %eax
20b7: 31 d2 xorl %edx, %edx
20b9: f7 f1 divl %ecx
20bb: c3 ret
Run Code Online (Sandbox Code Playgroud)
在下一个“迭代”中,EX(不是真正的寄存器,只是标记正在执行的内容的一种方式)将指向该imull指令,PC(RIP)将指向该xorl指令,依此类推,直到该ret指令,此时存储在堆栈上的返回地址将被加载到,RIP以便可以在 的调用者处继续执行foo。
0正如 Peter Cordes 所提到的,有些架构不适用这一点。就问题而言,这个答案是特定于 x86 的。
1这实际上并不是运行时找到该函数的地址,但为了示例而假装它是。
2在某些架构中,程序计数器指向当前指令(AArch64 执行此操作),甚至指向前面的两条指令(AArch32 执行此操作)。