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

Внедрение ресурсов в исполняемый файл с использованием GCC

Я ищу способ легко встраивать любые внешние двоичные данные в приложение C/С++, скомпилированное GCC.

Хорошим примером того, что я хотел бы сделать, является обработка шейдерного кода - я могу просто хранить его в исходных файлах, таких как const char* shader = "source here";, но это крайне непрактично.

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

Может быть полезно для небольших приложений, которые я хотел бы распространять как один .exe файл.

Поддерживает ли GCC что-то вроде этого?

4b9b3361

Ответ 1

Есть несколько возможностей:


Обновление: здесь более полный пример использования данных, связанных с исполняемым файлом с помощью ld -r -b binary:

#include <stdio.h>

// a file named foo.bar with some example text is 'imported' into 
// an object file using the following command:
//
//      ld -r -b binary -o foo.bar.o foo.bar
//
// That creates an bject file named "foo.bar.o" with the following 
// symbols:
//
//      _binary_foo_bar_start
//      _binary_foo_bar_end
//      _binary_foo_bar_size
//
// Note that the symbols are addresses (so for example, to get the 
// size value, you have to get the address of the _binary_foo_bar_size
// symbol).
//
// In my example, foo.bar is a simple text file, and this program will
// dump the contents of that file which has been linked in by specifying
// foo.bar.o as an object file input to the linker when the progrma is built

extern char _binary_foo_bar_start[];
extern char _binary_foo_bar_end[];

int main(void)
{
    printf( "address of start: %p\n", &_binary_foo_bar_start);
    printf( "address of end: %p\n", &_binary_foo_bar_end);

    for (char* p = _binary_foo_bar_start; p != _binary_foo_bar_end; ++p) {
        putchar( *p);
    }

    return 0;
}

Обновление 2 - Получение размера ресурса: я не смог правильно прочитать _binary_foo_bar_size. Во время выполнения gdb показывает правильный размер текстового ресурса с помощью display (unsigned int)&_binary_foo_bar_size. Но присвоение этого переменной всегда давало неверное значение. Я мог бы решить эту проблему следующим образом:

unsigned int iSize =  (unsigned int)(&_binary_foo_bar_end - &_binary_foo_bar_start)

Это обходной путь, но он работает хорошо и не слишком уродлив.

Ответ 2

Как уже упоминалось, в linux вы можете использовать инструмент xxd с шестнадцатеричным дампом, который имеет функцию для генерации файла заголовка C:

xxd -i mybinary > myheader.h

Ответ 3

Для этой задачи можно использовать директиву .incbin GAS. Вот совершенно бесплатная лицензионная библиотека, которая оборачивается вокруг нее:

https://github.com/graphitemaster/incbin

Напомним. Метод incbin такой. У вас есть файл сборки thing.s, который вы компилируете с помощью gcc -c thing.s

      .section .rodata
    .global thing
    .type   thing, @object
    .align  4
thing:
    .incbin "meh.bin"
thing_end:
    .global thing_size
    .type   thing_size, @object
    .align  4
thing_size:
    .int    thing_end - thing

В вашем коде c или cpp вы можете ссылаться на него:

extern const char thing[];
extern const char* thing_end;
extern int thing_size;

Затем вы связываете полученный .o с остальными модулями компиляции. Надо отдать должное @John Ripley с его ответом здесь: C/C++ с GCC: Статически добавлять файлы ресурсов в исполняемый файл/библиотеку

Но вышесказанное не так удобно, как то, что может дать вам incbin. Чтобы выполнить вышеизложенное с помощью incbin, вам не нужно писать никакой ассемблер. Просто следующее будет делать:

#include "incbin.h"

INCBIN(thing, "meh.bin");

int main(int argc, char* argv[])
{
    // Now use thing
    printf("thing=%p\n", gThingData);
    printf("thing len=%d\n", gThingSize);   
}

Ответ 4

Вы можете сделать это в файле заголовка:

#ifndef SHADER_SRC_HPP
#define SHADER_SRC_HPP
const char* shader= "

//source

";
#endif

и просто включите это.

Другой способ - прочитать файл шейдера.