AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > 汇编语言

汇编语言的准备知识-给初次接触汇编者4

51自学网 http://www.51zixue.net

  5. 函数调用

  一个函数在被定义时,也确定一个内存地址对应于函数名字。如:

  long comb(int m, int n)
  {
  long temp;
  .....

  return temp;
  }

  这样,函数comb就对应一个内存地址。对它的调用表现为:

  CALL xxxxxxxx ;comb对应的地址。这个函数需要两个整型参数,就通过堆栈来传递:

  ;lresult=comb(2,3);

  push 3
  push 2
  call xxxxxxxx
  mov dword ptr [yyyyyyyy], eax ;yyyyyyyy是长整型变量lresult的地址

  这里请注意两点。第一,在C语言中,参数的压栈顺序是和参数顺序相反的,即后面的参数先压栈,所以先执行push 3. 第二,在我们讨论的32位系统中,如果不指明参数类型,缺省的情况就是压入32位双字。因此,两个push指令总共压入了两个双字,即8个字节的数据。然后执行call指令。call 指令又把返回地址,即下一条指令(mov dword ptr....)的32位地址压入,然后跳转到xxxxxxxx去执行。

  在comb子程序入口处(xxxxxxxx),堆栈的状态是这样的:

  03000000 (请回忆small endian 格式)
  02000000
  yyyyyyyy <--ESP 指向返回地址

  前面讲过,子程序的标准起始代码是这样的:

  push ebp ;保存原先的ebp
  mov ebp, esp;建立框架指针
  sub esp, XXX;给临时变量预留空间
  .....

  执行push ebp之后,堆栈如下:

  03000000
  02000000
  yyyyyyyy
  old ebp <---- esp 指向原来的ebp

  执行mov ebp,esp之后,ebp 和esp 都指向原来的ebp. 然后sub esp, xxx 给临时变量留空间。这里,只有一个临时变量temp,是一个长整数,需要4个字节,所以xxx=4。这样就建立了这个子程序的框架:

  03000000
  02000000
  yyyyyyyy
  old ebp <---- 当前ebp指向这里
  temp

  所以子程序可以用[ebp+8]取得第一参数(m),用[ebp+C]来取得第二参数(n),以此类推。临时变量则都在ebp下面,如这里的temp就对应于[ebp-4].

  子程序执行到最后,要返回temp的值:

  mov eax,[ebp-04]
  然后执行相反的操作以撤销框架:

  mov esp,ebp ;这时esp 和ebp都指向old ebp,临时变量已经被撤销
  pop ebp ;撤销框架指针,恢复原ebp.

  这是esp指向返回地址。紧接的retn指令返回主程序:

  retn 4

  该指令从堆栈弹出返回地址装入EIP,从而返回到主程序去执行call后面的指令。同时调整esp(esp=esp+4*2),从而撤销参数,使堆栈恢复到调用子程序以前的状态,这就是堆栈的平衡。调用子程序前后总是应该维持堆栈的平衡。从这里也可以看到,临时变量temp已经随着子程序的返回而消失,所以试图返回一个指向临时变量的指针是非法的。

  为了更好地支持高级语言,INTEL还提供了指令Enter 和Leave 来自动完成框架的建立和撤销。Enter 接受两个操作数,第一个指明给临时变量预留的字节数,第二个是子程序嵌套调用层数,一般都为0。enter xxx,0 相当于:

  push ebp
  mov ebp,esp
  sub esp,xxx

  leave 则相当于:

  mov esp,ebp
  pop ebp

  =============================================================
  好啦,我的学习心得讲完了,谢谢各位的抬举。教程是不敢当的,因为我也是个大菜鸟。如果这些东东能使你们的学习轻松一些,进步快一些,本菜鸟就很开心了。

 
 

上一篇:汇编语言上机指导及例示  下一篇:汇编语言的准备知识-给初次接触汇编者2