Gcc içinde C / C ++ kaynağından birleştirici çıktısını nasıl alırsınız?


Yanıtlar:


421

-SGcc (veya g ++) seçeneğini kullanın .

gcc -S helloworld.c

Bu işlem ön işlemciyi (cpp) helloworld.c üzerinde çalıştıracak, ilk derlemeyi gerçekleştirecek ve sonra derleyici çalıştırılmadan duracaktır.

Varsayılan olarak bu bir dosya çıktısı verir helloworld.s. Çıktı dosyası yine de -oseçenek kullanılarak ayarlanabilir .

gcc -S -o my_asm_output.s helloworld.c

Tabii ki bu sadece orijinal kaynağınız varsa çalışır. Alternatifi, yalnızca sonuçta oluşan nesne dosyanız varsa, seçeneği objdumpayarlayarak --disassemble(veya -dkısaltılmış form için) kullanmaktır.

objdump -S --disassemble helloworld > helloworld.dump

Nesne dosyası için hata ayıklama seçeneği etkinse ( -gderleme zamanında) ve dosya çıkarılmadıysa, bu seçenek en iyi sonucu verir .

Koşu file helloworld, objdump kullanarak alacağınız ayrıntı seviyesi hakkında size bir fikir verecektir.


3
Bu doğru olsa da, Cr McDonough'un cevabının sonuçlarını daha yararlı buldum.
Rhys Ulerich

3
ek bir kullanım: objdump -M intel -S - helloworld sökmeye> helloworld.dump linux üzerinde nasm ile uyumlu intel sözdiziminde nesne dökümü almak için.
Mayıs 15'te

2
Eğer optimize / çek için tek işlevi varsa, o zaman çevrimiçi İnteraktif C ++ Derleyiciler yani bir şans verebiliriz Godbolt
fiorentinoing

1
@touchStone: GAZ .intel_syntaxolduğu değil NASM'ın ile uyumlu . Daha çok MASM'ye benzer (örneğin mov eax, symbol, mov r32, imm32adresin bulunduğu NASM'den farklı olarak bir yüktür ), ancak MASM ile tamamen uyumlu değildir. Özellikle NASM sözdiziminde yazmak isterseniz, okumak için güzel bir format olarak tavsiye ederim. objdump -drwC -Mintel | lessveya gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | lessfaydalıdır. (Ayrıca bkz. “Gürültü” GCC / clang montaj çıkışından nasıl çıkarılır? ). -masm=intelclang ile de çalışır.
Peter Cordes

3
Daha iyi kullanımgcc -O -fverbose-asm -S
Basile Starynkevitch

173

Bu, hangi satırların hangi kodu ürettiğini daha kolay görmek için C kodu + satır numaraları birbirine bağlı olarak montaj kodu oluşturur:

# create assembler code:
g++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst

Programcılar için Algoritmalar bölümünde bulunur , sayfa 3 (PDF'nin genel 15. sayfasıdır).


3
(Bu aslında sayfa (numaralı) 3'te (PDF'nin 15. sayfasıdır)
Grumdrig

1
Ne yazık ki, asOS X'te bu bayrakları bilmiyor. Eğer öyleyse, -Waseçenekleri geçmek için bunu muhtemelen tek satırlık yapabilirsiniz as.
Grumdrig

23
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lstbunun kısa el versiyonu olacaktı.
efsane2k

4
Ayrıca gcc -c -g -Wa,-ahl=test.s test.cveyagcc -c -g -Wa,-a,-ad test.c > test.txt
phuclv

1
Efsaneler ve Lu'u gibi tek komutlu sürüm de dahil olmak üzere bunu daha ayrıntılı olarak açıklayan bir blog yazısı . Ama neden -O0? Bu, bir değeri izlemeyi zorlaştıran yükler / mağazalarla doludur ve size optimize edilmiş kodun ne kadar verimli olacağı hakkında hiçbir şey söylemez.
Peter Cordes

51

Aşağıdaki komut satırı Christian Garbin'in blogundan

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

Gizli bir döküm içeren bir rutin karşı Win-XP üzerinde bir DOS penceresinden G ++ koştum

c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'

Çıktı, orijinal C ++ koduyla birlikte dağıtılan oluşturulan kod olarak birleştirilir (C ++ kodu, oluşturulan asm akışında yorum olarak gösterilir)

  16:horton_ex2_05.cpp **** using std::setw;
  17:horton_ex2_05.cpp ****
  18:horton_ex2_05.cpp **** void disp_Time_Line (void);
  19:horton_ex2_05.cpp ****
  20:horton_ex2_05.cpp **** int main(void)
  21:horton_ex2_05.cpp **** {
 164                    %ebp
 165                            subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55                    call ___main
167 0129 89E5          .stabn 68,0,21,LM2-_main
168 012b 81EC8000      LM2:
168      0000
169 0131 E8000000      LBB2:
169      00
170                    .stabn 68,0,25,LM3-_main
171                    LM3:
172                            movl $0,-16(%ebp)

@Paladin - Mutlaka değil. OP, C / C ++ kaynak kodunun derleyici çıktı eşdeğerini elde etmekle ilgiliydi, bu, derleyici ve optimize edicinin ne yaptığını anlamak için daha yararlı olduğunu kabul eden Liste'yi alır. Ancak, satır numaralarını beklemediği ve montaj yönergelerinden ayrılan baytları derlediğinden montajcının kendisinin barf olmasına neden olur.
Jesse Chisholm

-O2Gcc'nin kodunuzu nasıl optimize ettiğini görmek istiyorsanız, en azından veya projenizi oluştururken kullandığınız optimizasyon seçeneklerini kullanın. (Ya da LTO kullanıyorsanız, gerektiği gibi, o zaman gerçekten ne elde etmek için linker çıkışını sökmeniz gerekir.)
Peter Cordes

27

-S anahtarını kullanın

g++ -S main.cpp

veya ayrıca gcc ile

gcc -S main.c

Ayrıca bakınız bu


7
SSS'yi kontrol edin: "Kendi programlama sorunuzu sormak ve cevaplamak da gayet iyi". Şimdi StackOverflow başkaları için bir kaynak olarak Soru-Cevap içerir olmasıdır.
Steve Jessop

Ve belki de birileri gelip daha iyi bir cevapla sizi şaşırtacak, benimki zaman zaman biraz ayrıntılı olabilir ...
PhirePhly

Kendi soru düğmenizin yanıtı bile var.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

13

Görmek istediğiniz şey çıktının bağlantısına bağlıysa, yukarıda belirtilen gcc -S'ye ek olarak çıktı nesnesi dosyası / yürütülebilir dosyasına objdump da yararlı olabilir. Loren Merritt'in varsayılan objdump sözdizimini daha okunabilir nasm sözdizimine dönüştüren çok kullanışlı bir komut dosyası:

#!/usr/bin/perl -w
$ptr='(BYTE|WORD|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
    if(/$ptr/o) {
        s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
        s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
        s/$ptr/lc $1/oe;
    }
    if($prev =~ /\t(repz )?ret / and
       $_ =~ /\tnop |\txchg *ax,ax$/) {
       # drop this line
    } else {
       print $prev;
       $prev = $_;
    }
}
print $prev;
close FH;

Bunun gcc -S çıktısında da kullanılabileceğinden şüpheleniyorum.


2
Yine de, bu komut dosyası sözdizimini tam olarak dönüştürmeyen kirli bir hack'tir. Örneğin mov eax,ds:0x804b794çok NASMish değildir. Ayrıca, bazen sadece faydalı bilgiler şeritler: movzx eax,[edx+0x1]hafıza işlenen olup olmadığını tahmin etmek okuyucuya bırakır byteya word.
Ruslan

İlk etapta NASM sözdiziminde sökmek için Agner Sisobjconv kullanın . Çıktı dosyası = ile stdout'a ayırmayı /dev/stdoutbaşarabilirsiniz, böylece lessgörüntüleme için boru oluşturabilirsiniz . Ayrıca var ndisasm, ancak sadece düz ikili dosyaları söküyor ve nesne dosyaları (ELF / PE) hakkında bilgi sahibi değil.
Peter Cordes

9

Herkesin işaret ettiği gibi, -SGCC seçeneğini kullanın. Ayrıca sonuçlar (çılgınca!) Optimizasyon seçenekleri ekleyip eklemediğinize ( -O0hiçbiri -O2için, agresif optimizasyon için ) bağlı olarak değişebilir eklemek istiyorum .

Özellikle RISC mimarilerinde, derleyici genellikle kodu optimizasyonda tanınmanın neredeyse ötesine dönüştürecektir. Sonuçlara bakmak etkileyici ve büyüleyici!


9

Herkesin söylediği gibi, -S seçeneğini kullanın. -Save-temps seçeneğini kullanırsanız, önceden işlenmiş dosya ( .i), montaj dosyası ( .s) ve nesne dosyasını (*. O) da alabilirsiniz. (her birini -E, -S ve -c kullanarak alın.)


8

Daha önce de belirtildiği gibi, -S bayrağına bakın.

Ayrıca, gcc'nin ara formlarını görmenizi sağlayan '-fdump-tree' bayrak ailesine, özellikle '-fdump-tree-all' a bakmaya değer. Bunlar genellikle montajcıdan (en azından benim için) daha okunabilir olabilir ve optimizasyon geçişlerinin nasıl performans gösterdiğini görmenizi sağlar.


8

LLVM montajı arıyorsanız:

llvm-gcc -emit-llvm -S hello.c


8

-save-temps

Bu, https://stackoverflow.com/a/17083009/895245 adresinde belirtildi, ancak daha fazla örnek vereyim.

Bu seçeneğin en büyük avantajı -S, yapının kendisine çok fazla müdahale etmeden herhangi bir yapı komut dosyasına eklemenin çok kolay olmasıdır.

Yaptığınızda:

gcc -save-temps -c -o main.o main.c

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

ve şimdi, normal çıktının yanı sıra, main.ogeçerli çalışma dizini aşağıdaki dosyaları da içerir:

  • main.i bir bonus ve önceden aktarılmış dosyayı içerir:

    # 1 "main.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "main.c"
    
    
    int myfunc(int i) {
        return i + 1;
    }
  • main.s istenen oluşturulmuş montajı içerir:

        .file   "main.c"
        .text
        .globl  myfunc
        .type   myfunc, @function
    myfunc:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   myfunc, .-myfunc
        .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
        .section    .note.GNU-stack,"",@progbits

Çok sayıda dosya için yapmak istiyorsanız, bunun yerine kullanmayı düşünün:

 -save-temps=obj

ara dosyaları -ogeçerli çalışma dizini yerine nesne çıktısıyla aynı dizine kaydederek olası temel ad çakışmalarını önler.

Bu seçenekle ilgili bir başka harika şey de eklerseniz -v:

gcc -save-temps -c -o main.o -v main.c

aslında altında çirkin geçiciler yerine kullanılan açık dosyaları gösterir /tmp, bu yüzden önişleme / derleme / montaj adımlarını içeren tam olarak ne olduğunu bilmek kolaydır:

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s

Ubuntu 19.04 amd64, GCC 8.3.0'da test edilmiştir.




3

Bu commnadların çıktıları

Windows'unuzdaki herhangi bir C programının montaj kodunu görmek / yazdırmak için adımlar

konsol / terminal / komut istemi:

  1. Codeblocks gibi bir C kodu düzenleyicisine bir C programı yazın ve bir uzantıyla kaydedin. C

  2. Derleyin ve çalıştırın.

  3. Başarılı bir şekilde çalıştırıldıktan sonra, gcc derleyicinizi kurduğunuz klasöre gidin ve

    '.c' dosyasının '.s' dosyasını almak için aşağıdaki komut

    C: \ gcc> gcc -C dosyasının tam yolu ENTER

    Örnek bir komut (benim durumumda olduğu gibi)

    C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c

    Bu, özgün '.c' dosyasının '.s' dosyasını verir

4. Bundan sonra aşağıdaki komutu yazın

C; \ gcc> cpp dosyaadı.s ENTER

Örnek komut (benim durumumda olduğu gibi)

C; \ gcc> cpp alternate_letters.s

Bu, C programınızın tüm Meclis dil kodunu basar / çıkarır.


2

Seçenek olarak "-S" kullanın. Terminalde montaj çıkışını görüntüler.


Terminalde görüntülemek için tuşunu kullanın gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less. -Skendi başına yaratır foo.s.
Peter Cordes

2

Son zamanlarda bir programda her fonksiyonların montajını bilmek istedim
bu nasıl yaptım.

$ gcc main.c                      // main.c source file
$ gdb a.exe                       // gdb a.out in linux
  (gdb) disass main               // note here main is a function
                                  // similary it can be done for other functions

2

İşte gcc kullanan C için bir çözüm:

gcc -S program.c && gcc program.c -o output
  1. Burada ilk bölüm, programın derleme çıktısını Program ile aynı dosya adında depolar, ancak değiştirilmiş .s uzantısıyla, herhangi bir normal metin dosyası olarak açabilirsiniz.

  2. Buradaki ikinci bölüm, programınızı gerçek kullanım için derler ve Programınız için belirtilen bir dosya adıyla yürütülebilir bir dosya oluşturur.

Program.c Yukarıda kullandığınız programın adıdır ve çıkış oluşturmak istediğiniz yürütülebilir adıdır.

BTW StackOverFlow'daki ilk yazım: -}

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.