玩命加载中 . . .

3.3-栈与数据传送指令


栈与数据传送指令

在程序的执行过程中,需要在CPU和内存之间进行频繁的数据存取,例如,CPU执行加法c=a+b,首先通过执行数据传送指令将ab的值从内存读到寄存器内

寄存器就是CPU内的一种数据存储部件,只不过容量比较小,比如,寄存器rax64Bit,即8Byte,如果变量along类型,需要占用8个字节,因此,rax全部的数据位都用来保存变量a;如果变量aint类型,就只需要低32位来存储,如果是short类型,则只需要低16位

对于寄存器rax,如果使用全部的64位,用%rax表示,32位用%eax表示,低16位用%ax表示,低8位用%al表示

计算完结果后,再通过数据传送指令将结果保存到内存

代码示例

long exchange(long *xp, long y) {
    long x = *xp;
    *xp = y;
    return x;
}

int main()
{
    long a = 4;
    long b = exchange(&a, 3);
    printf("a = %ld, b = %ld\n", a, b);
    return 0;
}
a = 3, b = 4

这个程序会将变量a的值替换成3,变量b保存原来a的值4

exchange函数的汇编代码,包括两条数据传送指令和一条返回指令

xp -> %rdi, y -> %rsi
exchange:
    movq    (%rdi), %rax    // rdi指向的地址的值复制到rax
    movq    %rsi, (%rdi)    // rsi的值复制到rdi指向的地址处
    ret

寄存器rdirsi分别用来保存函数传递的第一个参数和第二个参数,因此rdi中保存了xp的值,rsi中保存了变量y的值

第一条mov指令从内存中读取数值到寄存器,内存地址保存在寄存器rdi中,目的操作数是寄存器rax,因为要返回x的值,所以直接放到rax里面

第二条mov指令将变量y的值写到内存里,变量y存储在rsi中,内存地址保存在rdi中,也就是xp指向的地址

程序栈

要将寄存器rax的值0x123放入栈中,可以使用pushq指令将数据压入栈中,该指令执行的过程可以分解为两步

pushq   %rax    // 将rax的值压栈

首先指向栈顶的寄存器rsp进行减法操作,因为栈是从高地址指向低地址,例如此时rsp的值为0x108,rsp值减8之后指向0x100,然后将需要保存的数据复制到新的栈顶位置,此时地址0x100处将保存寄存器rax的数值0x123

subq    $8, %rsp        // rsp的值减8
movq    %rax, (%rsp)    // 保存到rsp指向的地址处

区别在于pushq指令只要1个字节,而两条指令需要8个字节

pushq的本质是将数据写入到内存

与之对应的pop指令就是从内存中读取数据,并且修改栈顶指针

popq    %rbx

这条指令将栈顶保存的值复制到寄存器rbx中,也可以分解为两步:

  • 首先从栈顶读出数据,复制到寄存器rbx
  • 然后将栈顶指针加8
movq    (%rsp), %rbx
addq    $8, %rsp

注意,此时地址0x100内保存的数据0x123依然存在,知道下次push操作,才会被覆盖


文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录