提问人:Zayed Aldhaheri 提问时间:10/27/2023 最后编辑:Peter CordesZayed Aldhaheri 更新时间:10/27/2023 访问量:104
有没有办法计算分配给函数堆栈帧的字节数?
Is there a way to calculate the bytes allocated to the stack frame of a function?
问:
我已经在 C 中获得了这段代码,我需要计算分配给函数算术堆栈帧的字节数。我到处寻找一种方法,但每个人都有不同的答案。
long arith(long x, long y, long z){
long t1 = x + y;
long t2 = z + t1;
long t3 = x + 4;
long t4 = y * 48;
long t5 = t3 + t4;
long rval = t2 * t5;
return rval;
}
arith:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -56(%rbp)
movq %rsi, -64(%rbp)
movq %rdx, -72(%rbp)
movq -56(%rbp), %rdx
movq -64(%rbp), %rax
addq %rdx, %rax
movq %rax, -48(%rbp)
movq -72(%rbp), %rdx
movq -48(%rbp), %rax
addq %rdx, %rax
movq %rax, -40(%rbp)
movq -56(%rbp), %rax
addq $4, %rax
movq %rax, -32(%rbp)
movq -64(%rbp), %rdx
movq %rdx, %rax
addq %rax, %rax
addq %rdx, %rax
salq $4, %rax
movq %rax, -24(%rbp)
movq -32(%rbp), %rdx
movq -24(%rbp), %rax
addq %rdx, %rax
movq %rax, -16(%rbp)
movq -40(%rbp), %rax
imulq -16(%rbp), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
每次我们调用数据类型 long 时,我都尝试将字节相加,所以 6*8,即 64 字节,但我对此不太确定。
答:
4赞
Peter Cordes
10/27/2023
#1
TL:DR:不,你不能只看C。
您需要查看特定构建的 asm 并计算 es 和 。push
sub $imm, %rsp
在这种情况下,变量不会因此正常构建(启用优化)仅使用寄存器,根本不接触堆栈指针。(你可以说变量的地址被优化了,因为它们没有转义函数,甚至没有任何东西首先采用它们的地址。
在 Godbolt 上使用 GCC13 亲自查看volatile
-O3 -fverbose-asm
# first set of comments is compiler-generated, second are hand-written
arith:
lea rax, [rsi+rsi*2] # t4, # RAX = y*3
sal rax, 4 # tmp96, # t4 = RAX = y*3*16 = y*48
lea rax, [rdi+4+rax] # t5, # t5 = RAX += x+4
add rdi, rsi # t1, y # t1 = x + y (replacing x in RDI)
add rdi, rdx # t2, tmp102 # t2 = x+y + z
imul rax, rdi # rval, t2 # rval = t5 * t2
ret
如果禁用了优化(为什么 clang 会使用 -O0 产生低效的 asm(对于这个简单的浮点和)?)),您可以根据命名 C 变量的 sizeof
() 和 alignof()
计算最小值(假设最佳打包),但编译器可能会出于各种原因保留更多,例如对齐 RSP,或者
- 为什么 GCC 在堆栈上分配的空间超出了对齐所需的空间?- GCC 未优化错误;使用更少的堆栈本质上是一种优化。
- 为什么使用返回值时将 0 移动到堆栈?- 禁用优化的 clang 有时会为返回值分配额外的空间
在 x86-64 System V ABI 的叶函数中,编译器只能将已保留的空间(红色区域)用于它需要的部分/全部空间,因此看起来需要的空间可能更少:
- 为什么编译器保留了一点堆栈空间,而不是整个数组大小?
- 或者在 Windows x64 中,编译器可以使用 32 字节的影子空间。有些人可能会选择仅将堆栈空间用于溢出传入的寄存器参数,而不用于其他局部变量。
评论