/** * @file incbin.h * @author Dale Weiler * @brief Utility for including binary files * * Facilities for including binary files into the current translation unit and * making use from them externally in other translation units. */ #ifndef INCBIN_HDR #define INCBIN_HDR #include #if defined(__AVX512BW__) || \ defined(__AVX512CD__) || \ defined(__AVX512DQ__) || \ defined(__AVX512ER__) || \ defined(__AVX512PF__) || \ defined(__AVX512VL__) || \ defined(__AVX512F__) # define INCBIN_ALIGNMENT_INDEX 6 #elif defined(__AVX__) || \ defined(__AVX2__) # define INCBIN_ALIGNMENT_INDEX 5 #elif defined(__SSE__) || \ defined(__SSE2__) || \ defined(__SSE3__) || \ defined(__SSSE3__) || \ defined(__SSE4_1__) || \ defined(__SSE4_2__) || \ defined(__neon__) # define INCBIN_ALIGNMENT_INDEX 4 #elif ULONG_MAX != 0xffffffffu # define INCBIN_ALIGNMENT_INDEX 3 # else # define INCBIN_ALIGNMENT_INDEX 2 #endif /* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */ #define INCBIN_ALIGN_SHIFT_0 1 #define INCBIN_ALIGN_SHIFT_1 2 #define INCBIN_ALIGN_SHIFT_2 4 #define INCBIN_ALIGN_SHIFT_3 8 #define INCBIN_ALIGN_SHIFT_4 16 #define INCBIN_ALIGN_SHIFT_5 32 #define INCBIN_ALIGN_SHIFT_6 64 /* Actual alignment value */ #define INCBIN_ALIGNMENT \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \ INCBIN_ALIGNMENT_INDEX) /* Stringize */ #define INCBIN_STR(X) \ #X #define INCBIN_STRINGIZE(X) \ INCBIN_STR(X) /* Concatenate */ #define INCBIN_CAT(X, Y) \ X ## Y #define INCBIN_CONCATENATE(X, Y) \ INCBIN_CAT(X, Y) /* Deferred macro expansion */ #define INCBIN_EVAL(X) \ X #define INCBIN_INVOKE(N, ...) \ INCBIN_EVAL(N(__VA_ARGS__)) /* Green Hills uses a different directive for including binary data */ #if defined(__ghs__) # define INCBIN_MACRO "\tINCBIN" #else # define INCBIN_MACRO ".incbin" #endif #ifndef _MSC_VER # define INCBIN_ALIGN \ __attribute__((aligned(INCBIN_ALIGNMENT))) #else # define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT)) #endif #if defined(__arm__) || /* GNU C and RealView */ \ defined(__arm) || /* Diab */ \ defined(_ARM) /* ImageCraft */ # define INCBIN_ARM #endif #ifdef __GNUC__ /* Utilize .balign where supported */ # define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" # define INCBIN_ALIGN_BYTE ".balign 1\n" #elif defined(INCBIN_ARM) /* * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is * the shift count. This is the value passed to `.align' */ # define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n" # define INCBIN_ALIGN_BYTE ".align 0\n" #else /* We assume other inline assembler's treat `.align' as `.balign' */ # define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n" # define INCBIN_ALIGN_BYTE ".align 1\n" #endif /* INCBIN_CONST is used by incbin.c generated files */ #if defined(__cplusplus) # define INCBIN_EXTERNAL extern "C" # define INCBIN_CONST extern const #else # define INCBIN_EXTERNAL extern # define INCBIN_CONST const #endif /** * @brief Optionally override the linker section into which data is emitted. * * @warning If you use this facility, you'll have to deal with platform-specific linker output * section naming on your own * * Overriding the default linker output section, e.g for esp8266/Arduino: * @code * #define INCBIN_OUTPUT_SECTION ".irom.text" * #include "incbin.h" * INCBIN(Foo, "foo.txt"); * // Data is emitted into program memory that never gets copied to RAM * @endcode */ #if !defined(INCBIN_OUTPUT_SECTION) # if defined(__APPLE__) # define INCBIN_OUTPUT_SECTION ".const_data" # else # define INCBIN_OUTPUT_SECTION ".rodata" # endif #endif #if defined(__APPLE__) /* The directives are different for Apple branded compilers */ # define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n" # define INCBIN_GLOBAL(NAME) ".globl " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" # define INCBIN_INT ".long " # define INCBIN_MANGLE "_" # define INCBIN_BYTE ".byte " # define INCBIN_TYPE(...) #else # define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n" # define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n" # define INCBIN_INT ".int " # if defined(__USER_LABEL_PREFIX__) # define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__) # else # define INCBIN_MANGLE "" # endif # if defined(INCBIN_ARM) /* On arm assemblers, `@' is used as a line comment token */ # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n" # elif defined(__MINGW32__) || defined(__MINGW64__) /* Mingw doesn't support this directive either */ # define INCBIN_TYPE(NAME) # else /* It's safe to use `@' on other architectures */ # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n" # endif # define INCBIN_BYTE ".byte " #endif /* List of style types used for symbol names */ #define INCBIN_STYLE_CAMEL 0 #define INCBIN_STYLE_SNAKE 1 /** * @brief Specify the prefix to use for symbol names. * * By default this is `g', producing symbols of the form: * @code * #include "incbin.h" * INCBIN(Foo, "foo.txt"); * * // Now you have the following symbols: * // const unsigned char gFooData[]; * // const unsigned char *const gFooEnd; * // const unsigned int gFooSize; * @endcode * * If however you specify a prefix before including: e.g: * @code * #define INCBIN_PREFIX incbin * #include "incbin.h" * INCBIN(Foo, "foo.txt"); * * // Now you have the following symbols instead: * // const unsigned char incbinFooData[]; * // const unsigned char *const incbinFooEnd; * // const unsigned int incbinFooSize; * @endcode */ #if !defined(INCBIN_PREFIX) # define INCBIN_PREFIX g #endif /** * @brief Specify the style used for symbol names. * * Possible options are * - INCBIN_STYLE_CAMEL "CamelCase" * - INCBIN_STYLE_SNAKE "snake_case" * * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form: * @code * #include "incbin.h" * INCBIN(Foo, "foo.txt"); * * // Now you have the following symbols: * // const unsigned char FooData[]; * // const unsigned char *const FooEnd; * // const unsigned int FooSize; * @endcode * * If however you specify a style before including: e.g: * @code * #define INCBIN_STYLE INCBIN_STYLE_SNAKE * #include "incbin.h" * INCBIN(foo, "foo.txt"); * * // Now you have the following symbols: * // const unsigned char foo_data[]; * // const unsigned char *const foo_end; * // const unsigned int foo_size; * @endcode */ #if !defined(INCBIN_STYLE) # define INCBIN_STYLE INCBIN_STYLE_CAMEL #endif /* Style lookup tables */ #define INCBIN_STYLE_0_DATA Data #define INCBIN_STYLE_0_END End #define INCBIN_STYLE_0_SIZE Size #define INCBIN_STYLE_1_DATA _data #define INCBIN_STYLE_1_END _end #define INCBIN_STYLE_1_SIZE _size /* Style lookup: returning identifier */ #define INCBIN_STYLE_IDENT(TYPE) \ INCBIN_CONCATENATE( \ INCBIN_STYLE_, \ INCBIN_CONCATENATE( \ INCBIN_EVAL(INCBIN_STYLE), \ INCBIN_CONCATENATE(_, TYPE))) /* Style lookup: returning string literal */ #define INCBIN_STYLE_STRING(TYPE) \ INCBIN_STRINGIZE( \ INCBIN_STYLE_IDENT(TYPE)) \ /* Generate the global labels by indirectly invoking the macro with our style * type and concatenating the name against them. */ #define INCBIN_GLOBAL_LABELS(NAME, TYPE) \ INCBIN_INVOKE( \ INCBIN_GLOBAL, \ INCBIN_CONCATENATE( \ NAME, \ INCBIN_INVOKE( \ INCBIN_STYLE_IDENT, \ TYPE))) \ INCBIN_INVOKE( \ INCBIN_TYPE, \ INCBIN_CONCATENATE( \ NAME, \ INCBIN_INVOKE( \ INCBIN_STYLE_IDENT, \ TYPE))) /** * @brief Externally reference binary data included in another translation unit. * * Produces three external symbols that reference the binary data included in * another translation unit. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param NAME The name given for the binary data * * @code * INCBIN_EXTERN(Foo); * * // Now you have the following symbols: * // extern const unsigned char FooData[]; * // extern const unsigned char *const FooEnd; * // extern const unsigned int FooSize; * @endcode */ #define INCBIN_EXTERN(NAME) \ INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(DATA))[]; \ INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(END)); \ INCBIN_EXTERNAL const unsigned int \ INCBIN_CONCATENATE( \ INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \ INCBIN_STYLE_IDENT(SIZE)) /** * @brief Include a binary file into the current translation unit. * * Includes a binary file into the current translation unit, producing three symbols * for objects that encode the data and size respectively. * * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with * "Data", as well as "End" and "Size" after. An example is provided below. * * @param NAME The name to associate with this binary data (as an identifier.) * @param FILENAME The file to include (as a string literal.) * * @code * INCBIN(Icon, "icon.png"); * * // Now you have the following symbols: * // const unsigned char IconData[]; * // const unsigned char *const IconEnd; * // const unsigned int IconSize; * @endcode * * @warning This must be used in global scope * @warning The identifiers may be different if INCBIN_STYLE is not default * * To externally reference the data included by this in another translation unit * please @see INCBIN_EXTERN. */ #ifdef _MSC_VER #define INCBIN(NAME, FILENAME) \ INCBIN_EXTERN(NAME) #else #define INCBIN(NAME, FILENAME) \ __asm__(INCBIN_SECTION \ INCBIN_GLOBAL_LABELS(NAME, DATA) \ INCBIN_ALIGN_HOST \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \ INCBIN_MACRO " \"" FILENAME "\"\n" \ INCBIN_GLOBAL_LABELS(NAME, END) \ INCBIN_ALIGN_BYTE \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \ INCBIN_BYTE "1\n" \ INCBIN_GLOBAL_LABELS(NAME, SIZE) \ INCBIN_ALIGN_HOST \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \ INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \ INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \ ); \ INCBIN_EXTERN(NAME) #endif #endif