x86-64 AMD上的CALL指令的操作数生成

以下是一个示例程序的objdump的输出,

080483b4 <display>: 80483b4: 55 push %ebp 80483b5: 89 e5 mov %esp,%ebp 80483b7: 83 ec 18 sub $0x18,%esp 80483ba: 8b 45 0c mov 0xc(%ebp),%eax 80483bd: 89 44 24 04 mov %eax,0x4(%esp) 80483c1: 8d 45 fe lea 0xfffffffe(%ebp),%eax 80483c4: 89 04 24 mov %eax,(%esp) 80483c7: e8 ec fe ff ff call 80482b8 <strcpy@plt> 80483cc: 8b 45 08 mov 0x8(%ebp),%eax 80483cf: 89 44 24 04 mov %eax,0x4(%esp) 80483d3: c7 04 24 f0 84 04 08 movl $0x80484f0,(%esp) 80483da: e8 e9 fe ff ff call 80482c8 <printf@plt> 80483df: c9 leave 80483e0: c3 ret 080483e1 <main>: 80483e1: 8d 4c 24 04 lea 0x4(%esp),%ecx 80483e5: 83 e4 f0 and $0xfffffff0,%esp 80483e8: ff 71 fc pushl 0xfffffffc(%ecx) 80483eb: 55 push %ebp 80483ec: 89 e5 mov %esp,%ebp 80483ee: 51 push %ecx 80483ef: 83 ec 24 sub $0x24,%esp 80483f2: c7 44 24 04 f3 84 04 movl $0x80484f3,0x4(%esp) 80483f9: 08 80483fa: c7 04 24 0a 00 00 00 movl $0xa,(%esp) 8048401: e8 ae ff ff ff call 80483b4 <display> 8048406: b8 00 00 00 00 mov $0x0,%eax 804840b: 83 c4 24 add $0x24,%esp 804840e: 59 pop %ecx 804840f: 5d pop %ebp 8048410: 8d 61 fc lea 0xfffffffc(%ecx),%esp 

我需要了解的是,我们主要看到以下地址 – 8048401,调用80483b4,但是机器代码是 – e8 ae ff ff ff。 我看到CALL指令是E8,但函数80483b4的地址如何被解码为FFFFFFAE? 我在谷歌做了很多search,但没有任何回报。 任何人都可以解释吗?

E8是“相对调用”的操作数,表示通过将操作数添加到下一条指令的地址来计算目标地址。 操作数是0xFFFFFFAE,它是负的0x52。 0x808406 – 0x52是0x80483b4。

大多数反汇编程序都会帮忙计算实际的目标地址,而不是只给你操作数中的相对地址。

有关x86 ISA的完整信息,请访问: http : //www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html

有趣的问题。 我看了英特尔的文档 , E8操作码是CALL rel16/32 。 0xffffffae实际上是一个等于-82十进制的32位二进制补码有符号整数; 它是紧跟在操作码和操作数之后的字节的相对地址。

如果你做数学,你可以看到它检查:

0x8048406 – 82 = 0x80483b4

这将指令指针放在display函数的开头。

近调用通常是IP相对的 – 意思是“地址”实际上是指令指针的偏移量。 在这种情况下,EIP指向下一条指令(所以它的值是8048406 )。 添加ffffffae (或-00000052补码),即可得到80483b4

请注意,所有这些数学是32位的。 你在这里没有做任何64位的操作(或者你的寄存器的名字是R而不是E ,地址会更长)。