下面是一些简单的C++代码。我在test_func
中定义了一个变长数组。我想知道数组arr
和rbp
寄存器之间的关系。
void test_func(int m, int n) {
int arr[m];
for(int i = 0; i < m; ++i) {
arr[i] = m;
}
cout << "ok";
}
int main() {
int m = 30, n = 12;
test_func(m, n);
return 0;
}
我使用gdb检查他们的地址,但我什么也没发现。
然后我使用g++ -E test.cpp -o test.i , g++ -S test.i -o test.S
。我发现一些奇怪的汇编代码。
_Z9test_funcii:
.LFB1559:
pushq %rbp
.seh_pushreg %rbp
pushq %r12
.seh_pushreg %r12
subq $40, %rsp
.seh_stackalloc 40
leaq 128(%rsp), %rbp
.seh_setframe %rbp, 128
.seh_endprologue
movl %ecx, -64(%rbp)
movl %edx, -56(%rbp)
movq %rsp, %rax
movq %rax, %r8
movl -64(%rbp), %eax
cltq
subq $1, %rax
movq %rax, -112(%rbp)
movq %rax, %rdx
addq $1, %rdx
movq %rdx, %r11
movl $0, %r12d
movq %rax, %rdx
addq $1, %rdx
movq %rdx, %r9
movl $0, %r10d
addq $1, %rax
salq $2, %rax
addq $15, %rax
shrq $4, %rax
salq $4, %rax
call ___chkstk_ms
subq %rax, %rsp
movq %rsp, %rax
addq $3, %rax
shrq $2, %rax
salq $2, %rax
movq %rax, -120(%rbp)
movl $0, -100(%rbp)
.L3:
movl -100(%rbp), %eax
cmpl -64(%rbp), %eax
jge .L2
movq -120(%rbp), %rdx
movl -100(%rbp), %eax
cltq
movl -64(%rbp), %ecx
movl %ecx, (%rdx,%rax,4)
addl $1, -100(%rbp)
jmp .L3
.L2:
movq %r8, %rsp
nop
leaq -88(%rbp), %rsp
popq %r12
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
我想知道arr
在堆栈上的位置及其与rbp
寄存器的关系。
1条答案
按热度按时间xfb7svmp1#
与处理固定大小数组的方式差不多。堆栈指针按对象的大小递减。通常计算所有局部变量的堆栈大小,并在开始时进行一次堆栈调整。对于动态请求的堆栈(法律的c VLA,gcc '非法' c++ VLA,alloca,...),当大小已知时,将进一步递减
下面是一个c版本-使用-O2编译以减少混乱,但副作用是迫使编译器编写真实的的代码
godbolt显示
提醒,在大多数当前系统堆栈增长下来,即新的东西是一个t较低的地址,因此减去分配堆栈空间