INTEL汇编的函数调用过程

汇编调用函数的过程

 

         push arg2                                     func:    push %ebp                  保存caller的栈顶

         push arg1                                                 mov   %esp,%ebp       ebp保存callee的新栈顶

         push arg0                                                 保存用到的寄存器值 

eip-->call    func                                                 递减esp创建局部变量

                                                                          递增esp销毁局部变量

                                                                          恢复用到的寄存器值

                                                                          mov %ebp,%esp         恢复callee的栈顶

                                                                          pop %ebp                    从callee的栈顶弹出caller的栈顶

                                                                          ret    n                      弹出函数的返回地址(n可以用来销毁传递参数所占用的字节)

 

函数调用后栈中的内容

 

高地址      arg2

               arg1

               arg0

               函数的返回地址【call后面的指令地址】

低地址      ebp--->caller的栈基地地址

 

 

 

 

 

 

 

 

 

 

1) EBP是栈基址的指针,永远指向栈底(高地址),ESP是栈指针,永远指向栈顶(低地址)。 
  
2) CALL指令用来调用一个函数或过程,此时,下一条指令地址会被压入堆栈,以备返回时能恢复执行下条指令。 

3) RET指令用来从一个函数或过程返回,之前CALL保存的下条指令地址会从栈内弹出到EIP寄存器中,程序转到CALL之前下条指令处执行 

4) ENTER是建立当前函数的栈框架,即相当于以下两条指令:
        pushl   %ebp
        movl    %esp,%ebp 

 

5) LEAVE是释放当前函数或者过程的栈框架,即相当于以下两条指令:
        movl %ebp,%esp
        popl  %ebp

关于WINDOWS的C函数调用

 

__cdecl 最大好处在于由于是调用者清理栈【清理压入栈中的函数参数】,它可以处理可变参数,缺点则在于它增加了程序的大小,因为在每个调用返回的时候,需要多执行一条清理栈的指令。
  

__stdcall 是在windows程序设计中出现的最多的调用规则,所有的不可变参数的API调用都使用这个规则【由callee清除压入栈中的函数参数】。
  

 

__fastcall 在windows内核设计中被广泛的使用,由于两个参数由寄存器直接传递,采用这种规则的函数效率要比以上两种规则高【由callee清除压入栈中的函数参数】。

Int __cdecl func(void* p);
Push p
Call func
Add esp,4 //注意这里,由于是cdecl调用,需要调用者清栈。

Int __stdcall func(void* p);

Push p
Call func    //由被调用者清除栈

 

linux系统调用

 

Linux会有6个寄存器使用来传递这些参数:eax (存放系统调用号) ebxecxedxesiedi来存放这些额外的参数

你可能感兴趣的:(c,windows,linux,框架,汇编,api)