在汇编时Int与Double

2 c c++ x86 gcc reverse-engineering

为什么GCC编译器在使用double时会添加这三行而在有Int时不添加?


使用int:

#include <cstdio>

int main(){
    int i = 1;
}
Run Code Online (Sandbox Code Playgroud)

==>

main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        mov     DWORD PTR [ebp-4], 1
        mov     eax, 0
        leave
        ret
Run Code Online (Sandbox Code Playgroud)

双倍:

#include <cstdio>

int main(){
    double i = 1;
}
Run Code Online (Sandbox Code Playgroud)

==>

main:
        lea     ecx, [esp+4]            // This three lines
        and     esp, -8                 //  ...
        push    DWORD PTR [ecx-4]       //  ...
        push    ebp
        mov     ebp, esp
        push    ecx
        sub     esp, 20
        fld1
        fstp    QWORD PTR [ebp-16]
        mov     eax, 0
        add     esp, 20
        pop     ecx
        pop     ebp
        lea     esp, [ecx-4]
        ret
Run Code Online (Sandbox Code Playgroud)

使用指针时会发生类似的情况,例如,int*s = new int(4);

你能解释为什么会这样,为什么不总是这样?

Sam*_*hik 7

double自动作用域(在堆栈上)的情况下,额外的代码将堆栈帧在偶数8字节边界处对齐,以便将double变量存储在具有适当对齐的存储器地址处.进入函数时,堆栈指针不能保证在偶数8字节边界上对齐,编译器会添加额外的代码来实现它.

这就是它的and esp, -8作用.-8是0xFFFFFFF8.这将清除的最后3个位esp,使用and,使得它指向一个甚至8个字节的边界存储器地址,调整它向下(堆栈从高增长到低存储器地址).

  • 在x86上,`double`是64位类型,需要8字节对齐,但ABI不要求堆栈是8字节对齐的.同样的事情发生在`long long`,BTW,因为它也是一个8字节类型.对于`int`没有必要,因为它只是一个4字节类型,并且堆栈指针保证是4字节对齐的. (2认同)