Как это сделать?
Если я хочу проанализировать, как что-то компилируется, как я могу получить испущенный ассемблерный код?
Как это сделать?
Если я хочу проанализировать, как что-то компилируется, как я могу получить испущенный ассемблерный код?
Используйте параметр -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.
Это сгенерирует ассемблерный код с переплетенными номерами кода 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).
Следующая командная строка из блог христианского 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)
Используйте переключатель -S
g++ -S main.cpp
а также с помощью gcc
gcc -S main.c
Также см. this
Если то, что вы хотите видеть, зависит от компоновки вывода, тогда 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.
Ну, как сказали все, используйте опцию -S. Если вы используете параметр -save-temps, вы также можете получить предварительно обработанный файл (.i), файл сборки (.s) и файл объекта (*. O). (получить каждый из них с помощью -E, -S и -c.)
Как все отметили, используйте параметр -S
для GCC. Я также хотел бы добавить, что результаты могут отличаться (дико!) В зависимости от того, добавляете ли вы параметры оптимизации (-O0
для none, -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 clone и запустить его проект 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
в альтернативе PhirePhly ответ Или просто используйте -S, как сказали все.
Вот шаги, чтобы увидеть/распечатать код сборки любой программы на вашей 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.
Используйте "-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
Вот решение для C с использованием gcc:
gcc -S program.c && gcc program.c -o output
Здесь первая часть хранит вывод сборки программы с тем же именем файла, что и у Program, но с измененным расширением .s, вы можете открыть его как любой обычный текстовый файл.
Вторая часть здесь компилирует вашу программу для фактического использования и генерирует исполняемый файл для вашей Программы с указанным именем файла.
Program.c, использованный выше - это имя вашей программы, а output - это имя исполняемого файла, который вы хотите сгенерировать.
Кстати, это мой первый пост на StackOverFlow: -}
-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.