最近研究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;
}