Embedding Files in C Source Code

This topic was published by and viewed 2832 times since "". The last page revision was "".

Viewing 1 post (of 1 total)
  • Author
    Posts

  • DevynCJohnson
    Keymaster
    • Topics - 437
    • @devyncjohnson

    When programming using C, some developers may need to embed a file (such as a JPEG, MP3, etc.) into the compiled program. Thankfully, there is are multiple easy cross-platform methods to perform this task.

    NOTE: This trick also works with Fortran,  Ada, and other programming languages that use object files (*.o).

    Assembly Method

    To embed (or include) a file into a compiled program, create a new file that uses the file-extension "*.S". This will be an Assembly file. Next, copy and paste the below template into the newly created file.

        .global blob_FILENAME_EXT
        .global size_FILENAME_EXT
        .section .rodata
    blob_FILENAME_EXT:
        .incbin "PATH/TO/FILE.EXT"
    1:
    size_FILENAME_EXT:
        .int 1b - blob_FILENAME_EXT

    Replace "FILENAME"  with the name of the file that will be embedded, and replace "EXT" with the file's extension. Other names can be used instead, if desired. Also, for the 5th line (beginning with .incbin), type the path (relative or absolute) to the desired file.

    In the primary source-code file that will use the embedded file, the embedded file can be accessed using the name created and used in the Assembly file (i.e. "blob_FILENAME_EXT"). The size of the embedded file can be accessed using the const "size_FILENAME_EXT" that is declared on the second line and set on line 8 (the last line). For illustration, if the developer uses the name "blob_image_jpeg" and the size name of "size_image_jpeg", then a "memcpy()" command would look like memcpy(script, &blob_image_jpeg, (size_t)size_image_jpeg). However, remember to declare the two constants in the header file of the source-code, or (if header files are not used) declare the constants near the top of the primary source-code file using code similar as seen below.

    extern const unsigned int size_FILENAME_EXT;
    extern const char *blob_FILENAME_EXT;

    Although the constant "size_FILENAME_EXT" is declared as an integer (int) and created as such in the Assembly file (.int), the constant can safely be cast as a size_t, as needed.

    During the compilation stage, list the Assembly file with the source-code file that needs/uses the embedded file. For instance, cc -Wall -Wextra -pedantic -O3 -fwhole-program -funroll-loops main.c asm_embed_jpeg.S -o compiled_program.exe.

    NOTE: If you do not wish to thoroughly understand the above Assembly code, then you can skip to the next method.

    • In the Assembly code, the first two lines declare the two constants as global variables.
    • The third line (.section .rodata) indicates that the code will be placed in the "read-only" section (rodata) of the compiled code.
    • Lines 4-5 initialize "blob_FILENAME_EXT". The command .incbin is used to include a file (binary mode).
    • Line 6 (1:) is a variable for the memory location after "blob_FILENAME_EXT".
    • The last two lines set the constant "size_FILENAME_EXT" to the length (number of bits) of "blob_FILENAME_EXT" by using the 1: variable and the memory location of "blob_FILENAME_EXT" (using the label on line 4).

    Linking Method

    The file to be embedded can be created as an object file using the command-line code ld -r -b binary FILE_TO_EMBED -o EMBEDDED.o.

    An object file can also be made using the previously mentioned Assembly code by using a command like cc -c ASM_FILE.S -o EMBEDDED.o.

    Further Reading

Viewing 1 post (of 1 total)