GCC生成组装

问题描述 投票:7回答:1

为什么printf函数会导致序言的变化?

C code_1:

#include <cstdio>

int main(){
  int a = 11;
  printf("%d", a);
}

GCC -m32生成一个:

.LC0:
        .string "%d"
main:
        lea     ecx, [esp+4]           // What's purpose of this three
        and     esp, -16               // lines?
        push    DWORD PTR [ecx-4]      // 
        push    ebp
        mov     ebp, esp
        push    ecx
        sub     esp, 20                // why sub 20?
        mov     DWORD PTR [ebp-12], 11
        sub     esp, 8
        push    DWORD PTR [ebp-12]
        push    OFFSET FLAT:.LC0
        call    printf
        add     esp, 16
        mov     eax, 0
        mov     ecx, DWORD PTR [ebp-4]
        leave
        lea     esp, [ecx-4]
        ret

C code_2:

#include <cstdio>

int main(){
  int a = 11;
}

GCC -m32:

main:
        push    ebp
        mov     ebp, esp
        sub     esp, 16
        mov     DWORD PTR [ebp-4], 11
        mov     eax, 0
        leave
        ret

在第一个代码中添加前三行的目的是什么?如果可以,请解释第一个汇编代码。

编辑:

64位模式:

.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 11
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave
        ret
c++ c gcc assembly reverse-engineering
1个回答
8
投票

洞察力是编译器在函数调用时保持堆栈对齐。 对齐是16字节。

lea     ecx, [esp+4]           ;Save original ESP to ECX (ESP+4 actually)
and     esp, -16               ;Align stack on 16 bytes (Lower esp)

push    DWORD PTR [ecx-4]      ;Push main return address (Stack at 16B + 4)
                               ;My guess is to aid debugging tools that expect the RA
                               ;to be at [ebp+04h]
push    ebp
mov     ebp, esp               ;Prolog (Stack at 16B+8)

push    ecx                    ;Save ECX (Original stack pointer) (Stack at 16B+12)

sub     esp, 20                ;Reserve 20 bytes (Stack at 16B+0, ALIGNED AGAIN)
                               ;4 for alignment + 1x16 for a variable (variable space is
                               ;allocated in multiple of 16)

mov     DWORD PTR [ebp-12], 11 ;a = 11

sub     esp, 8                 ;Stack at 16B+8 for later alignment
push    DWORD PTR [ebp-12]     ;a
push    OFFSET FLAT:.LC0       ;"%d"     (Stack at 16B)
call    printf
add     esp, 16                ;Remove args+pad from the stack (Stack at 16B)

mov     eax, 0                 ;Return 0

mov     ecx, DWORD PTR [ebp-4] ;Restore ECX without the need to add to esp
leave                          ;Restore EBP

lea     esp, [ecx-4]           ;Restore original ESP
ret

我不知道为什么编译器在esp+4而不是ecx中保存espesp+4main的第一个参数的地址)。

© www.soinside.com 2019 - 2024. All rights reserved.