2013-04-30 15 views
6

Uczę się, jak plik C jest kompilowany do kodu maszynowego. Wiem, że mogę wygenerować zestaw od gcc z flagą -S, jednak generuje on również dużo kodu związanego z main() i printf(), w tej chwili nie jestem zainteresowany.Czy istnieje sposób na wydrukowanie zespołu pojedynczej funkcji w izolacji?

Czy istnieje sposób, aby uzyskać gcc lub clang do „skompilować” funkcję w izolacji i wysyłać montażowej?

tj. dostać zespół na kolejny C w izolacji:

int add(int a, int b) { 
    return a + b; 
} 
+0

Niektóre IDE umożliwiają ustawienie punktu przerwania i wyświetlenie kodu zespołu wygenerowanego przez tę funkcję. To się nazywa okno * demontażu *. To powinno zrobić to, czego szukasz - czy korzystasz z IDE? – Aaron

+0

Wolę kompilować (z optymalizacją), a następnie dezasemblować, trzeba zrozumieć, że kompilator pozostawi kilka instrukcji niekompletnych dla adresów zewnętrznych i takich, ale łatwiej jest odczytać IMO niż przy użyciu -S. gcc -O2 -c hello.c -o hello.o, objdump -D hello.o –

+3

Przejdź tutaj: http://gcc.godbolt.org/ wklej funkcję, wybierz kompilator, bardzo przydatny. – harold

Odpowiedz

7

Istnieją dwa sposoby, aby to zrobić dla konkretnego pliku obiektu:

  1. Opcja gcc-ffunction-sections nakazuje mu, aby utworzyć sekcję oddzielny ELF dla każdej funkcji w SourceFile jest skompilowany.
  2. Tabela symboli zawiera nazwę sekcji, adres początkowy i rozmiar danej funkcji; które można wprowadzić do objdump za pośrednictwem argumentów --start-address/--stop-address.

Pierwszy przykład:

$ readelf -S t.o | grep ' .text.' 
    [ 1] .text    PROGBITS   0000000000000000 00000040 
    [ 4] .text.foo   PROGBITS   0000000000000000 00000040 
    [ 6] .text.bar   PROGBITS   0000000000000000 00000060 
    [ 9] .text.foo2  PROGBITS   0000000000000000 000000c0 
    [11] .text.munch  PROGBITS   0000000000000000 00000110 
    [14] .text.startup.mai PROGBITS   0000000000000000 00000180

ten został skompilowany z -ffunction-sections i istnieją cztery funkcje, foo(), bar(), foo2() i munch() w moim pliku wynikowego. Mogę demontować je oddzielnie tak:

$ objdump -w -d --section=.text.foo t.o 

t.o:  file format elf64-x86-64 

Disassembly of section .text.foo: 

0000000000000000 <foo>: 
    0: 48 83 ec 08    sub $0x8,%rsp 
    4: 8b 3d 00 00 00 00  mov 0(%rip),%edi  # a <foo+0xa> 
    a: 31 f6     xor %esi,%esi 
    c: 31 c0     xor %eax,%eax 
    e: e8 00 00 00 00   callq 13 <foo+0x13> 
    13: 85 c0     test %eax,%eax 
    15: 75 01     jne 18 <foo+0x18> 
    17: 90      nop 
    18: 48 83 c4 08    add $0x8,%rsp 
    1c: c3      retq

Inną opcją może być stosowany tak (nm wysypisk wpisów w tabeli symbol):

$ nm -f sysv t.o | grep bar 
bar  |0000000000000020| T | FUNC|0000000000000026|  |.text 
$ objdump -w -d --start-address=0x20 --stop-address=0x46 t.o --section=.text 

t.o:  file format elf64-x86-64 

Disassembly of section .text: 

0000000000000020 <bar>: 
    20: 48 83 ec 08    sub $0x8,%rsp 
    24: 8b 3d 00 00 00 00  mov 0(%rip),%edi  # 2a <bar+0xa> 
    2a: 31 f6     xor %esi,%esi 
    2c: 31 c0     xor %eax,%eax 
    2e: e8 00 00 00 00   callq 33 <bar+0x13> 
    33: 85 c0     test %eax,%eax 
    35: 75 01     jne 38 <bar+0x18> 
    37: 90      nop 
    38: bf 3f 00 00 00   mov $0x3f,%edi 
    3d: 48 83 c4 08    add $0x8,%rsp 
    41: e9 00 00 00 00   jmpq 46 <bar+0x26>

w tym przypadku opcja -ffunction-sections nie ma został użyty, dlatego początkowe przesunięcie funkcji nie jest równe zeru i nie ma go w osobnej sekcji (ale w .text).

Uważaj jednak podczas demontażu plików obiektowych ...

To nie jest dokładnie co chcesz, ponieważ pliki obiektu, call cele (jak również adresy zmiennych globalnych) nie zostały rozwiązane - nie widzisz tutaj, że foo dzwoni printf, ponieważ rozdzielczość tego na poziomie binarnym dzieje się tylko w czasie połączenia. Źródło zestawu miałoby tam jednak numer call printf.Informacja, że ​​ta callq jest w rzeczywistości do printf znajduje się w pliku obiektowym, ale oddzielona od kodu (jest to sekcja o nazwie relokacja, która wymienia lokalizacje w pliku obiektowym, które mają być "załatane" przez linker); dezasembler nie może tego rozwiązać.

+0

Widzę, po prostu dla kogoś innego, możesz użyć "gcc -ffunction-sections -c test.c", aby skompilować plik źródłowy do pliku obiektowego. Dzięki ~ – ashleysmithgpu

0

Najlepszym sposobem, aby przejść byłoby skopiować swoją funkcję w jednym temp.c C pliku i skompilować go z flagą -c jak ten: gcc -c -S temp.c -o temp.s

Powinno to skutkować bardziej dokręconym kodem montażowym bez żadnych innych zakłóceń (z wyjątkiem nagłówka i stopki).

Powiązane problemy