编译器如何在堆栈上使用默认值为零来初始化本地数组?

How does the compiler initialize local arrays with a default value of zero on the stack?

假设我在我的函数中定义了一个默认值为 0 的 int 局部数组:

void test() {
    int array[256] = {0};
}

我的理解是:

数组将存储在堆栈中,方法是将 256 个零压入堆栈并随后增加堆栈指针。如果数组没有默认值,增加堆栈指针就足够了。

现在这是由前面的片段生成的汇编代码:

test:
.LFB2:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %edi
    pushl   %ebx
    subl    24, %esp
    .cfi_offset 7, -12
    .cfi_offset 3, -16
    leal    -1032(%ebp), %ebx
    movl    [=11=], %eax
    movl    6, %edx
    movl    %ebx, %edi
    movl    %edx, %ecx
    rep stosl
    addl    24, %esp
    popl    %ebx
    .cfi_restore 3
    popl    %edi
    .cfi_restore 7
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE2:
    .size   test, .-test

我意识到这可能是一个愚蠢的问题,而且我知道每个编译器的行为可能不同,但我想知道具有 256 个零的数组的分配发生在何处。我的假设是正确的还是情况有所不同?

(我已经很长时间没有写汇编了,我在理解发生了什么方面遇到了一些困难)

正在此处进行分配:

    subl    24, %esp                 

它是堆栈指针esp上的sub,因为堆栈向下增长。

此处清空数组:

    movl    [=11=], %eax
    movl    6, %edx     
    movl    %ebx, %edi 
    movl    %edx, %ecx
    rep stosl

它的作用是:

  • rep : 重复字符串操作ecx
  • stosl:将eax存入edi指向的内存中,edi加4,或减4,取决于方向标志。如果很清楚 (cld),edi 会递增,否则会递减。 请注意,ebx 在代码中稍早一点设置为指向数组的开头。

最后,数组在这里被释放:

    addl    24, %esp


这些是亮点,但还有一些注意事项,所以这里是(未优化的)代码的完整列表:

pushl   %ebp                # preserve caller's ebp (decrements esp by 4)
movl    %esp, %ebp          # copy stack pointer to ebp
pushl   %edi                # preserve for caller
pushl   %ebx                # preserve for caller
subl    24, %esp         # allocate 1kb on the stack
leal    -1032(%ebp), %ebx   # esp + 1024 + 4 + 4 = ebp; equivalent to mov %esp, %ebx
movl    [=13=], %eax            # the {0}
movl    6, %edx          # the repeat count - could have been stored in ecx directly
movl    %ebx, %edi          # init edi to the start of the array
movl    %edx, %ecx          # put 256 in ecx
rep stosl                   # repeat 'mov %eax, %(edi); add , %edi' ecx times
addl    24, %esp         # release the array
popl    %ebx                # and the preserved registers
popl    %edi
popl    %ebp                
ret