c - 当我只有一个 4 字节的局部变量时,为什么堆栈在反汇编中增长了 16 个字节?

标签 c assembly x86 calling-convention gcc8

我无法理解为什么编译器选择以我编写的代码的方式偏移堆栈空间。

我在玩弄 Godbolt 的编译器资源管理器以研究 C 调用约定,当我想出一个简单的代码时,我对它的选择感到困惑。

代码在 this link 中找到.我选择了 GCC 8.2 x86-64,但我的目标是 x86 处理器,这很重要。下面是编译器资源管理器报告的 C 代码和生成的程序集的转录。

// C code
int testing(char a, int b, char c) {
    return 42;
}

int main() {
    int x = testing('0', 0, '7');

    return 0;
}
; Generated assembly
testing(char, int, char):
        push    ebp
        mov     ebp, esp
        sub     esp, 8
        mov     edx, DWORD PTR [ebp+8]
        mov     eax, DWORD PTR [ebp+16]
        mov     BYTE PTR [ebp-4], dl
        mov     BYTE PTR [ebp-8], al
        mov     eax, 42
        leave
        ret
main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        push    55
        push    0
        push    48
        call    testing(char, int, char)
        add     esp, 12
        mov     DWORD PTR [ebp-4], eax
        mov     eax, 0
        leave
        ret

从现在开始看汇编专栏,据我了解,第15行负责为局部变量保留堆栈空间。问题是我只有一个本地 int 并且偏移量是 16 个字节而不是 4 个字节。这感觉像是浪费了空间。

这和单词对齐有关系吗?但即使是,如果通用寄存器的大小是 4 个字节,这种对齐不应该是关于 4 个字节吗?

我看到的另一件奇怪的事情是关于 testing 函数的本地 char 的放置。它们似乎在堆栈中各占用 4 个字节,如第 7-8 行所示,但仅操作了较低的字节。为什么不每个只使用 1 个字节?

这些选择可能是出于好意,我很想了解它们的目的(或者是否没有目的)。或者,也许我只是感到困惑,没有完全理解。

最佳答案

因此,根据评论,我可以弄清楚堆栈增长问题是由于 i386 SystemV ABI 要求引起的,如@PeterCordes 所述。

字符按字对齐的原因可能是由于 GCC 提高速度的默认行为,这可能是从 @Ped7g 的评论中推断出来的。虽然不确定,但这对我来说已经足够好了。

关于c - 当我只有一个 4 字节的局部变量时,为什么堆栈在反汇编中增长了 16 个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54210828/

相关文章:

debugging - 有哪些可用的可执行二进制格式和模拟器?

assembly - 使用段寄存器(今天)有什么好处?

c - `timeout` 超时中的未知参数 `Z3_set_param_value(cfg, "", "10")`;

java - 在 Linux 上调用 JNI 代码时奇怪的崩溃;我是否正确编译了我的共享库?

c++ - 从 .so/.o 文件获取 c/cpp 中的静态库列表

c - 如何从程序本身获取指向特定可执行文件部分的指针? (也许与 libelf)

windows - 汇编中的非法指令

assembly - 如何将16位寄存器的符号相反扩展到8位寄存器?

Windows内核内存保护

c++ - 移位语法错误