在堆栈上分配String

new*_*int 1 c assembly

我在堆栈上分配12个字符串,或者相当于它是12个字节.

使用gdb(在Linux下)进行分解表明,为了在堆栈上为字符串分配空间,esp会被-24(向下移动)移动.

push   %ebp
mov    %esp,%ebp
sub    $0x18,%esp
Run Code Online (Sandbox Code Playgroud)

为什么它移动了24(0x18)?

Mat*_*ery 6

如果您的函数调用其他参数,其中一些可能是传出参数的空间; 其中一些可能是从寄存器中溢出的价值的临时空间; 其中一些可能是填充.它将非常依赖于编译器版本和优化标志.

这里有一些简单的无意义代码用于说明:

extern int foo(int a, int b);

int bar(int c)
{
    char s[12];

    s[0] = foo(c, 123);
    return 456;
}
Run Code Online (Sandbox Code Playgroud)

这里使用gcc 4.3.2在Debian Lenny机器上编译时没有进行优化:

bar:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $123, 4(%esp)
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    foo
    movb    %al, -12(%ebp)
    movl    $456, %eax
    leave
    ret
Run Code Online (Sandbox Code Playgroud)

与您的代码一样,它分配24个字节.这是他们用于:

     Stack while running bar()
    :                         :
    +-------------------------+
    | incoming parameter: c   | 8(%ebp)
    +-------------------------+            ---
    | return address          | 4(%ebp)     ^
    +-------------------------+             |
    | old %ebp                | (%ebp)      |
    +-------------------------+             |  bar()'s stack
    | s[8]..s[11]             | -4(%ebp)    | frame: 32 bytes
    +-------------------------+             |
    | s[4]..s[7]              | -8(%ebp)    |
    +-------------------------+             |
    | s[0]..s[3]              | -12(%ebp)   |
    +-------------------------+             |     Stack while running foo()
    | (unused)                | 8(%esp)     |    :                         :
    +-------------------------+             |    +-------------------------+
    | outgoing parameter: 123 | 4(%esp)     |    | incoming parameter: b   |
    +-------------------------+             |    +-------------------------+
    | outgoing parameter: c   | (%esp)      v    | incoming parameter: a   |
    +-------------------------+            ---   +-------------------------+
                                                 | return address          |
                                                 +-------------------------+
                                                 | old %ebp                |
                                                 +-------------------------+
                                                 : locals for foo()        :

一些实验表明,如果s[]增加,它将进入未使用的空间; 例如,如果它是13个字节,则堆栈帧的大小相同,但是s[]会先提前一个字节(at -13(%ebp)) - 最多16个字节,其中实际使用所有分配的堆栈.如果s声明为s[17],则编译器将分配40个字节的堆栈而不是24个.

这是因为编译器保持堆栈帧的总大小(上图中左侧的所有内容,除了传入参数,实际上位于调用者堆栈帧的底部)四舍五入为16个字节的倍数.(有关该-mpreferred-stack-boundary选项,请参阅gcc文档.)