在c ++中的函数内执行汇编

时间:2011-05-15 14:39:46

标签: c assembly x86 inline-assembly

    
long getesp() {  
    __asm__("movl %esp,%eax");  
    }  

    void main() {  
    printf("%08X\n",getesp()+4);  
    }  

为什么esp在设置堆栈帧之前指向值,它是否与下面的代码有任何区别?

   
void main() {    
   __asm__("movl %esp,%eax");    
   } 

1 个答案:

答案 0 :(得分:3)

我做了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,并使用内联和{{1}获取espeax的操纵ebp }}

进行函数调用以获取堆栈指针并将其放入main内部肯定是不同的,它相差12个字节(在这种特定情况下)。这是因为当你执行call推送eip(如果不是段落,并且对于linux / unix正常程序执行它只是eip)(需要引用),接下来是{ {1}}函数还有另一个带有getesp的{​​{1}},然后将堆栈指针减去4.因为pushebp是4个字节,所以总差异现在是12个字节。实际上我们可以在函数调用版本中看到。

如果没有函数调用,则不会推动eip和其他ebp操作,因此我们会在主要设置之后获得eip值。

我对AT& T不满意所以这里的英特尔语法代码相同,下面是Intex语法asm转储。请注意,在esp调用esp内部主要值进入printf时,没有推送或其他__asm__修改,因此,主要内部的a获取由esp行在main中设置的__asm__值。我们通过调用esp得到的值是(你期望的) - 12,如上所述。

C代码

sub     esp, 20

输出在我的情况下是针对特定的运行:

getesp

intel语法转储是:

#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);
}

我希望这会有所帮助。