Відповіді:
Використовуйте -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, як слід, тоді вам доведеться розібрати вихід лінкера, щоб побачити, що ви дійсно отримаєте.)
Використовуйте перемикач -S
g++ -S main.cpp
або також з gcc
gcc -S main.c
Переконайтесь також у цьому
Якщо те, що ви хочете побачити, залежить від зв'язування виводу, тоді також допоміжний вивідний об'єктний файл / виконуваний файл може бути корисним на додаток до вищезгаданого 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
. Ви можете змусити його розбирати stdout з вихідним файлом = /dev/stdout
, так що ви можете передати на less
перегляд. Є також ndisasm
, але він розбирає лише плоскі двійкові файли і не знає про файли об'єктів (ELF / PE).
Як усі зазначали, використовуйте -S
варіант для GCC. Я також хотів би додати, що результати можуть відрізнятися (дико!) Залежно від того, додаєте ви чи ні варіанти оптимізації ( -O0
для жодної, -O2
для агресивної оптимізації).
Зокрема, для архітектур RISC компілятор часто трансформує код майже невпізнанним шляхом оптимізації. Вражаюче та захоплююче дивитись на результати!
Як згадувалося раніше, подивіться на прапор -S.
Варто також переглянути сімейство прапорів "-fdump-tree", зокрема "-fdump-tree-all", що дозволяє побачити деякі проміжні форми gcc. Вони часто можуть бути більш читабельними, ніж асемблер (принаймні для мене), і ви зможете побачити, як виконуються передачі для оптимізації.
Я не бачу такої можливості серед відповідей, ймовірно, тому, що це питання з 2008 року, але в 2018 році ви можете використовувати Інтернет-сайт Метта Голдбольта https://godbolt.org
Ви також можете локально git клонувати та запускати його проект 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
Складіть і запустіть його.
Після успішного запуску перейдіть до папки, де ви встановили компілятор gcc, і дайте
наступна команда для отримання файлу ".s" файлу ".c"
C: \ gcc> gcc -S повний шлях до файлу C ВВЕДЕННЯ
Приклад команди (як у моєму випадку)
C: \ gcc> gcc -SD: \ Aa_C_Certified \ alternate_letters.c
Це виводить '.s' файл вихідного файлу '.c'
4. Після цього введіть таку команду
C; \ gcc> cpp filename.s ВВОД
Приклад команди (як у моєму випадку)
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: -}