Okunabilir montaj üretmek için GCC mi kullanıyorsunuz?


256

Kodumun ne derlendiğini görebilmem için makine kodunun anımsatıcı bir versiyonunu dökmek için C kaynak dosyamda GCC'yi nasıl kullanacağımı merak ediyordum . Bunu Java ile yapabilirsiniz, ancak GCC ile bir yol bulamadım.

Montajda bir C yöntemini yeniden yazmaya çalışıyorum ve GCC nasıl yaptığını görmek büyük bir yardımcı olacaktır.


25
'bayt kodu' genellikle JVM veya .NET CLR gibi bir VM tarafından tüketilen kod anlamına gelir. GCC'nin çıktısına daha iyi 'makine kodu', 'makine dili' veya 'montaj dili' denir
Javier

2
Godbolt kullanarak bir cevap ekledim, çünkü farklı seçeneklerin kod üretiminizi nasıl etkilediğini hızla denemek için çok güçlü bir araç.
Shafik Yaghmour



Asm çıkışının okunabilir hale getirilmesine ilişkin daha fazla ipucu için ayrıca bkz: GCC / clang montaj çıkışından “gürültü” nasıl kaldırılır?
Peter Cordes

Yanıtlar:


335

Hata ayıklama sembolleri ile derlerseniz, objdumpdaha okunabilir bir sökme işlemi için kullanabilirsiniz.

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel Güzel:

  • -rrelocations üzerinde gösterileri sembol isimleri (ulaşacağınızı yüzden putsde callaşağıda talimat)
  • -R dinamik bağlantı konumlarını / simge adlarını gösterir (paylaşılan kitaplıklarda yararlıdır)
  • -C demangles C ++ sembol adları
  • -w "geniş" mod: makine kodu baytlarını satır kaydırmaz
  • -Mintel: .intel_syntax noprefixAT&T yerine GAS / binutils MASM benzeri sözdizimini kullanın
  • -S: demontajlı kaynak hatları serpiştirin.

Sen gibi bir şey koyabilirsiniz alias disas="objdump -drwCS -Mintel"içinde senin~/.bashrc


Misal:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret

3
Yalnızca Intel talimatlarını almak için bir anahtar var mı?
James

3
Tüm bunlar Intel işlemcilerde çalıştığı için Intel talimatlarıdır: D.
toto

12
@toto Bence AT&T sözdizimi yerine Intel sözdizimi anlamına geliyor
Amok

7
Anahtar nesne kullanılarak ara nesne dosyasını ile birlikte bırakmak mümkündür -Wa,-adhln -g to gcc. Bu, birleştiricinin gaz olduğunu varsayar ve bu her zaman böyle olmayabilir.
Marc Butler

8
@James Evet, tedarik -Mintel.
fuz

106

GCC'ye bayrak verirseniz -fverbose-asm,

Daha okunabilir hale getirmek için oluşturulan montaj koduna fazladan yorum bilgisi ekleyin.

[...] Eklenen yorumlar şunları içerir:

  • derleyici sürümü ve komut satırı seçenekleri hakkında bilgi,
  • montaj talimatları ile ilişkili kaynak kodu satırları, FILENAME: LINENUMBER: CONTENT OF LINE biçiminde,
  • üst düzey ifadelerin çeşitli montaj talimatı işlenenlerine karşılık geldiği ipuçları.

Ama sonra, kullanılan tüm anahtarını kaybetmiş olur objdump- objdump -drwCS -Mintel, peki nasıl böyle bir şey kullanabilirsiniz verboseile objdump? Böylece -fverbose-asmgcc gibi asm kodunda yorum alabilir miyim ?
Çoban

1
@Herdsman: Yapamazsın. Eklenen şeyler -fverbose-asm, .odosyaya fazladan bir şey koyacak yönergeler değil, çıktının asm sözdizimindeki yorumlar biçimindedir . Hepsi bir araya geldiğinde atılır. Demontaj yerine derleyici asm çıktısına bakın , örneğin ilgili kaynak / asm hatlarının fareyle üzerine getirilmesi ve renk vurgulanmasıyla kaynak hattıyla kolayca eşleştirebileceğiniz godbolt.org'da . GCC / clang montaj çıkışından "gürültü" nasıl kaldırılır?
Peter Cordes

75

GCC'ye -S (note: capital S) anahtarını kullanın, derleme kodunu .s uzantılı bir dosyaya yayar. Örneğin, aşağıdaki komut:

gcc -O2 -S foo.c

oluşturulan derleme kodunu foo.s dosyasında bırakacaktır.

Doğrudan http://www.delorie.com/djgpp/v2faq/faq8_20.html adresinden kopyalandı (ancak hatalı kaldırma -c)


35
-C ve -S'yi karıştırmamalısınız, sadece birini kullanın. Bu durumda, muhtemelen kullanıldıkları sıraya bağlı olarak biri diğerini geçersiz kılar.
Adam Rosenfield

4
@AdamRosenfield '-c ve -S' yi karıştırmamalı mı? Doğruysa, yazara hatırlatmalı ve düzenlemeliyiz.
Tony

5
@Tony : gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options " gcc'nin nerede duracağını söylemek için -c, -S veya -E seçeneklerinden birini kullanabilirsiniz . "
Nate Eldredge

1
Tüm ara çıkışları istiyorsanız kullanın gcc -march=native -O3 -save-temps. Yine de -c, bağlantı oluşturmaya çalışmadan nesne dosyası oluşturmayı durdurmak için kullanabilirsiniz .
Peter Cordes

2
-save-tempsbir seferde tam kod üretilen kodu dökerken ilginçtir, oysa derleyiciyi -Siki kez derleme araçlarıyla ve muhtemelen farklı seçeneklerle çağırmanın diğer seçeneği . Ama -save-temps hepsi şu anki dizine dökülüyor, ki bu biraz dağınık. Kodunuzu incelemek için bir araç yerine GCC için bir hata ayıklama seçeneği olarak düşünülmüş gibi görünüyor.
Stéphane Gourichon

50

-SX86 tabanlı sistemlerde GCC anahtarını kullanmak, varsayılan olarak, -masm=attanahtarla belirtilebilen bir AT&T sözdizimi dökümü üretir :

gcc -S -masm=att code.c

Intel sözdiziminde bir döküm oluşturmak istiyorsanız, -masm=intelanahtarı şu şekilde kullanabilirsiniz :

gcc -S -masm=intel code.c

(Her ikisi de sırasıyla code.cçeşitli sözdizimlerine, dosyaya dökümler üretir code.s)

Objdump ile benzer efektler üretmek için --disassembler-options= intel/ attswitch'i kullanmak istersiniz , bir örnek (sözdizimindeki farklılıkları göstermek için kod dökümleriyle birlikte):

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

ve

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ce:   55                      push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop

Ne ... gcc -S -masm=intel test.cBenim için tam olarak çalışma yaptı, ben Intel ve bunun gibi AT & T sözdizimi bazı crossbreed var: mov %rax, QWORD PTR -24[%rbp]bunun yerine: movq -24(%rbp), %rax.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

1
Güzel ipucu. Bunun ayrıca .oASM dosyalarının paralel çıkışını gerçekleştirirken de işe yaradığına dikkat edilmelidir , yani-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d

-MSeçeneği kullanabilir , aynı --disassembler-optionsama çok daha kısa, örneğinobjdump -d -M intel a.out | less -N
Eric Wang

34

godbolt çok kullanışlı bir araçtır, sadece C ++ derleyicileri vardır, ancak -x ckodu C olarak işlemek için bayrağı kullanabilirsiniz . Daha sonra kodunuz için yan yana bir montaj listesi Colouriseoluşturacak ve oluşturma seçeneğini kullanabilirsiniz oluşturulan kaynakla hangi kaynak kodunun eşleştiğini görsel olarak göstermek için renkli çubuklar. Örneğin, aşağıdaki kod:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

aşağıdaki komut satırını kullanarak:

-x c -std=c99 -O3

ve Colouriseaşağıdakileri oluşturur:

resim açıklamasını buraya girin


Godbolt filtrelerinin nasıl çalıştığını bilmek güzel olurdu: .LC0, .text, // ve Intel. Intel kolaydır -masm=intel, gerisi ne olacak?
Z boson

Sanırım burada açıklanmıştır stackoverflow.com/a/38552509/2542702
Z bozonu

godbolt C'yi destekliyor (Rust, D, Pascal gibi bir ton başka dil ile birlikte). Sadece çok daha az C derleyicisi var, bu yüzden C ++ derleyicilerini kullanmak daha iyidir-x c
phuclv

23

Denediniz mi gcc -S -fverbose-asm -O source.coluşturulan içine bakmak sonra source.smontajcı dosyası?

Oluşturulan birleştirici kodu girer source.s(bunu -o birleştirici-dosya adıyla geçersiz kılabilirsiniz ); -fverbose-asmseçenek oluşturulan montajcı kodu "açıklayan" Bazı montajcı yorumlarınızı yayacak şekilde derleyici sorar. -OSeçeneği (o daha iyi duruma olabilir biraz optimize etmek derleyici sorar -O2ya -O3).

Ne gccyaptığını anlamak istiyorsanız geçmeyi deneyin, -fdump-tree-allancak dikkatli olun: yüzlerce döküm dosyası alırsınız.

BTW, GCC, eklentilerle genişletilebilir veya MELT ( GCC'yi genişletmek için yüksek düzeyde alana özgü bir dil; 2017'de terk ettiğim)


belki source.sbir çok insan konsolda bir çıktı beklediğinden, çıktının gerçekleşeceğini belirtin .
RubenLaguna

1
@ ecerulm: -S -o-stdout'a döker. -masm=intelNASM / YASM sözdizimini kullanmak istiyorsanız faydalıdır. (ancak sadece kullanmak qword ptr [mem]yerine qwordNASM / YASM yerine Intel / MASM gibi). gcc.godbolt.org , çöplüğü toplamak için iyi bir iş çıkarır : isteğe bağlı olarak yalnızca yorum satırlarını, kullanılmayan etiketleri ve montajcı yönergeleri.
Peter Cordes

2
Unutmayı unutma: "Kaynağa benzer, ancak her kaynak hattından sonra depola / yeniden yükle gürültüsü olmadan" arıyorsanız, o -Ogzaman bile daha iyidir -O1. "Hata ayıklama için optimize et" anlamına gelir ve kaynağın söylediği her şeyi yapan çok fazla zor / takip edilmesi zor optimizasyon olmadan yükselir. Gcc4.8'den beri mevcut, ancak clang 3.7 hala sahip değil. İDK aleyhine veya neye karşı karar verdiler.
Peter Cordes

19

Bunun için objdump gibi gdb kullanabilirsiniz.

Bu alıntı http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64 adresinden alınmıştır.


İşte Intel x86 için karışık kaynak + derlemesini gösteren bir örnek:

  (gdb) disas / m ana
Fonksiyon ana için montajcı kodu dökümü:
5 {
0x08048330:% ebp zorla
0x08048331: mov% esp,% ebp
0x08048333: alt $ 0x8,% esp
0x08048336: ve $ 0xfffffff0,% esp
0x08048339: alt $ 0x10,% esp

6 printf ("Merhaba. \ N");
0x0804833c: mov $ 0x8048440, (% esp)
0x08048343: 0x8048284'ü arayın 

7 dönüş 0;
8}
0x08048348: mov $ 0x0,% eax
0x0804834d: ayrılmak
0x0804834e: ret

Montajcı dökümü sonu.


GDB'nin sökücüsünü Intel sözdizimine geçirmek için set disassembly-flavor intelcommand komutunu kullanın.
Ruslan

13

GCC'ye -S (note: capital S) anahtarını kullanın, derleme kodunu .s uzantılı bir dosyaya yayar. Örneğin, aşağıdaki komut:

gcc -O2 -S -c foo.c


4

Gcc'ye bir şans vermedim, ancak g ++ durumunda. Aşağıdaki komut benim için çalışıyor. -g hata ayıklama derlemesi ve -Wa, -adhln kaynak koduyla listeleme için derleyiciye geçirilir

g ++ -g -Wa, -adhln src.cpp


Gcc için de çalışıyor! -Wa, ... birleştirici kısmı için komut satırı seçenekleri içindir (C / ++ derlemesinden sonra gcc / g ++ ile yürütme). Dahili olarak çağırır (Windows'ta as.exe). Daha fazla yardım görmek için komut satırı olarak --help olarak bakın
Hartmut Schorrig

0

stdout'a bir liste çıktısı oluşturmak için gcc veya g ++ 'da seçenek olarak -Wa, -adhln kullanın .

-Wa, ... birleştirici kısmı için komut satırı seçenekleri içindir (C / ++ derlemesinden sonra gcc / g ++ ile yürütme). Dahili olarak çağırır (Windows'ta as.exe). Görmek

> --help olarak

gcc içindeki montaj aracı için daha fazla yardım görmek için komut satırı olarak

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.