используйте gcc для прямой компиляции в машинный код без привязки - PullRequest
0 голосов
/ 12 декабря 2018

Я хочу, чтобы gcc скомпилировал для меня c-код в двоичный код Linux x86-32, но без каких-либо библиотек или около того.Я просто хочу указать адрес в начале, и он должен предполагать, что он был загружен там.Затем я вручную создам файл elf из выходных данных и все настраиваю.

Я знаю, как сделать что-то подобное с помощью NASM, но у меня есть кое-что более сложное в виду, где я не хочуиспользуйте только ассемблер.Мне не нужны никакие библиотеки, я буду использовать чистые системные вызовы со встроенным asm.Мне также все равно, если он потеряет некоторую переносимость.

Я немного попробовал, но не смог найти способ сделать это.Может ли кто-то не только предоставить мне правильные настройки для этого, но также некоторую справочную информацию о параметрах компиляции и компоновщика?Я попытался поискать в руководстве по gcc, но мне это показалось очень запутанным.

1 Ответ

0 голосов
/ 12 декабря 2018

Я хочу, чтобы gcc скомпилировал для меня c-код в двоичный код Linux x86-32, но без каких-либо библиотек или около того.

Это означает, что вы пишете Отдельно стоящий C код.(Когда стандартная библиотека доступна, у вас есть размещенная среда; когда нет, автономная одна.)

Для компиляции, например, foo.c в исполняемый файл,foo, убедитесь, что у него есть функция _start(), и используйте

gcc -march=i686 -mtune=generic -m32 -ffreestanding -nostdlib -nostartfiles foo.c -o foo

В цепочке инструментов GNU используется адрес символа _start для кодирования начального адреса исполняемого файла в файле ELF.

Этот ответ является реальным реальным примером для x86-64.Для x86-32 (или любой другой архитектуры) вам нужно настроить макросы SYSCALL_.


В комментарии OP объясняет, что им нужен двоичный двоичный объект вместо исполняемого файла ELF.

В этом случае лучше всего сказать компилятору сгенерировать независимый от позиции исполняемый файл .Например, 'blob.c':

void do_something(int arg)
{
    /* Do something with arg, perhaps a syscall,
       or inline assembly? */
}

void loop_something(int from, int to)
{
    int  arg;

    if (from <= to)
        for (arg = from; arg <= to; arg++)
            do_something(arg);
    else
        for (arg = from; arg <= to; arg--)
            do_something(arg);
}

void _start(void)
{
    loop_something(2, 5);
    do_something(6);
    loop_something(5, 2);
    do_something(1);
}    

Я рекомендую объявлять все функции, кроме _start, как static, чтобы избежать любых ссылок на глобальную таблицу смещений (GOT) или таблицы связей процедур (PLT)(например, <__x86.get_pc_thunk.bx> звонки).

Скомпилируйте это в независимый от позиции исполняемый файл, используя, например,

gcc -march=i686 -mtune=generic -m32 -O2 -fPIE -ffreestanding -nostdlib -nostartfiles blob.c -o blob

, удалите его,

strip --strip-all blob

и выгрузите содержимоеДвоичный файл:

objdump -fd blob

В этом выводе есть две важные строки:

start address 0x08048120

, который сообщает адрес символа _start, и

080480e0 <.text>:

который сообщает смещение кода в шестнадцатеричном формате.Вычтите первое из последнего (0x08048120 - 0x080480e0 = 0x40 = 64), чтобы получить смещение начального символа.

Наконец, выведите код в необработанный двоичный файл 'blob.raw', используя

objcopy -O binary -j .text blob blob.raw
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...