Есть ли способ получить GCC для вывода сырых двоичных файлов?

Есть ли набор параметров командной строки, которые убедят gcc создать плоский двоичный файл из автономного исходного файла? Например, предположим, что содержимое файла foo.c

static int f(int x)
{
  int y = x*x;
  return y+2;
}

Нет внешних ссылок, ничего для экспорта в компоновщик. Я хотел бы получить небольшой файл, содержащий только машинные инструкции для этой функции, без какого-либо другого оформления. Вроде как (DOS) .COM файл, кроме 32-битного защищенного режима.

4 ответа

Решение

Попробуйте это:

$ cc -c test.c
$ objcopy -O binary test.o binfile

Вы можете убедиться, что это правильно с objdump:

$ objdump -d test.o 
test.o:     file format pe-i386


Disassembly of section .text:

00000000 <_f>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 04                sub    $0x4,%esp
   6:   8b 45 08                mov    0x8(%ebp),%eax
   9:   0f af 45 08             imul   0x8(%ebp),%eax
   d:   89 45 fc                mov    %eax,-0x4(%ebp)
  10:   8b 45 fc                mov    -0x4(%ebp),%eax
  13:   83 c0 02                add    $0x2,%eax
  16:   c9                      leave  
  17:   c3                      ret  

И сравните с двоичным файлом:

$ hexdump -C binfile 
00000000  55 89 e5 83 ec 04 8b 45  08 0f af 45 08 89 45 fc  |U......E...E..E.|
00000010  8b 45 fc 83 c0 02 c9 c3                           |.E......|
00000018

Вы можете передать параметры компоновщику напрямую с -Wl,<linker option>

Соответствующая документация скопирована ниже из man gcc

-Wl, вариант
Опция передачи в качестве опции для компоновщика. Если опция содержит запятые, она разделяется на несколько опций через запятую. Вы можете использовать этот синтаксис для передачи аргумента опции. Например, -Wl,-Map,output.map передает -Map output.map компоновщику. При использовании компоновщика GNU, вы также можете получить тот же эффект с -Wl,-Map=output.map.

Так что при компиляции с GCC, если вы передаете -Wl,--oformat=binary вы создадите двоичный файл вместо формата elf. куда --oformat=binary говорит ld сгенерировать двоичный файл.

Это устраняет необходимость objcopy по отдельности.

Обратите внимание, что --oformat=binary может быть выражено как OUTPUT_FORMAT("binary") из скрипта компоновщика. Если вы хотите иметь дело с плоскими двоичными файлами, есть большая вероятность, что вы выиграете от высокого уровня контроля, который обеспечивают сценарии компоновщика.

Ты можешь использовать objcopy вытащить текстовый сегмент из файла.o или файла a.out.

$ cat q.c
f() {}
$ cc -S -O q.c
$ cat q.s
        .file   "q.c"
        .text
.globl f
        .type   f, @function
f:
        pushl   %ebp
        movl    %esp, %ebp
        popl    %ebp
        ret
        .size   f, .-f
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits
$ cc -c -O q.c
$ objcopy -O binary q.o q.bin
$ od -X q.bin
0000000 5de58955 000000c3
0000005
$ objdump -d q.o
q.o:     file format elf32-i386
Disassembly of section .text:
00000000 <f>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   5d                      pop    %ebp
   4:   c3                      ret    

Другие ответы, безусловно, путь. Однако я должен был указать дополнительные аргументы командной строки для objcopy, чтобы мой вывод был таким, как ожидалось. Обратите внимание, что я разрабатываю 32-битный код на 64-битной машине, поэтому -m32 аргумент. Кроме того, мне больше нравится синтаксис Intel, поэтому вы увидите это и в аргументах.

$ cat test.c
int main() { return 0; }
$ gcc -nostdinc -m32 -masm=intel -Wall -c test.c -o test.o
$ objdump --disassemble --disassembler-options intel test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   b8 00 00 00 00          mov    eax,0x0
   8:   5d                      pop    ebp
   9:   c3                      ret    

Хорошо, здесь я должен был указать, что мне нужен только раздел.text:

$ objcopy --only-section=.text --output-target binary test.o test.bin
$ hexdump -C test.bin
00000000  55 89 e5 b8 00 00 00 00  5d c3   |U.......].|
0000000a

Мне потребовалось около 2 часов, чтобы прочитать и попробовать разные варианты, прежде чем я понял это. Надеюсь, это спасет кого-то еще в этот раз.

Другие вопросы по тегам