有没有办法计算分配给函数堆栈帧的字节数?

Is there a way to calculate the bytes allocated to the stack frame of a function?

提问人:Zayed Aldhaheri 提问时间:10/27/2023 最后编辑:Peter CordesZayed Aldhaheri 更新时间:10/27/2023 访问量:104

问:

我已经在 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 字节,但我对此不太确定。

C 程序集 x86-64 内存堆栈

评论

2赞 Armali 10/27/2023
如果你不能判断如何处理你已经拥有的答案,你会用你在这里得到的更多答案做什么?
1赞 user207421 10/27/2023
至少 6 个多头加上一个返回地址和一个基指针。
2赞 Ted Lyngmo 10/27/2023
我假设需要在堆栈上分配的字节数取决于您是否对其进行了优化的编译以及函数是否可以内联。
2赞 Ian Abbott 10/27/2023
变量和参数可以存储在寄存器中,不需要任何堆栈空间。
2赞 0___________ 10/27/2023
使用合理的编译选项 - 0 字节。根本不使用堆栈。变量不是必需的,将被优化出来。godbolt.org/z/3EcP4j1Kd

答:

4赞 Peter Cordes 10/27/2023 #1

TL:DR:不,你不能只看C。
您需要查看特定构建的 asm 并计算 es 和 。
pushsub $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,或者

在 x86-64 System V ABI 的叶函数中,编译器只能将已保留的空间(红色区域)用于它需要的部分/全部空间,因此看起来需要的空间可能更少: