Как вы получаете выходные данные ассемблера из исходного кода C / C ++ в gcc?
Вопрос
Как это можно сделать?
Если я хочу проанализировать, как что-то компилируется, как я могу получить исходящий ассемблерный код?
Решение
Используйте -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.
Другие советы
Это сгенерирует asm-код с переплетением кода 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-файла).
Следующая командная строка взята из Блог Кристиана Гарбина
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)
Используйте переключатель -S
g++ -S main.cpp
или также с помощью gcc
gcc -S main.c
Также смотрите это
Если то, что вы хотите увидеть, зависит от связывания выходных данных, то objdump в выходном объектном файле / исполняемом файле также может быть полезен в дополнение к вышеупомянутому gcc -S.Вот очень полезный скрипт от 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.
Ну, как все говорили, используйте опцию -S.Если вы используете опцию -save-temps, вы также можете получить предварительно обработанный файл (.i), файл сборки (.s) и объектный файл (*.o).(получите каждый из них, используя -E, -S и -c .)
Как все уже отмечали, используйте -S
опция для GCC.Я также хотел бы добавить, что результаты могут отличаться (сильно!) в зависимости от того, добавляете вы параметры оптимизации или нет (-O0
ни для кого, -O2
для агрессивной оптимизации).
В частности, в архитектурах RISC компилятор часто преобразует код почти до неузнаваемости при выполнении оптимизации.Результаты впечатляют и завораживают!
Как упоминалось ранее, посмотрите на флаг -S.
Также стоит взглянуть на семейство флагов '-fdump-tree', в частности '-fdump-tree-all', которое позволяет вам увидеть некоторые промежуточные формы gcc.Они часто могут быть более удобочитаемыми, чем ассемблер (по крайней мере, для меня), и позволяют вам увидеть, как выполняются этапы оптимизации.
Используйте опцию -S:
gcc -S program.c
Если вы ищете сборку LLVM:
llvm-gcc -emit-llvm -S hello.c
Я не вижу такой возможности среди ответов, вероятно, потому, что вопрос задан в 2008 году, но в 2018 году вы можете воспользоваться онлайн-сайтом Мэтта Голдболта https://godbolt.org
Вы также можете локально клонировать git и запустить его проект https://github.com/mattgodbolt/compiler-explorer
От: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa,-a,-ad [другие параметры GCC] foo.c > foo.lst
в качестве альтернативы ответу Фирефли Или просто используйте -S, как все говорили.
Вот шаги для просмотра / печати ассемблерного кода любой программы на C в вашей Windows
консоль / терминал / командная строка :
Напишите программу на C в редакторе кода на C, таком как codeblocks, и сохраните ее с расширением .c
Скомпилируйте и запустите его.
После успешного запуска перейдите в папку, в которую вы установили свой компилятор gcc, и укажите
следующая команда для получения файла ' .s' из файла ' .c'
C:\ gcc> введите полный путь gcc -S к файлу C
Пример команды (как в моем случае)
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.
Используйте "-S" в качестве опции.Он отображает выходные данные сборки в терминале.
недавно я захотел узнать, как выполняется сборка каждой функции в программе
вот как я это сделал.
$ 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
-save-temps
Об этом упоминалось на https://stackoverflow.com/a/17083009/895245 но позвольте мне еще раз проиллюстрировать это на примере.Когда ты это сделаешь:
gcc -save-temps -c -o main.o main.c
main.с
#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
вывод объекта вместо текущего рабочего каталога, что позволяет избежать потенциальных конфликтов базовых имен.
Преимущество этого варианта перед -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.
Вот решение для C с использованием gcc :
gcc -S program.c && gcc program.c -o output
Здесь первая часть сохраняет выходные данные сборки программы в том же имени файла, что и Program, но с измененным .с расширение, вы можете открыть его как любой обычный текстовый файл.
Вторая часть здесь компилирует вашу программу для фактического использования и генерирует исполняемый файл для вашей Программы с указанным именем файла.
Тот Самый program.c программа.c выше используется название вашей программы и выходной сигнал это имя исполняемого файла, который вы хотите сгенерировать.
Кстати, это мой первый пост о StackOverflow:-}