incbin.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /**
  2. * @file incbin.h
  3. * @author Dale Weiler
  4. * @brief Utility for including binary files
  5. *
  6. * Facilities for including binary files into the current translation unit and
  7. * making use from them externally in other translation units.
  8. */
  9. #ifndef INCBIN_HDR
  10. #define INCBIN_HDR
  11. #include <limits.h>
  12. #if defined(__AVX512BW__) || \
  13. defined(__AVX512CD__) || \
  14. defined(__AVX512DQ__) || \
  15. defined(__AVX512ER__) || \
  16. defined(__AVX512PF__) || \
  17. defined(__AVX512VL__) || \
  18. defined(__AVX512F__)
  19. # define INCBIN_ALIGNMENT_INDEX 6
  20. #elif defined(__AVX__) || \
  21. defined(__AVX2__)
  22. # define INCBIN_ALIGNMENT_INDEX 5
  23. #elif defined(__SSE__) || \
  24. defined(__SSE2__) || \
  25. defined(__SSE3__) || \
  26. defined(__SSSE3__) || \
  27. defined(__SSE4_1__) || \
  28. defined(__SSE4_2__) || \
  29. defined(__neon__)
  30. # define INCBIN_ALIGNMENT_INDEX 4
  31. #elif ULONG_MAX != 0xffffffffu
  32. # define INCBIN_ALIGNMENT_INDEX 3
  33. # else
  34. # define INCBIN_ALIGNMENT_INDEX 2
  35. #endif
  36. /* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */
  37. #define INCBIN_ALIGN_SHIFT_0 1
  38. #define INCBIN_ALIGN_SHIFT_1 2
  39. #define INCBIN_ALIGN_SHIFT_2 4
  40. #define INCBIN_ALIGN_SHIFT_3 8
  41. #define INCBIN_ALIGN_SHIFT_4 16
  42. #define INCBIN_ALIGN_SHIFT_5 32
  43. #define INCBIN_ALIGN_SHIFT_6 64
  44. /* Actual alignment value */
  45. #define INCBIN_ALIGNMENT \
  46. INCBIN_CONCATENATE( \
  47. INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \
  48. INCBIN_ALIGNMENT_INDEX)
  49. /* Stringize */
  50. #define INCBIN_STR(X) \
  51. #X
  52. #define INCBIN_STRINGIZE(X) \
  53. INCBIN_STR(X)
  54. /* Concatenate */
  55. #define INCBIN_CAT(X, Y) \
  56. X ## Y
  57. #define INCBIN_CONCATENATE(X, Y) \
  58. INCBIN_CAT(X, Y)
  59. /* Deferred macro expansion */
  60. #define INCBIN_EVAL(X) \
  61. X
  62. #define INCBIN_INVOKE(N, ...) \
  63. INCBIN_EVAL(N(__VA_ARGS__))
  64. /* Green Hills uses a different directive for including binary data */
  65. #if defined(__ghs__)
  66. # if (__ghs_asm == 2)
  67. # define INCBIN_MACRO ".file"
  68. /* Or consider the ".myrawdata" entry in the ld file */
  69. # else
  70. # define INCBIN_MACRO "\tINCBIN"
  71. # endif
  72. #else
  73. # define INCBIN_MACRO ".incbin"
  74. #endif
  75. #ifndef _MSC_VER
  76. # define INCBIN_ALIGN \
  77. __attribute__((aligned(INCBIN_ALIGNMENT)))
  78. #else
  79. # define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))
  80. #endif
  81. #if defined(__arm__) || /* GNU C and RealView */ \
  82. defined(__arm) || /* Diab */ \
  83. defined(_ARM) /* ImageCraft */
  84. # define INCBIN_ARM
  85. #endif
  86. #ifdef __GNUC__
  87. /* Utilize .balign where supported */
  88. # define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
  89. # define INCBIN_ALIGN_BYTE ".balign 1\n"
  90. #elif defined(INCBIN_ARM)
  91. /*
  92. * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is
  93. * the shift count. This is the value passed to `.align'
  94. */
  95. # define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n"
  96. # define INCBIN_ALIGN_BYTE ".align 0\n"
  97. #else
  98. /* We assume other inline assembler's treat `.align' as `.balign' */
  99. # define INCBIN_ALIGN_HOST ".align " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
  100. # define INCBIN_ALIGN_BYTE ".align 1\n"
  101. #endif
  102. /* INCBIN_CONST is used by incbin.c generated files */
  103. #if defined(__cplusplus)
  104. # define INCBIN_EXTERNAL extern "C"
  105. # define INCBIN_CONST extern const
  106. #else
  107. # define INCBIN_EXTERNAL extern
  108. # define INCBIN_CONST const
  109. #endif
  110. /**
  111. * @brief Optionally override the linker section into which data is emitted.
  112. *
  113. * @warning If you use this facility, you'll have to deal with platform-specific linker output
  114. * section naming on your own
  115. *
  116. * Overriding the default linker output section, e.g for esp8266/Arduino:
  117. * @code
  118. * #define INCBIN_OUTPUT_SECTION ".irom.text"
  119. * #include "incbin.h"
  120. * INCBIN(Foo, "foo.txt");
  121. * // Data is emitted into program memory that never gets copied to RAM
  122. * @endcode
  123. */
  124. #if !defined(INCBIN_OUTPUT_SECTION)
  125. # if defined(__APPLE__)
  126. # define INCBIN_OUTPUT_SECTION ".const_data"
  127. # else
  128. # define INCBIN_OUTPUT_SECTION ".rodata"
  129. # endif
  130. #endif
  131. #if defined(__APPLE__)
  132. /* The directives are different for Apple branded compilers */
  133. # define INCBIN_SECTION INCBIN_OUTPUT_SECTION "\n"
  134. # define INCBIN_GLOBAL(NAME) ".globl " INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
  135. # define INCBIN_INT ".long "
  136. # define INCBIN_MANGLE "_"
  137. # define INCBIN_BYTE ".byte "
  138. # define INCBIN_TYPE(...)
  139. #else
  140. # define INCBIN_SECTION ".section " INCBIN_OUTPUT_SECTION "\n"
  141. # define INCBIN_GLOBAL(NAME) ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
  142. # if defined(__ghs__)
  143. # define INCBIN_INT ".word "
  144. # else
  145. # define INCBIN_INT ".int "
  146. # endif
  147. # if defined(__USER_LABEL_PREFIX__)
  148. # define INCBIN_MANGLE INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)
  149. # else
  150. # define INCBIN_MANGLE ""
  151. # endif
  152. # if defined(INCBIN_ARM)
  153. /* On arm assemblers, `@' is used as a line comment token */
  154. # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
  155. # elif defined(__MINGW32__) || defined(__MINGW64__)
  156. /* Mingw doesn't support this directive either */
  157. # define INCBIN_TYPE(NAME)
  158. # else
  159. /* It's safe to use `@' on other architectures */
  160. # define INCBIN_TYPE(NAME) ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
  161. # endif
  162. # define INCBIN_BYTE ".byte "
  163. #endif
  164. /* List of style types used for symbol names */
  165. #define INCBIN_STYLE_CAMEL 0
  166. #define INCBIN_STYLE_SNAKE 1
  167. /**
  168. * @brief Specify the prefix to use for symbol names.
  169. *
  170. * By default this is `g', producing symbols of the form:
  171. * @code
  172. * #include "incbin.h"
  173. * INCBIN(Foo, "foo.txt");
  174. *
  175. * // Now you have the following symbols:
  176. * // const unsigned char gFooData[];
  177. * // const unsigned char *const gFooEnd;
  178. * // const unsigned int gFooSize;
  179. * @endcode
  180. *
  181. * If however you specify a prefix before including: e.g:
  182. * @code
  183. * #define INCBIN_PREFIX incbin
  184. * #include "incbin.h"
  185. * INCBIN(Foo, "foo.txt");
  186. *
  187. * // Now you have the following symbols instead:
  188. * // const unsigned char incbinFooData[];
  189. * // const unsigned char *const incbinFooEnd;
  190. * // const unsigned int incbinFooSize;
  191. * @endcode
  192. */
  193. #if !defined(INCBIN_PREFIX)
  194. # define INCBIN_PREFIX g
  195. #endif
  196. /**
  197. * @brief Specify the style used for symbol names.
  198. *
  199. * Possible options are
  200. * - INCBIN_STYLE_CAMEL "CamelCase"
  201. * - INCBIN_STYLE_SNAKE "snake_case"
  202. *
  203. * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
  204. * @code
  205. * #include "incbin.h"
  206. * INCBIN(Foo, "foo.txt");
  207. *
  208. * // Now you have the following symbols:
  209. * // const unsigned char <prefix>FooData[];
  210. * // const unsigned char *const <prefix>FooEnd;
  211. * // const unsigned int <prefix>FooSize;
  212. * @endcode
  213. *
  214. * If however you specify a style before including: e.g:
  215. * @code
  216. * #define INCBIN_STYLE INCBIN_STYLE_SNAKE
  217. * #include "incbin.h"
  218. * INCBIN(foo, "foo.txt");
  219. *
  220. * // Now you have the following symbols:
  221. * // const unsigned char <prefix>foo_data[];
  222. * // const unsigned char *const <prefix>foo_end;
  223. * // const unsigned int <prefix>foo_size;
  224. * @endcode
  225. */
  226. #if !defined(INCBIN_STYLE)
  227. # define INCBIN_STYLE INCBIN_STYLE_CAMEL
  228. #endif
  229. /* Style lookup tables */
  230. #define INCBIN_STYLE_0_DATA Data
  231. #define INCBIN_STYLE_0_END End
  232. #define INCBIN_STYLE_0_SIZE Size
  233. #define INCBIN_STYLE_1_DATA _data
  234. #define INCBIN_STYLE_1_END _end
  235. #define INCBIN_STYLE_1_SIZE _size
  236. /* Style lookup: returning identifier */
  237. #define INCBIN_STYLE_IDENT(TYPE) \
  238. INCBIN_CONCATENATE( \
  239. INCBIN_STYLE_, \
  240. INCBIN_CONCATENATE( \
  241. INCBIN_EVAL(INCBIN_STYLE), \
  242. INCBIN_CONCATENATE(_, TYPE)))
  243. /* Style lookup: returning string literal */
  244. #define INCBIN_STYLE_STRING(TYPE) \
  245. INCBIN_STRINGIZE( \
  246. INCBIN_STYLE_IDENT(TYPE)) \
  247. /* Generate the global labels by indirectly invoking the macro with our style
  248. * type and concatenating the name against them. */
  249. #define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
  250. INCBIN_INVOKE( \
  251. INCBIN_GLOBAL, \
  252. INCBIN_CONCATENATE( \
  253. NAME, \
  254. INCBIN_INVOKE( \
  255. INCBIN_STYLE_IDENT, \
  256. TYPE))) \
  257. INCBIN_INVOKE( \
  258. INCBIN_TYPE, \
  259. INCBIN_CONCATENATE( \
  260. NAME, \
  261. INCBIN_INVOKE( \
  262. INCBIN_STYLE_IDENT, \
  263. TYPE)))
  264. /**
  265. * @brief Externally reference binary data included in another translation unit.
  266. *
  267. * Produces three external symbols that reference the binary data included in
  268. * another translation unit.
  269. *
  270. * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
  271. * "Data", as well as "End" and "Size" after. An example is provided below.
  272. *
  273. * @param NAME The name given for the binary data
  274. *
  275. * @code
  276. * INCBIN_EXTERN(Foo);
  277. *
  278. * // Now you have the following symbols:
  279. * // extern const unsigned char <prefix>FooData[];
  280. * // extern const unsigned char *const <prefix>FooEnd;
  281. * // extern const unsigned int <prefix>FooSize;
  282. * @endcode
  283. */
  284. #define INCBIN_EXTERN(NAME) \
  285. INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \
  286. INCBIN_CONCATENATE( \
  287. INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
  288. INCBIN_STYLE_IDENT(DATA))[]; \
  289. INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \
  290. INCBIN_CONCATENATE( \
  291. INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
  292. INCBIN_STYLE_IDENT(END)); \
  293. INCBIN_EXTERNAL const unsigned int \
  294. INCBIN_CONCATENATE( \
  295. INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
  296. INCBIN_STYLE_IDENT(SIZE))
  297. /**
  298. * @brief Include a binary file into the current translation unit.
  299. *
  300. * Includes a binary file into the current translation unit, producing three symbols
  301. * for objects that encode the data and size respectively.
  302. *
  303. * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
  304. * "Data", as well as "End" and "Size" after. An example is provided below.
  305. *
  306. * @param NAME The name to associate with this binary data (as an identifier.)
  307. * @param FILENAME The file to include (as a string literal.)
  308. *
  309. * @code
  310. * INCBIN(Icon, "icon.png");
  311. *
  312. * // Now you have the following symbols:
  313. * // const unsigned char <prefix>IconData[];
  314. * // const unsigned char *const <prefix>IconEnd;
  315. * // const unsigned int <prefix>IconSize;
  316. * @endcode
  317. *
  318. * @warning This must be used in global scope
  319. * @warning The identifiers may be different if INCBIN_STYLE is not default
  320. *
  321. * To externally reference the data included by this in another translation unit
  322. * please @see INCBIN_EXTERN.
  323. */
  324. #ifdef _MSC_VER
  325. #define INCBIN(NAME, FILENAME) \
  326. INCBIN_EXTERN(NAME)
  327. #else
  328. #define INCBIN(NAME, FILENAME) \
  329. __asm__(INCBIN_SECTION \
  330. INCBIN_GLOBAL_LABELS(NAME, DATA) \
  331. INCBIN_ALIGN_HOST \
  332. INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
  333. INCBIN_MACRO " \"" FILENAME "\"\n" \
  334. INCBIN_GLOBAL_LABELS(NAME, END) \
  335. INCBIN_ALIGN_BYTE \
  336. INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
  337. INCBIN_BYTE "1\n" \
  338. INCBIN_GLOBAL_LABELS(NAME, SIZE) \
  339. INCBIN_ALIGN_HOST \
  340. INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \
  341. INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \
  342. INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \
  343. INCBIN_ALIGN_HOST \
  344. ".text\n" \
  345. ); \
  346. INCBIN_EXTERN(NAME)
  347. #endif
  348. #endif