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

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

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

Советы по сделать вывод asm удобочитаемым см. Также: Как убрать «шум» из вывода сборки GCC / clang?

Peter Cordes 26.07.2016 07:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
415
1
376 832
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

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

g++ -S main.cpp

или также с gcc

gcc -S main.c

Также см. это

Ознакомьтесь с FAQ: «Также совершенно нормально задать свой собственный вопрос по программированию и ответить на него». Дело в том, что теперь StackOverflow содержит вопросы и ответы в качестве ресурса для других.

Steve Jessop 26.09.2008 04:50

И, может быть, кто-то другой придет и удивит вас лучшим ответом, хотя мой иногда может быть немного многословным ...

PhirePhly 26.09.2008 07:01

Есть даже кнопка ответа на свой вопрос.

Ciro Santilli TRUMP BAN IS BAD 25.08.2013 00:05

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

gcc -S program.c

Если то, что вы хотите увидеть, зависит от связывания вывода, то objdump в файле / исполняемом файле выходного объекта также может быть полезен в дополнение к вышеупомянутому gcc -S. Вот очень полезный сценарий Лорен Мерритт, который преобразует синтаксис 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)//o or
        s/($reg,)$ptr(\[[^\[\]]+\])//o or
        s/$ptr/lc /oe;
    }
    if ($prev =~ /\t(repz )?ret / and
       $_ =~ /\tnop |\txchg *ax,ax$/) {
       # drop this line
    } else {
       print $prev;
       $prev = $_;
    }
}
print $prev;
close FH;

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

Тем не менее, этот сценарий представляет собой грязный прием, который не полностью преобразует синтаксис. Например. mov eax,ds:0x804b794 не очень NASMish. Кроме того, иногда он просто удаляет полезную информацию: movzx eax,[edx+0x1] дает читателю возможность догадаться, был ли операнд памяти byte или word.

Ruslan 08.10.2017 01:00

Для дизассемблирования в синтаксисе NASM в первую очередь используйте objconv Агнера Фога. Вы можете заставить его дизассемблировать в стандартный вывод с помощью output file = /dev/stdout, чтобы вы могли перенаправить его в less для просмотра. Также есть ndisasm, но он разбирает только плоские двоичные файлы и не знает об объектных файлах (ELF / PE).

Peter Cordes 08.10.2017 01:12
Ответ принят как подходящий

Используйте параметр -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.

Хотя это правильно, я нашел результаты ответа Cr McDonough более полезными.

Rhys Ulerich 03.11.2013 06:13

дополнительное использование: objdump -M intel -S --disassemble helloworld> helloworld.dump, чтобы получить дамп объекта в синтаксисе Intel, совместимом с nasm в Linux.

touchStone 11.03.2015 14:58

Если у вас есть одна функция для оптимизации / проверки, вы можете попробовать интерактивные интерактивные компиляторы C++, то есть Godbolt

fiorentinoing 11.11.2015 11:06

@touchStone: GAS .intel_syntaxнет совместим с NASM. Это больше похоже на MASM (например, mov eax, symbol - это нагрузка, в отличие от NASM, где это mov r32, imm32 адреса), но также не полностью совместим с MASM. Я настоятельно рекомендую его как удобный для чтения формат, особенно если вы любите писать в синтаксисе NASM. objdump -drwC -Mintel | less или gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less полезны. (См. Также Как убрать «шум» из вывода сборки GCC / clang?). -masm=intel тоже работает с лязгом.

Peter Cordes 02.09.2017 22:27

Лучше используйте gcc -O -fverbose-asm -S

Basile Starynkevitch 21.09.2017 12:02

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

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

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

# 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

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

(На самом деле это страница (пронумерованная) 3 (это 15-я страница PDF-файла))

Grumdrig 05.04.2013 08:51

К сожалению, as в OS X не знает этих флагов. Однако если бы это было так, вы, вероятно, могли бы однострочно использовать -Wa для передачи параметров в as.

Grumdrig 05.04.2013 08:57

g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst будет сокращенной версией этого.

legends2k 06.05.2013 17:49

Вы также можете использовать gcc -c -g -Wa,-ahl=test.s test.c или gcc -c -g -Wa,-a,-ad test.c > test.txt.

phuclv 07.06.2014 18:28

Сообщение блога, объясняющий это более подробно, включая версию с одной командой, такую ​​как легенды и опубликованные Lu'u. Но почему -O0? Он полон загрузок / хранилищ, которые затрудняют отслеживание значения и ничего не говорят вам о том, насколько эффективным будет оптимизированный код.

Peter Cordes 25.07.2016 03:23

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

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

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

Для отображения в терминале используйте gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less. -S сам по себе создает foo.s.

Peter Cordes 24.01.2018 20:56

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

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

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

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

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

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

Следующая командная строка взята из Блог Кристиана Гарбина

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'

Выходные данные представляют собой ассемблированный сгенерированный код, смешанный с исходным кодом C++ (код C++ отображается в виде комментариев в сгенерированном потоке 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)

@Paladin - Не обязательно. OP был о получении выходного эквивалента ассемблера исходного кода C / C++, он получает листинг, который, я согласен, более полезен для понимания того, что делают компилятор и оптимизатор. Но это приведет к тому, что сам ассемблер отключится, поскольку он не ожидает номеров строк и скомпилирует байты, оставшиеся от инструкций сборки.

Jesse Chisholm 12.08.2015 00:14

Используйте по крайней мере -O2 или любые другие параметры оптимизации, которые вы действительно используете при создании проекта, если вы хотите увидеть, как gcc оптимизирует ваш код. (Или, если вы используете LTO, как и следовало бы, тогда вам придется дизассемблировать вывод компоновщика, чтобы увидеть, что вы действительно получите.)

Peter Cordes 08.10.2017 01:16

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

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

Output of these commnads

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

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

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

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

  3. После успешного запуска перейдите в папку, в которую вы установили компилятор 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 filename.s ENTER

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

C; \ gcc> cpp alternate_letters.s

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

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

$ 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

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

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

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

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

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

-save-temps

Об этом упоминалось в https://stackoverflow.com/a/17083009/895245, но позвольте мне еще раз проиллюстрировать это.

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

Когда вы это сделаете:

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    , %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, вместо текущего рабочего каталога, что позволяет избежать потенциальных конфликтов базовых имен.

Еще одна интересная особенность этой опции - добавить -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.

Предварительно определенные цели CMake

CMake автоматически предоставляет цели для предварительно обработанного файла:

make help

показывает нам, что мы можем:

make main.s

и эта цель запускается:

Compiling C source to assembly CMakeFiles/main.dir/main.c.s
/usr/bin/cc    -S /home/ciro/hello/main.c -o CMakeFiles/main.dir/main.c.s

так что файл можно увидеть на CMakeFiles/main.dir/main.c.s

Проверено на cmake 3.16.1.

Другие вопросы по теме