Подтвердить что ты не робот

Как заставить gcc генерировать только машинный код, который может быть загружен непосредственно в память и выполнен?

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

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

4b9b3361

Ответ 1

Вы можете сделать это, но вам нужно будет пройти через формат объектного файла. В частности, команда objcopy может преобразовать исполняемый файл в "плоский" двоичный файл (в зависимости от вашей целевой платформы). Возможно, что-то вроде этого:

gcc -o test test.c
objcopy -O binary test test.bin

Подробнее см. man objcopy на вашей платформе.

Ответ 2

Вы хотите узнать об утилите objcopy, которая обычно доступна вместе с GCC. Он является компонентом пакета инструментов binutils, наиболее заметным из которых является компоновщик, ld.

Процесс состоит в том, что вы компилируете исходный файл и связываете их, как обычно. Это дает вам готовый исполняемый файл в эльфе (или другом перемещаемом бинарном формате, зависящем от платформы). Затем вы используете objcopy для преобразования исполняемого файла в плоское двоичное изображение.

Это наиболее полезно для подготовки кода, который должен быть запущен из ПЗУ, где вы хотите убедиться, что используете подходящую библиотеку времени выполнения C для целевой платформы и, вероятно, необходимо настроить файл компоновщика script, а также предоставить свой собственный код запуска C.

Если ваша цель - получить что-то вроде файла .so для загрузки в существующий процесс, тогда имейте в виду, что часть работы загрузчика разделяемой библиотеки заключается в том, чтобы фактически завершить привязку, чтобы символы в файл .so, который ссылается на адреса в основном исполняемом файле (или других .so файлах), разрешается во время загрузки. Использование objcopy этого не сделает, и поэтому для функций, загруженных таким образом, может быть сложно правильно использовать существующую библиотеку времени выполнения C и объекты, которые она поддерживает, например, открытые файлы.

Независимо от ваших целей, вам нужно будет захватить контроль над компоновщиком, чтобы найти ваш двоичный файл по известному адресу. Для этого вам понадобится создать компоновщик script. Документация для языка script находится в руководстве binutils. Вас будут интересовать разделы ".text *" и, возможно, в разделах ".rodata *", если вы планируете инициализировать глобальные переменные. Фактически организация этой инициализации остается в качестве упражнения для читателя.

В целом, это всего лишь верхушка очень большого айсберга. Я бы предложил потратить некоторое время на сборку кросс-компилятора, чтобы увидеть, как эти вещи используются на практике. Сообщества AVR и MSP430 используют GCC, имеют активное участие и недорогое (и часто даже с открытым исходным кодом) оборудование, чтобы начать работу.