Kocherga app descriptor

Hi! I have been stuck on this simple issue for several days now, and hope someone here can help explain what I am missing.

I am trying to implement Kocherga in a system and have encountered a problem with integrating the app descriptor.
Running kocherga_image.py on the .bin fails to find an uninitialized app descriptor, manualy checking with a hexeditor I have also been unable to find a descriptor.

This minimal application recreates my issue:

#include <cstdio>
#include <cstdint>
#include <array>
#include <cstddef>

struct AppDescriptor
{
    std::uint64_t               magic = 0x5E4415146FC0C4C7ULL;
    std::array<std::uint8_t, 8> signature{{'A', 'P', 'D', 'e', 's', 'c', '0', '0'}};

    std::uint64_t                               image_crc  = 0;     // Populated after build
    std::uint32_t                               image_size = 0;     // Populated after build
    [[maybe_unused]] std::array<std::byte, 4>   _reserved_a{};
    std::uint8_t                                version_major = 1;
    std::uint8_t                                version_minor = 5;
    std::uint8_t                                flags =
#if RELEASE_BUILD
        1
#else
        2
#endif
    ;
    [[maybe_unused]] std::array<std::byte, 1>   _reserved_b{};
    std::uint32_t                               build_timestamp_utc = 6432;
    std::uint64_t                               vcs_revision_id     = 6537653;
    [[maybe_unused]] std::array<std::byte, 16>  _reserved_c{};

    struct Flags
    {
        static constexpr std::uint8_t ReleaseBuild = 1U;
        static constexpr std::uint8_t DirtyBuild   = 2U;
    };
};


int main()
{
   static const volatile AppDescriptor g_app_descriptor __attribute__((used));
   // Optionally, use explicit placement near the beginning of the binary:
   //      __attribute__((used, section(".app_descriptor")));
   // and define the .app_descriptor section in the linker file.

   printf("HelloWorld\n");
}

I am building the application with platformio using c++17 and stm32cube.

I’ve put your MWE into main.cpp then did the following, which worked as expected:

$ arm-none-eabi-g++ -std=c++17 main.cpp --specs=nosys.specs -O3
$ arm-none-eabi-objcopy  -O binary a.out a.bin
$ ./kocherga_image.py a.bin     # Success!

If I instruct the linker to discard unreferenced sections, however, I get the error you described:

$ arm-none-eabi-g++ -std=c++17 main.cpp --specs=nosys.specs -O3 -Wl,--gc-sections
$ arm-none-eabi-objcopy  -O binary a.out a.bin
$ ./kocherga_image.py a.bin     # No luck!
An uninitialized app descriptor could not be found in 'a.bin'. If this is intentional, use --lazy to squelch this error. Existing app descriptor: None

Therefore, you should explicitly put the descriptor into a specific linker section that is guaranteed to be kept. You can do it as follows in your linker script:

SECTIONS
{
    .text :
    {
        __text_start = .;
        KEEP(*(.vectors*))
        . = ALIGN(16);
        KEEP(*(.app_descriptor));   /* This is needed for the bootloader. */
        . = ALIGN(16);
        /* ... the rest is not shown ... */

And then annotate your struct with __attribute__((used, section(".app_descriptor"))),

It should also be possible to do it without modifying the linker script but I will leave this to you.

1 Like

Thank you Pavel,

I was able to make it work with a modified linker script.