Как получить вывод ассемблера из источника C/С++ в gcc?

Как это сделать?

Если я хочу проанализировать, как что-то компилируется, как я могу получить испущенный ассемблерный код?

Ответ 1

Используйте параметр -S для gcc (или g++).

gcc -S helloworld.c

Это запустит препроцессор (cpp) поверх helloworld.c, выполнит начальную компиляцию, а затем остановится до запуска ассемблера.

По умолчанию будет выведен файл helloworld.s. Выходной файл все еще можно установить с помощью параметра -o.

gcc -S -o my_asm_output.s helloworld.c

Конечно, это работает только в том случае, если у вас есть исходный источник. Альтернативой, если у вас есть только результирующий объектный файл, является использование objdump, установив опцию --disassemble (или -d для сокращенной формы).

objdump -S --disassemble helloworld > helloworld.dump

Эта опция работает лучше всего, если опция отладки включена для объектного файла (-g во время компиляции), и файл не был удален.

Запуск file helloworld даст вам некоторые указания относительно уровня детализации, который вы получите с помощью objdump.

Ответ 2

Это сгенерирует ассемблерный код с переплетенными номерами кода C +, чтобы легче было видеть, какие строки генерируют какой код.

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

Находится в разделе " Алгоритмы для программистов", стр. 3 (общая 15-я страница PDF).

Ответ 3

Следующая командная строка из блог христианского Garbin

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

Я запускал g++ из окна DOS в Win-XP, против подпрограммы, содержащей неявный листинг

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'

Вывод обработан сгенерированным кодом, переработанным исходным кодом С++ (код С++ отображается как комментарии в сгенерированном потоке asm)

  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)

Ответ 4

Используйте переключатель -S

g++ -S main.cpp

а также с помощью gcc

gcc -S main.c

Также см. this

Ответ 5

Если то, что вы хотите видеть, зависит от компоновки вывода, тогда objdump для файла/исполняемого файла вывода также может быть полезен в дополнение к вышеупомянутому gcc -S. Здесь очень полезный script Loren Merritt, который преобразует синтаксис objdump по умолчанию в более читаемый синтаксис nasm:

#!/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;

Я подозреваю, что это также можно использовать на выходе gcc -S.

Ответ 6

Ну, как сказали все, используйте опцию -S. Если вы используете параметр -save-temps, вы также можете получить предварительно обработанный файл (.i), файл сборки (.s) и файл объекта (*. O). (получить каждый из них с помощью -E, -S и -c.)

Ответ 7

Как все отметили, используйте параметр -S для GCC. Я также хотел бы добавить, что результаты могут отличаться (дико!) В зависимости от того, добавляете ли вы параметры оптимизации (-O0 для none, -O2 для агрессивной оптимизации).

В архитектуре RISC, в частности, компилятор часто преобразует код, который почти не поддается распознаванию при оптимизации. Это впечатляет и увлекательно смотреть на результаты!

Ответ 8

Как уже упоминалось ранее, посмотрите на флаг -S.

Также стоит посмотреть на семейство флагов '-fdump-tree', в частности '-fdump-tree-all', что позволяет увидеть некоторые из промежуточных форм gcc. Они часто могут быть более читабельными, чем ассемблер (по крайней мере, для меня), и позволяют увидеть, как выполняется прогон оптимизации.

Ответ 9

Используйте параметр -S:

gcc -S program.c

Ответ 10

Если вы ищете сборку LLVM:

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

Ответ 11

Я не вижу такой возможности среди ответов, возможно, потому что вопрос с 2008 года, но в 2018 году вы можете использовать онлайн-сайт Мэтта Голдболта https://godbolt.org

Вы также можете локально git clone и запустить его проект https://github.com/mattgodbolt/compiler-explorer

Ответ 12

От: http://www.delorie.com/djgpp/v2faq/faq8_20.html

gcc -c -g -Wa, -a, -ad [другие параметры GCC] foo.c > foo.lst

в альтернативе PhirePhly ответ Или просто используйте -S, как сказали все.

Ответ 13

Вывод этих commnads

Вот шаги, чтобы увидеть/распечатать код сборки любой программы на вашей Windows

консоль/терминал/командная строка:

  • Напишите программу C в редакторе кода C, например, кодовые блоки и сохраните его с расширением .c

  • Скомпилируйте и запустите его.

  • После успешного запуска перейдите в папку, в которой вы установили свой компилятор gcc, и дайте

    следующая команда, чтобы получить файл .s 'файла .c'

    C:\gcc > gcc -S полный путь к файлу C ENTER

    Пример команды (как в моем случае)

    C:\gcc > gcc -S D:\Aa_C_Certified\alternate_letters.c

    Это выводит файл .s 'исходного файла .c'

4. После этого введите следующую команду

C;\gcc > cpp имя_файла .s ВВОД

Пример команды (как в моем случае)

C;\gcc > cpp alternate_letters.s

Это будет печатать/выводить весь код языка сборки вашей программы C.

Ответ 14

Используйте "-S" в качестве опции. Он отображает вывод сборки в терминале.

Ответ 15

недавно я хотел знать сборку каждой функции в программе
Вот как я это сделал.

$ 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

Ответ 16

Вот решение для C с использованием gcc:

gcc -S program.c && gcc program.c -o output
  1. Здесь первая часть хранит вывод сборки программы с тем же именем файла, что и у Program, но с измененным расширением .s, вы можете открыть его как любой обычный текстовый файл.

  2. Вторая часть здесь компилирует вашу программу для фактического использования и генерирует исполняемый файл для вашей Программы с указанным именем файла.

Program.c, использованный выше - это имя вашей программы, а output - это имя исполняемого файла, который вы хотите сгенерировать.

Кстати, это мой первый пост на StackOverFlow: -}

Ответ 17

-Save-temps

Это было упомянуто на fooobar.com/info/7661/... но позвольте мне далее проиллюстрировать это. Когда вы делаете:

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

main.c

#define INC 1

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

и теперь, кроме обычного вывода main.o, текущий рабочий каталог также содержит следующие файлы:

  • main.i является бонусом и содержит желаемый предустановленный файл:

    # 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 содержит желаемую сгенерированную сборку:

        .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
    

Если вы хотите сделать это для большого количества файлов, попробуйте вместо этого:

 -save-temps=obj

который сохраняет промежуточные файлы в том же каталоге, что и -o объекта -o вместо текущего рабочего каталога, что позволяет избежать потенциальных конфликтов -o.

Преимущество этой опции перед -S том, что ее легко добавить в любой скрипт сборки, не сильно влияя на саму сборку.

Еще одна интересная вещь об этой опции, если вы добавите -v:

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

на самом деле он показывает явные файлы, используемые вместо некрасивых временных файлов в /tmp, поэтому легко точно знать, что происходит, включая этапы предварительной обработки/компиляции/сборки:

/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.