2010-10-26 24 views
8
$ gcc -O2 -S test.c -----------------------(1) 
     .file "test.c" 
    .globl accum 
     .bss 
     .align 4 
     .type accum, @object 
     .size accum, 4 
    accum: 
     .zero 4 
     .text 
     .p2align 2,,3 
    .globl sum 
     .type sum, @function 
    sum: 
     pushl %ebp 
     movl %esp, %ebp 
     movl 12(%ebp), %eax 
     addl 8(%ebp), %eax 
     addl %eax, accum 
     leave 
     ret 
     .size sum, .-sum 
     .p2align 2,,3 
    .globl main 
     .type main, @function 
    main: 
     pushl %ebp 
     movl %esp, %ebp 
     subl $8, %esp 
     andl $-16, %esp 
     subl $16, %esp 
     pushl $11 
     pushl $10 
     call sum 
     xorl %eax, %eax 
     leave 
     ret 
     .size main, .-main 
     .section .note.GNU-stack,"",@progbits 
     .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)" 

to kod zespół generowane programu C:analizowanie kodu zespół

#include <stdio.h> 
int accum = 0; 

int sum(int x,int y) 
{ 
    int t = x+y; 
    accum +=t; 
    return t; 
} 

int main(int argc,char *argv[]) 
{ 
    int i = 0,x=10,y=11; 
    i = sum(x,y); 
    return 0; 
} 

Ponadto, jest to kod wynikowy generowany z powyższego programu:

$objdump -d test.o -------------------------(2) 

test.o:  file format elf32-i386 

Disassembly of section .text: 

00000000 <sum>: 
    0: 55      push %ebp 
    1: 89 e5     mov %esp,%ebp 
    3: 8b 45 0c    mov 0xc(%ebp),%eax 
    6: 03 45 08    add 0x8(%ebp),%eax 
    9: 01 05 00 00 00 00  add %eax,0x0 
    f: c9      leave 
    10: c3      ret 
    11: 8d 76 00    lea 0x0(%esi),%esi 

00000014 <main>: 
    14: 55      push %ebp 
    15: 89 e5     mov %esp,%ebp 
    17: 83 ec 08    sub $0x8,%esp 
    1a: 83 e4 f0    and $0xfffffff0,%esp 
    1d: 83 ec 10    sub $0x10,%esp 
    20: 6a 0b     push $0xb 
    22: 6a 0a     push $0xa 
    24: e8 fc ff ff ff   call 25 <main+0x11> 
    29: 31 c0     xor %eax,%eax 
    2b: c9      leave 
    2c: c3      ret 

Idealnie wykaz (1) i (2) muszą być takie same. Ale widzę , że jest movl, pushl itp w wykazie (1) podczas gdy mov, push w lising (2). Moje pytanie brzmi:

  1. Która instrukcja poprawna jest rzeczywiście wykonana na procesorze?
  2. W wykazie (1), widzę to na początku:

.file "test.c" 
    .globl accum 
     .bss 
     .align 4 
     .type accum, @object 
     .size accum, 4 
    accum: 
     .zero 4 
     .text 
     .p2align 2,,3 
    .globl sum 
     .type sum, @function 

a to w końcu:

.size main, .-main 
      .section .note.GNU-stack,"",@progbits 
      .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)" 

Co to oznacza?

Dzięki.

Odpowiedz

13

Instrukcja nosi nazwę MOV niezależnie od używanego wariantu. Sufiks l jest po prostu konwencją zespołu gcc/AT & T w celu określenia wielkości wymaganych operandów, w tym przypadku 4 bajtowych operandów.

W Intel składni - gdzie istnieją jakiekolwiek dwuznaczność - zamiast przyrostka dyspozycję to zwykle oznaczyć parametr pamięci ze wskaźnikiem wielkości wymaganej (np BYTE, WORD, DWORD, itd.), To po prostu kolejny sposób osiągnięcia tego samego.

89 55 jest prawidłowa sekwencja bajtów dla MOV z rejestru 32-bitowego EBP w 32-bitowym rejestrze, ESP. Nie ma nic złego w żadnym ze spisów.


określenie pliku, ten kod zespół wytworzono z:

.file "test.c" 

mówi, że accum jest globalnym symbolem (C zmienna z zewnętrznym łącznikiem)

.globl accum 

Następujące bajty powinien być umieszczony w sekcji bss, jest to sekcja, która nie zajmuje miejsca w pliku obiektowym, ale jest alokowana i wyzerowana w czasie wykonywania.

 .bss 

wyrównany na granicy 4 bajtów:

 .align 4 

Jest to obiekt (zmienna, a nie jakiś kod):

 .type accum, @object 

To cztery bajty:

 .size accum, 4 

Oto gdzie jest accum zdefiniowane, cztery zero bajtów.

accum: 
     .zero 4 

Teraz przełącz z sekcji bss do sekcji tekstowej, w której zwykle przechowywane są funkcje.

 .text 

Dodaj do trzech bajtów wypełnienia aby upewnić się, że jesteśmy na 4 bajty (2^2) granice:

 .p2align 2,,3 

sum to światowy symbol i jest to funkcja.

.globl sum 
     .type sum, @function 

Wielkość main jest "tu" - "gdzie main rozpoczęła":

.size main, .-main 

To gdzie gcc opcje specyficzne stosu są określone. Zwykle jest to miejsce, w którym wybierasz stos wykonywalny (niezbyt bezpieczny) lub nie (zazwyczaj preferowany).

 .section .note.GNU-stack,"",@progbits 

Określić, która wersja kompilatora generowany ten zespół:

 .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-9)" 
+0

+9,000. Dziękuję Ci. Bit o opcjach konkretnego stosu GCC był bardzo pomocny. – kevinarpe

0

Assembler wystawianie i aukcja dezasembler pokazują ten sam kod, ale używać innej składni. Dołączony -l jest wariantem składni używanym przez gcc. To, że masz inną składnię w narzędziach (wynik kompilatora i deasembler) pokazuje słabość twojego toolchaina.

Demontaż z przesunięciem 11 w sumie: pokazuje tylko niektóre bajty śmieci. Punkt wejścia do następnej funkcji głównej jest wyrównany do 4 bajtów, co daje tę lukę, wypełnij śmieciami.

Grono .statements określa dokumentacja asemblera. Zwykle nie dają żadnego kodu wykonywalnego.