Ответы:
Используйте -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.
.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
тоже работает с лязгом
gcc -O -fverbose-asm -S
Это сгенерирует ассемблерный код с переплетенными номерами кода 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).
as
в OS X эти флаги не известны. Если это произойдет, вы, вероятно, можете сделать это одной строкой, используя -Wa
для передачи параметров as
.
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
будет короткая версия этого.
gcc -c -g -Wa,-ahl=test.s test.c
илиgcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? Он полон загрузок / хранилищ, которые затрудняют отслеживание значения, и ничего не говорит о том, насколько эффективным будет оптимизированный код.
Следующая командная строка из блога Кристиана Гарбина
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)
-O2
, используйте те опции оптимизации, которые вы используете при создании проекта, если вы хотите увидеть, как gcc оптимизирует ваш код. (Или, если вы используете LTO, как и вы, то вам нужно разобрать вывод компоновщика, чтобы увидеть, что вы на самом деле получаете.)
Если то, что вы хотите увидеть, зависит от связывания выходных данных, тогда 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)/$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.
mov eax,ds:0x804b794
, не очень NASMish. Кроме того, иногда он просто удаляет полезную информацию: movzx eax,[edx+0x1]
оставляет читателю угадать, был ли операнд памяти byte
или word
.
objconv
. Вы можете заставить его разбирать на стандартный вывод с выходным файлом = /dev/stdout
, так что вы можете перейти less
к просмотру. Также есть ndisasm
, но он разбирает только плоские двоичные файлы и не знает об объектных файлах (ELF / PE).
Как все уже отметили, используйте -S
опцию GCC. Я также хотел бы добавить, что результаты могут отличаться (дико!) В зависимости от того, добавляете ли вы опции оптимизации ( -O0
ни для одного, -O2
для агрессивной оптимизации).
В частности, на архитектурах RISC компилятор часто преобразует код практически до неузнаваемости при выполнении оптимизации. Это впечатляет и интересно смотреть на результаты!
Как упоминалось ранее, посмотрите на флаг -S.
Также стоит взглянуть на семейство флагов -fdump-tree, в частности, -fdump-tree-all, которое позволяет увидеть некоторые промежуточные формы gcc. Они часто могут быть более удобочитаемыми, чем ассемблер (по крайней мере, для меня), и позволяют увидеть, как выполняются проходы оптимизации.
Я не вижу такой возможности среди ответов, возможно, потому что вопрос с 2008 года, но в 2018 году вы можете использовать онлайн-сайт Мэтта Голдболта https://godbolt.org
Вы также можете локально git clone и запустить его проект https://github.com/mattgodbolt/compiler-explorer
-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 $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
выходные данные объекта, вместо текущего рабочего каталога, что позволяет избежать потенциальных конфликтов базовых имен.
Еще одна интересная вещь об этой опции, если вы добавите -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.
Используйте опцию -S:
gcc -S program.c
От: http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [другие опции GCC] foo.c> foo.lst
в качестве альтернативы ответу PhirePhly или просто используйте -S, как все сказали.
Вот шаги, чтобы увидеть / распечатать ассемблерный код любой программы на C в вашей Windows
консоль / терминал / командная строка:
Напишите C-программу в редакторе C-кода, например, кодовые блоки, и сохраните ее с расширением .c
Скомпилируйте и запустите его.
После успешного запуска перейдите в папку, в которую вы установили компилятор gcc, и введите
Следующая команда, чтобы получить файл .s из файла .c
C: \ gcc> gcc -S полный путь к C-файлу ENTER
Пример команды (как в моем случае)
C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c
Это выводит файл «.s» исходного файла «.c»
4 После этого введите следующую команду
C; \ gcc> cpp filename.s ENTER
Пример команды (как в моем случае)
C; \ gcc> cpp alternate_letters.s
Это напечатает / выведет весь код на ассемблере вашей C-программы.
Используйте «-S» в качестве опции. Он отображает вывод сборки в терминале.
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
. -S
сам по себе создает foo.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 использованное выше название вашей программы и вывода является имя исполняемого вы хотите создать.
Кстати, это мой первый пост на StackOverFlow: -}