Использование GCC для создания читаемой сборки?

210

Мне было интересно, как использовать GCC в моем исходном файле C, чтобы сбрасывать мнемоническую версию машинного кода, чтобы я мог видеть, что мой код был скомпилирован. Вы можете сделать это с помощью Java, но мне не удалось найти способ с GCC.

Я пытаюсь перезаписать метод C в сборке и посмотреть, как GCC это будет большой помощью.

  • 24
    обратите внимание, что «байт-код» обычно означает код, потребляемый виртуальной машиной, такой как JVM или CLR .NET. Выходные данные GCC лучше называть «машинный код», «машинный язык» или «язык ассемблера»
  • 2
    Я добавил ответ, используя godbolt, так как это очень мощный инструмент для быстрого эксперимента с тем, как различные опции влияют на генерацию кода.
Показать ещё 4 комментария
Теги:
gcc
assembly

9 ответов

308
Лучший ответ

Если вы компилируете символы отладки, вы можете использовать objdump для создания более читаемой разборки.

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel хорош:

  • -r показывает имена символов на переездах (так что вы хотите видеть puts в call инструкции ниже)
  • -r показывает динамические связи/имена символов (полезно для разделяемых библиотек)
  • -C отображает имена символов C++
  • -w является "широким" режимом: он не строит -w рэп -C ode bytes
  • -Mintel: используйте GAS/binutils MASM-like .intel_syntax noprefix синтаксис .intel_syntax noprefix вместо AT & T
  • -S: чередовать строки источника с разборкой.

Вы можете поставить что-то вроде alias disas="objdump -drwCS -Mintel" в ~/.bashrc


Пример:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret
  • 2
    Есть ли переключатель, чтобы захватить только инструкции Intel?
  • 2
    Все это инструкции Intel, поскольку они работают на процессорах Intel: D.
Показать ещё 4 комментария
95

Я хотел бы добавить к этим ответам, что если вы дадите gcc флаг -fverbose-asm, ассемблер, который он испускает, будет намного понятнее читать.

69

Используйте ключ -S (note: capital S) для GCC, и он выдает код сборки в файл с расширением .s. Например, следующая команда:

gcc -O2 -S foo.c

оставит сгенерированный код сборки в файле foo.s.

Сброс прямо из http://www.delorie.com/djgpp/v2faq/faq8_20.html (но удаление ошибочного -c)

  • 34
    Вы не должны смешивать -c и -S, используйте только один из них. В этом случае один переопределяет другой, возможно, в зависимости от порядка их использования.
  • 3
    @AdamRosenfield Любое упоминание о «не следует смешивать -c и -S»? Если это правда, мы можем напомнить автору и отредактировать его.
Показать ещё 2 комментария
49

Использование переключателя -S для GCC на системах на базе x86 дает по умолчанию дамп синтаксиса AT & T, который может быть указан с помощью -masm=att, например:

gcc -S -masm=att code.c

Если вы хотите создать дамп в синтаксисе Intel, вы можете использовать переключатель -masm=intel, например:

gcc -S -masm=intel code.c

(Оба производят дампы code.c в их различный синтаксис, в файл code.s соответственно)

Для создания подобных эффектов с помощью objdump, вы хотите использовать --disassembler-options= intel/att, пример (с --disassembler-options= кода для иллюстрации различий в синтаксисе):

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

а также

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ce:   55                      push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop
  • 10
    Вот Это Да! Я не могу дождаться, чтобы попробовать это дома. Я терпеть не могу читать синтаксис AT & T. :-)
  • 0
    Что ... gcc -S -masm=intel test.c точно не сработало для меня, я получил несколько скрещенных синтаксисов Intel и AT & T, например: mov %rax, QWORD PTR -24[%rbp] вместо this: movq -24(%rbp), %rax .
Показать ещё 2 комментария
33

godbolt - очень полезный инструмент, в списке есть только компиляторы С++, но вы можете использовать флаг -x c для его получения обработайте код как C. Затем он сгенерирует список сборок для вашего кода бок о бок, и вы можете использовать параметр Colourise для создания цветных полосок, чтобы визуально указать, какой исходный код сопоставляется сгенерированной сборкой. Например, следующий код:

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

используя следующую командную строку:

-x c -std=c99 -O3

и Colourise генерируют следующее:

Изображение 4805

  • 0
    Было бы неплохо узнать, как работают фильтры Godbolt: .LC0, .text, // и Intel. Интел это просто -masm=intel а как насчет остальных?
  • 0
    Я думаю, это объясняется здесь stackoverflow.com/a/38552509/2542702
Показать ещё 1 комментарий
21

Вы пробовали gcc -S -fverbose-asm -O source.c затем source.s сгенерированный source.s ассемблера source.s?

Сгенерированный ассемблерный код переходит в source.s (вы можете переопределить его с помощью -O имя ассемблера); -fverbose-asm просит компилятор -fverbose-asm некоторые комментарии ассемблера, "объясняя" сгенерированный код ассемблера. Опция -O просит компилятор немного оптимизировать (он может оптимизировать больше с -O2 или -O3).

Если вы хотите понять, что делает gcc, попробуйте передать -fdump-tree-all но будьте осторожны: вы получите сотни файлов дампа.

Кстати, GCC можно расширять с помощью плагинов или с помощью MELT (высокоуровневый домен-специфический язык для расширения GCC; от которого я отказался в 2017 году)

  • 0
    возможно source.s , что вывод будет в source.s , так как многие люди ожидают распечатки на консоли.
  • 1
    @ecerulm: -S -o- выдает дамп на стандартный вывод. -masm=intel полезен, если вы хотите использовать синтаксис NASM / YASM. (но он использует qword ptr [mem] , а не просто qword , поэтому он больше похож на Intel / MASM, чем NASM / YASM). gcc.godbolt.org отлично справляется с уборкой дампа: опционально убирает строки только для комментариев, неиспользуемые метки и директивы ассемблера.
Показать ещё 1 комментарий
18

Вы можете использовать gdb для этого, как objdump.

Эта выдержка взята из http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64


Ниже приведен пример сборки смешанного источника + для Intel x86:

  (gdb) disas /m main
Dump of assembler code for function main:
5       {
0x08048330 :    push   %ebp
0x08048331 :    mov    %esp,%ebp
0x08048333 :    sub    $0x8,%esp
0x08048336 :    and    $0xfffffff0,%esp
0x08048339 :    sub    $0x10,%esp

6         printf ("Hello.\n");
0x0804833c :   movl   $0x8048440,(%esp)
0x08048343 :   call   0x8048284 

7         return 0;
8       }
0x08048348 :   mov    $0x0,%eax
0x0804834d :   leave
0x0804834e :   ret

End of assembler dump.
  • 1
    архивная ссылка: web.archive.org/web/20090412112833/http://sourceware.org:80/gdb/…
  • 0
    А чтобы переключить дизассемблер GDB на синтаксис Intel, используйте команду set disassembly-flavor intel .
13

Используйте ключ -S (note: capital S) для GCC, и он выдает код сборки в файл с расширением .s. Например, следующая команда:

gcc -O2 -S -c foo.c

4

Я не дал выстрел в gcc, но в случае g++. Следующая приведенная ниже команда работает для меня. -g для сборки отладки и -Wa, -adhln передается ассемблеру для распечатки с исходным кодом

g++ -g -Wa, -adhln src.cpp

Ещё вопросы

Сообщество Overcoder
Наверх
Меню