Skip to content

Instantly share code, notes, and snippets.

@stecman
Last active September 5, 2023 00:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stecman/bbe0b53c568b64dd7c8e270042049aa8 to your computer and use it in GitHub Desktop.
Save stecman/bbe0b53c568b64dd7c8e270042049aa8 to your computer and use it in GitHub Desktop.
Basics of embedding a file in firmware with GCC

Basics of embedding files in firmware

This is an appendix item for Unicode Input Terminal.

With gcc, the linker can can happily create an object file from arbitrary input files. This is useful for embedding images, fonts, etc into firmware. Full CMake code at the end, but the important parts are:

# Create object file
arm-none-eabi-ld --relocatable --format binary --output logo.o unicode-logo.png

If you run nm logo.o, you can see the symbols that are available:

00000445 D _binary_unicode_logo_png_end
00000445 A _binary_unicode_logo_png_size
00000000 D _binary_unicode_logo_png_start

These can be added to your build (gcc ... main.c logo.o, etc), but some boilerplate is needed to make them ergonomic. This code makes the symbols accessible as pointers:

Header: embeds.hh

#pragma once

namespace assets {
    extern const uint8_t* unicode_logo_png;
    extern const uint8_t* unicode_logo_png_end;
}

Source: embeds.cpp

#include "embeds.hh"

// Note these aren't pointers: they're fixed size arrays with an address defined by the linker
extern "C" {
    extern const uint8_t _binary_assets_unicode_logo_png_start[];
    extern const uint8_t _binary_assets_unicode_logo_png_end[];
}

// Pointers that to the memory above (whereever it ends up at link time)
namespace assets {
	const uint8_t* unicode_logo_png = _binary_assets_unicode_logo_png_start;
	const uint8_t* unicode_logo_png_end = _binary_assets_unicode_logo_png_end;
}

CMake function

#
# Support embedding resources in the binary (GCC-specific)
# Based on https://stackoverflow.com/a/56006001/1470907
#
set(RC_DEPENDS "")

function(add_resource target input)
    string(MAKE_C_IDENTIFIER ${input} input_identifier)
    set(output "${CMAKE_CURRENT_BINARY_DIR}/${input_identifier}.o")
    target_link_libraries(${target} ${output})

    add_custom_command(
        OUTPUT ${output}
        COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} --relocatable --format binary --output ${output}
    ${input}
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${input}
    )

    set(RC_DEPENDS ${RC_DEPENDS} ${output} PARENT_SCOPE)
endfunction()

Using this looks like:

add_resource(my_firmware "assets/unicode-logo.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment