汇编代码中的函数调用

以下分析全部基于AT&T汇编语法,目标操作数在源操作数的右边,且正确性不做保证

汇编函数调用时堆栈的变化

问题概述

在主程序调用子程序时,子程序的开头两行代码很多都是一样的,例如:

    7d15:	55                   	push   %ebp
    7d16:	89 e5                	mov    %esp,%ebp

这是为什么呢

详解

接下来通过一个例子来直观的感受一下。在讲这个例子之前要先讲一下与堆栈相关的寄存器的作用,比较重要。
与堆栈相关的 3 个寄存器是:SS, ESP, EBP。
ESP 寄存器中的内容作为堆栈的当前指针。PUSH, POP, CALL, RET 等指令都与堆栈有关,使用 SS:ESP 指向堆栈单元(栈顶)
EBP 寄存器中的内容作为堆栈的“基准”指针。SS:EBP 指向的地址作为基准地址。在函数(子程序)内部。能够使用 [EBP+马上数] 的形式来取得主程序传递的參数,使用 [EBP-马上数] 的形式来訪问局部变量。

下图就是我们要讲的例子了:
image
主程序在call之前会将实参压入堆栈, call的时候会将当前IP,也就是返回地址压入堆栈,然后跳转。

跳转到子程序后会先把ebp压栈,然后mov esp, ebp,重点来了,在执行这个命令之前,ebp是指向大地址X的(极端假设主程序的堆栈只有这两个数据),esp指向X-0CH,代表主程序使用的堆栈,执行这个命令之后,ebp指向了X-0CH,esp也指向了X-0CH,代表了子程序使用的新的堆栈,当子程序定义局部变量1和局部变量2的时候,esp便会再次发送生化。同时这个时候通过EBP+08H、EBP+0CH可以访问到主程序传入的参数。

子程序在执行完毕后会有一条leave指令,其实就是

mov ebp, esp
pop esp

相当于将esp重新指向X-0CH,ebp重新指向大地址X,恢复了原来主程序使用的堆栈。

leave执行完后,就ret,ret指令是用栈中的数据(也就是X-08H的地址)弹出到IP中,从而实现跳转。

参考了暴雪对门的文章:https://www.cnblogs.com/bxdm/p/6725873.html
有问题请联系我删除

汇编寄存器使用惯例

问题概述

函数调用中,进入子程序后为什么会执行
    7d18:	56                   	push   %esi
    7d19:	53                   	push   %ebx

详解

知识来源:深入了解计算机操作系统 第三章

程序寄存器组是唯一能够被所有过程共享的资源。虽然在给定时刻只能有一个过程是活动的,但是我们必须保证当一个过程(调用者)调用另一个过程(被调用者)时,被调用者不会覆盖某个调用者稍后会使用的寄存器的值。为此必须采用一组统一的寄存器使用惯例,所有的过程都必须遵守,包括程序库的过程。

  假如没有这些规矩,比如在调用一个过程时,无论是调用者还是被调用者,都可能更新寄存器的值。假设调用者在%edx中存了一个整数值100,而被调用者也使用这个寄存器,并更新成了1000,于是悲剧就发生了。当过程调用完毕返回后,调用者再使用%edx的时候,值已经从100变成了1000,这几乎必将导致程序会错误的执行下去。所以便有如下规矩:

  在 IA32 中,寄存器%eax,%edx和%ecx被划分为调用者保存寄存器。当过程 P 调用 Q 时,Q可以覆盖这些寄存器,而不会破坏 P 所需的数据。

  寄存器%ebx,%esi和%edi被划分为被调用者保存寄存器。这里 Q 必须在覆盖这些寄存器的值之前,先把他们保存到栈中,并在返回前恢复它们,因为 P(或某个更高层次的过程)可能会在今后的计算中需要这些值。

考虑如下代码:

  int P(int x)
{
    int y = x*x;
    int z = Q(y);
    return y+z;
}

  过程 P 在调用 Q 之前会先计算 y 的值,而且它必须保证 y 的值在 Q 返回后是可用的。这里有两种方法实现:

  ①、可以在调用 Q 之前,将 y 的值保存在自己的帧栈中;当 Q 返回时,过程 P 就可以从栈中取出y 的值。换句话说就是调用者 P 自己保存这个值。

  ②、可以将 y 保存在被调用者保存寄存器中。如果 Q ,或者其它 Q 调用的程序想使用这个寄存器,它必须将这个寄存器的值保存在帧栈中,并在返回前恢复该值。换句话说就是被调用者保存这个值。当 Q 返回到 P 时,y 的值会在被调用者保存寄存器中,或者是因为寄存器根本就没有改变,或者是因为它被保存并恢复了。

  这两种方法在 IA32 中是都采用的。

posted @ 2021-11-23 15:47  Pril  阅读(751)  评论(0)    收藏  举报