X86_64栈寄存器用法分析

112 阅读3分钟

最近研究X64寄存器,但是发现不同的linux发行版本上,寄存器的实际使用情况也不一样。查资料显示大概是编译器优化不同导致,暂时还未找到详细的解释文档。

红帽服务器

Linux version 3.10.0-1160.92.1.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) ) #1 SMP Tue Jun 20 11:48:01 UTC 2023

结论:
(1) 局部变量的入栈顺序和定义顺序相同
(2) rsp寄存器指向栈顶已使用地址

1. 地址递增
    stack top (low address)  
    rsp --> &y 7fffe3025090: a0 50 02 e3 ff 7f 00 00  
            &x 7fffe3025098: 90 50 02 e3 ff 7f 00 00  
    rbp -->    7fffe30250a0: 00 00 00 00 00 00 00 00  
               7fffe30250a8: 55 65 8e d9 09 7f 00 00  
               7fffe30250b0: 00 00 00 00 00 00 00 00  
               7fffe30250b8: 88 51 02 e3 ff 7f 00 00  
               7fffe30250c0: 00 00 00 00 01 00 00 00  
               7fffe30250c8: 7d 05 40 00 00 00 00 00  
    stack bottom (high address)  

    rsp=7fffe3025090
    rbp=7fffe30250a0  
    &x =7fffe3025098  
    &y =7fffe3025090
    

2. 地址递减
stack bottom (high address)
7ffdea14fcff: 00 00 7f 18 41 e3 65 55
7ffdea14fcf7: 00 00 00 00 00 00 00 00        <-- rbp
7ffdea14fcef: 00 00 7f fd ea 14 fc e0   &x
7ffdea14fce7: 00 00 7f fd ea 14 fc f0   &y   <-- rsp
7ffdea14fcdf: 00 00 00 00 00 40 06 09
7ffdea14fcd7: 00 00 00 00 00 00 00 01
7ffdea14fccf: 00 00 7f 18 42 40 51 50
7ffdea14fcc7: 00 00 00 00 00 00 00 00
stack top (low address)

rsp=7ffdea14fce0
rbp=7ffdea14fcf0
&x =7ffdea14fce8
&y =7ffdea14fce0

gcc汇编如下,可以看到进入main后,立即申请了16字节栈空间;&x=%rsp-8; &y=%rsp-16; 局部变量入栈顺序确实和定义顺序相同(x地址大所以先入栈)

main:
.LFB2:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
#APP
# 14 "stack.c" 1
        mov %rsp, -8(%rbp)
        mov %rbp, -16(%rbp)

ubuntu桌面环境

Linux version 6.2.0-26-generic (buildd@bos03-amd64-042) (x86_64-linux-gnu-gcc-11 (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #26~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Jul 13 16:27:29 UTC 2

结论:
(1) 局部变量入栈顺序和定义顺序相反
(2) rsp寄存器指向栈顶未使用地址

1. 地址递增
stack top (low address)
rsp --> 7ffd322d13b0: 00 00 00 00 00 00 00 00  
     &x 7ffd322d13b8: b0 13 2d 32 fd 7f 00 00
     &y 7ffd322d13c0: d0 13 2d 32 fd 7f 00 00
        7ffd322d13c8: 00 ab d2 16 1c 1e 23 97
rbp --> 7ffd322d13d0: 01 00 00 00 00 00 00 00
        7ffd322d13d8: 90 9d 22 8b 06 7f 00 00
        7ffd322d13e0: 00 00 00 00 00 00 00 00
        7ffd322d13e8: 89 71 de f4 11 56 00 00
stack bottom (high address)

rsp =7ffd322d13b0  
rbp =7ffd322d13d0   
 &x =7ffd322d13b8  
 &y =7ffd322d13c0  

2. 地址递减
stack bottom (high address)  
7ffcaa2d8a9f: 00 00 7f 77 52 02 9d 90  
7ffcaa2d8a97: 00 00 00 00 00 00 00 01 <-- rbp
7ffcaa2d8a8f: b1 1b 7e 09 86 92 69 00
7ffcaa2d8a87: 00 00 7f fc aa 2d 8a 90 &y
7ffcaa2d8a7f: 00 00 7f fc aa 2d 8a 70 &x
7ffcaa2d8a77: 00 00 00 00 00 00 00 00 <-- rsp
7ffcaa2d8a6f: 00 00 55 be 0e d9 83 bd
7ffcaa2d8a67: 00 00 55 be 0e d9 83 1e
stack top (low address)

rsp =7ffcaa2d8a70
rbp =7ffcaa2d8a90
&x =7ffcaa2d8a78
&y =7ffcaa2d8a80

gcc汇编如下,进入main后,申请了32字节栈地址;&x=%rsp-24; &y=%rsp-16。局部变量入栈顺序和定义顺序相反。

main:
.LFB6:
        .cfi_startproc
        endbr64
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $32, %rsp
        movq    %fs:40, %rax
        movq    %rax, -8(%rbp)
        xorl    %eax, %eax
        movq    $1, -24(%rbp)
        movq    $2, -16(%rbp)
#APP
# 14 "stack.c" 1
        mov %rsp, -24(%rbp)
        mov %rbp, -16(%rbp)


实现代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *it;
int i = 0;
int inc = 1;

int main()
{
    long x = 1;
    long y = 2;

    asm("mov %%rsp, %0\n\t"
        "mov %%rbp, %1\n\t"
        :"=m"(x),"=m"(y)::);
    
    if (inc)
    {
        it = (void *)x;
    }
    else
    {
        it  = (void *)y;
        it += 15;
    }

    i = 0;

    while (i < 64)
    {
        if ((i % 8) == 0)
        {
            printf("\n%lx:", (long)it);
        }
        
        printf(" %02hhx", *it);    
        
        if (inc)
        {
            it++;
        }
        else
        {
            it--;
        }

        i++;
    }

    printf("\n");

    printf("rsp =%lx\n", x);
    printf("rbp =%lx\n", y);
    printf(" &x =%lx\n", (long)&x);
    printf(" &y =%lx\n", (long)&y);    

    return 0;
}