【发布时间】:2011-05-15 14:39:45
【问题描述】:
为什么 esp 在设置堆栈帧之前指向值,它与下面的代码有什么区别?
无效的主要(){ __asm__("movl %esp,%eax"); }【问题讨论】:
标签: c assembly x86 inline-assembly
为什么 esp 在设置堆栈帧之前指向值,它与下面的代码有什么区别?
无效的主要(){ __asm__("movl %esp,%eax"); }【问题讨论】:
标签: c assembly x86 inline-assembly
在我做了gcc -S file.c之后
getesp:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
#APP
# 4 "xxt.c" 1
movl %esp,%eax
# 0 "" 2
#NO_APP
leave
ret
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $20, %esp
call getesp
addl $4, %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
call printf
addl $20, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
getesp 有一个pushl,它操纵esp 并通过内联和ebp 在eax 中获取操纵的esp。
调用函数来获取堆栈指针并将其放入main 肯定是不同的,并且相差 12 个字节(在这种特定情况下)。这是因为当您执行call 时会推送eip(如果不是段间,并且对于linux/unix 正常程序执行它只是eip)(需要引用),接下来在getesp 函数中还有另一个push 和 ebp 之后堆栈指针减 4。因为 eip 和 ebp 是 4 个字节,所以现在总差值为 12 个字节。实际上我们可以在函数调用版本中看到。
没有函数调用就没有eip 和其他esp 操作的推送,所以我们在主设置后得到esp 值。
我对 AT&T 不满意,所以这里是 Intel 语法中的相同代码和下面的 Intex 语法 asm 转储。请注意,在 printf 调用 __asm__ 内的 main 值进入 a 没有推送或其他 esp 修改,因此, __asm__ 内 main 获得 esp 值,该值设置在主要由sub esp, 20 行。如上所述,我们通过调用 getesp 获得的值是(您所期望的) - 12 。
C 代码
#include <stdio.h>
int a;
long getesp() {
__asm__("mov a, esp");
}
int main(void)
{
__asm__("mov a,esp");
printf("%08X\n",a);
getesp ();
printf("%08X\n",a);
}
我的输出是针对特定运行的:
BF855D00
BF855CF4
英特尔语法转储是:
getesp:
push ebp
mov ebp, esp
sub esp, 4
#APP
# 7 "xt.c" 1
mov a, esp
# 0 "" 2
#NO_APP
leave
ret
main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
sub esp, 20
#APP
# 12 "xt.c" 1
mov a,esp
# 0 "" 2
#NO_APP
mov eax, DWORD PTR a
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:.LC0
call printf
call getesp
mov eax, DWORD PTR a
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], OFFSET FLAT:.LC0
call printf
add esp, 20
pop ecx
pop ebp
lea esp, [ecx-4]
ret
我希望这会有所帮助。
【讨论】: