c - 字符串在栈上的分配

标签 c assembly

我在堆栈上分配了 12 个字符字符串,或者说它是 12 个字节。

使用 gdb(在 Linux 下)反汇编表明,为了在堆栈上为字符串分配空间,esp 移动了 -24(在堆栈下)。

push   %ebp
mov    %esp,%ebp
sub    $0x18,%esp

为什么移动24(0x18)?

最佳答案

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

下面是一些简单的废话代码来说明:

extern int foo(int a, int b);

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

    s[0] = foo(c, 123);
    return 456;
}

这里是在 Debian Lenny 机器上使用 gcc 4.3.2 编译的,没有优化:

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

与您的代码一样,它分配了 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[] 将提前一个字节开始(在 -13(%ebp))- 最多 16字节,其中所有分配的堆栈将实际使用。如果 s 声明为 s[17],编译器将分配 40 字节的堆栈而不是 24。

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

关于c - 字符串在栈上的分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4270756/

相关文章:

c - ARM 上的堆和堆栈测量

assembly - 写入正在运行的汇编程序

c++ - 在主要 C/C++ 编译器生成的代码中注册分配规则

c - 如何将 GSList 放入 GHashTable 中?

c - 段错误,增加指针中的值

c - 使移动位更有效率

linux - x86 反汇编中 <<< 和 >>> 的含义

assembly - ARM算术加法和标志更新

linux - 在 shellcode NASM 的 JMP CALL POP 技术中避免 JMP?

代码只接受输入值然后什么也不会发生