long vframe(long n, long idx, long *q){
long i;
long *p[n];
p[0] = &i;
for(i=1; i<n; i++)
p[i]=q;
return *p[idx];
}
我具有vframe函数并生成了这样的汇编代码
1: vframe:
2: pushq %rbp
3: movq %rsp, %rbp
4: subq $16, %rsp
5: leaq 22(, %rdi, 8), %rax # I think the number 22 is vary from machine and OS
6: andq $-16, %rax
7: subq %rax, %rsp
8: leaq 7(%rsp), %rax
9: shrq $3, %rax
10: leaq 0(, %rax, 8), %r8
11: movq %r8, %rcx
................................
12: L3:
13: movq %rdx, (%rcx, %rax, 8)
14: addq $1, %rax
15: movq %rax, -8(%rbp)
16: L2:
17: movq -8(%rbp), %rax
18: cmpq %rdi, %rax
19: jl L3
20: leave
21: ret
如果我们看到从8到11的行,我们没有将p的地址压入堆栈,但是汇编已经假定&p [0]在%rsp中,因为leaq 0(,%rax,8),%r8表示指令将%r8设置为&p [0] (实际上,我通过检查自己的编译器来检查变量是否已移至堆栈 就像movq $ 0x1,-0x8(%rbp),但我找不到&p [0])
如果我们希望某些参数不被破坏,则推送一些寄存器,并将被调用方保存的寄存器移到推送的寄存器中。但是,在这种情况下,似乎不是。 这段代码中是否还有其他有关局部变量的约定,例如i和&p [0]?我的意思是即使我们没有将&p [0]压入堆栈,为什么&p [0]也位于%rsp中?
答案 0 :(得分:2)
编译器在内部跟踪每个局部变量的偏移量,包括p。它不需要在堆栈上存储局部变量的地址。在这种情况下,它知道p为(%rsp)。
此代码除了使用rbp之外,不使用任何保留呼叫的寄存器,因此它是唯一保存的寄存器。