2016-12-14 21 views
7

Tại sao chức năng printf gây ra thay đổi phần mở đầu?Lắp ráp GCC được tạo ra

C code_1:

#include <cstdio> 

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

GCC -m32 tạo một:

.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 

Mục đích của ba dòng đầu tiên được thêm vào trong mã đầu tiên là gì? Vui lòng giải thích mã lắp ráp đầu tiên, nếu có thể.

EDIT:

64-bit mode:

.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

Có thể [Godbolt] (https://godbolt.org/g/OyxeLq) -Tool có thể giúp bạn phân tích. – Frodo

+0

Tôi đang sử dụng Godbolt. Hội đồng này được tạo ra trên Godbolt :) –

Trả lời

8

Sự thấu hiểu là trình biên dịch giữ chồng liên kết tại các cuộc gọi chức năng.
Căn chỉnh là 16 byte.

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 

Tôi không biết lý do tại sao các trình biên dịch tiết kiệm esp+4 trong ecx thay vì esp (esp+4 là địa chỉ của tham số đầu tiên của main).

+0

Nếu ba dòng đầu tiên này là cần thiết để lưu thông tin, tại sao mã 64 bit sử dụng cùng một thứ? (xem bài viết đã chỉnh sửa) –

+0

@ J.Doe Điều tương tự? Mã 64 bit có chuẩn prolog. –

+0

Tại sao chế độ 64 bit không lưu ESP gốc như ở chế độ 32 bit? –

Các vấn đề liên quan