2016-12-14 2 views
7

Почему функция printf вызывает смену пролога?GCC сборка

С 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 
+0

Возможно, [Godbolt] (https://godbolt.org/g/OyxeLq) -Tool может помочь вам в анализе. – Frodo

+0

Я использую Godbolt. Эта сборка создается на Godbolt :) –

ответ

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 вместо esp (esp+4 это адрес первого параметра main).

+0

Если эти первые три строки необходимы для сохранения информации, почему 64-битный код использует то же самое? (просмотреть отредактированный пост) –

+0

@ J.Doe Что же? 64-битный код имеет стандартный пролог. –

+0

Почему 64-битный режим не сохраняет исходный ESP, как в 32-битном режиме? –

Смежные вопросы