incbin()

From vegard.wiki
Jump to navigation Jump to search

To include binary files directly in a C++ program without using an external tool you can use this handy macro (probably only works with the GNU assembler, though):

#include <stdio.h>

struct binfile {
    char *data;
    size_t size;

    binfile(char *data, size_t size):
        data(data),
        size(size)
    {
    }
};

#define _CONCAT(x, y) x##y
#define CONCAT(x, y) _CONCAT(x, y)

#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)

#define incbin(filename) \
    ({ \
        extern char CONCAT(incbin_data, __LINE__)[]; \
        extern unsigned long CONCAT(incbin_data_size, __LINE__); \
        asm (".pushsection .rodata, \"a\" ;" \
            ".global incbin_data" STRINGIFY(__LINE__) " ;" \
            "incbin_data" STRINGIFY(__LINE__) ": ;" \
            ".incbin " STRINGIFY(filename) " ;" \
            "incbin_data_end" STRINGIFY(__LINE__) ": ;" \
            ".byte 0 ;" \
            ".global incbin_data_size" STRINGIFY(__LINE__) " ;" \
            "incbin_data_size" STRINGIFY(__LINE__) ": ;" \
            ".quad (incbin_data_end" STRINGIFY(__LINE__) " - incbin_data" STRINGIFY(__LINE__) ") ;" \
            ".popsection"); \
        binfile(CONCAT(incbin_data, __LINE__), \
            CONCAT(incbin_data_size, __LINE__)); \
    })

int main(int argc, char *argv[])
{
    auto v = incbin("/etc/passwd");
    fwrite(v.data, 1, v.size, stdout);
    return 0;
}

It should also work for C with some minor changes.

See also