gcc/g++如何处理变长数组

mdfafbf1  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(132)

下面是一些简单的C++代码。我在test_func中定义了一个变长数组。我想知道数组arrrbp寄存器之间的关系。

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寄存器的关系。

xfb7svmp

xfb7svmp1#

与处理固定大小数组的方式差不多。堆栈指针按对象的大小递减。通常计算所有局部变量的堆栈大小,并在开始时进行一次堆栈调整。对于动态请求的堆栈(法律的c VLA,gcc '非法' c++ VLA,alloca,...),当大小已知时,将进一步递减
下面是一个c版本-使用-O2编译以减少混乱,但副作用是迫使编译器编写真实的的代码

#include <stdio.h>

int main(){

    int sz;
    scanf("%d", &sz);
    int j[sz];
    for(int i = 0; i < sz; i++){
        j[i] = sz+22;
    }
    printf("%d", j[sz/2]);
}

godbolt显示

.LC0:
        .string "%d"
main:
        push    rbp
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        mov     rbp, rsp
        sub     rsp, 16
        lea     rsi, [rbp-4]
        call    __isoc99_scanf
        movsx   rdx, DWORD PTR [rbp-4]
        mov     rsi, rdx
        sal     rdx, 2
        lea     rax, [rdx+15]
        and     rax, -16
        sub     rsp, rax   <<<<<==== dynamically adjusted top of stack
        mov     rdi, rsp
        add     rdx, rdi
        test    esi, esi
        jle     .L4
        lea     ecx, [rsi+22]
        mov     rax, rdi
.L3:
        mov     DWORD PTR [rax], ecx
        add     rax, 4
        cmp     rax, rdx
        jne     .L3
.L4:
        mov     eax, esi
        shr     eax, 31
        add     eax, esi
        sar     eax
        cdqe
        mov     esi, DWORD PTR [rdi+rax*4]
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        call    printf
        xor     eax, eax
        leave
        ret

提醒,在大多数当前系统堆栈增长下来,即新的东西是一个t较低的地址,因此减去分配堆栈空间

相关问题