我有两个不同的二进制文件,它们的main
函数的反汇编如下所示:
80483d4: 55 push %ebp
80483d5: 89 e5 mov %esp,%ebp
80483d7: 83 e4 f0 and $0xfffffff0,%esp
80483da: 83 ec 20 sub $0x20,%esp
80483dd: 8d 45 08 lea 0x8(%ebp),%eax
80483e0: 89 44 24 1c mov %eax,0x1c(%esp)
另一个是:
80483d4: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483d8: 83 e4 f0 and $0xfffffff0,%esp
80483db: ff 71 fc pushl -0x4(%ecx)
80483de: 55 push %ebp
80483df: 89 e5 mov %esp,%ebp
...
80483e6: 89 4d f0 mov %ecx,-0x10(%ebp)
第一个是在GNU/Linux 2.6.24下编译的,第二个是在GNU/Linux 2.6.9下编译的。在大多数情况下,我将0x4(%esp)
理解为返回地址,将0x8(%esp)
理解为第一个参数。显然,第一个二进制文件使用0x8(%ebp)
作为第一个自变量,与对齐前的0x8(%esp)
相同,而第二个二进制文件则使用0x4(%esp)
作为第一个论据,这让我很困惑为什么要这样做。这是因为它们是在不同版本的GNU/Linux下编译的吗?
似乎两者都引用了第一个参数。第一个例子中的8(%ebp)
和第二个例子中4(%esp)
之间的位移差异的原因是一个发生在保存ebp
之前,另一个发生之后。
让它完全清楚:
movl 4(%esp), %eax # here, the first argument is at esp + 4
push %ebp # push has the effect of esp -= 4
movl %esp, %ebp
movl 8(%ebp), %eax # here, the first argument is at esp + 8 (or equivalently, ebp + 8)
另一个有趣的地方是,在将堆栈指针保存到一个二进制文件中的ebp
之前,以及在将其保存到另一个二进制中之后,都要对其进行对齐。这对我来说似乎很奇怪——我只能假设在后一种情况下,esp
的旧值是在main返回之前的某个点从ecx
重新计算的。