Linkers and orphaned sections

Problem statement

I recently came across a situation in a project where I had the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
struct FaultInfo final {
    uint32_t r0;
    uint32_t r1;
    // And all the other register state of a Cortex-M0+ processor
    // ...

    uint32_t crc;
};

[[gnu::section(".uninit")]] volatile FaultInfo fault_data;

I was using this static region of data to persist some fault information across reboots, to log it on the next boot after recovering from the fault.

Data Structures: Ditto::static_ptr<Base, Derived, ...>

One of the nice things about C++ compared to C is its ability to define reusable types and data structures. They make code reuse easier and also help with reasoning if the abstraction is high-level enough.

Today we are going to talk about static_ptr from the library Ditto. Dynamic allocation is often forbidden when developing embedded systems. This leads to allocating most things either in the stack or globally. A static_ptr allows the user to statically allocate an object of a derived class and access it as a base class pointer. The nice thing is that it allows to easily implement the factory pattern if only one instance of each child is required at a time.

Bare Metal C++ Register Access API

Introduction to memory-mapping

Note: This section is introductory material for those who are not yet familiar with the concept of memory-mapping. If you are already experienced with memory-mapping feel free to jump to the next section. Most likely you won’t miss anything new.

One of the most common ways of accessing peripherals from a CPU is memory-mapping. In short, this means that the address space of the CPU has some addresses that when accessed read/write peripheral’s registers. In order to access such peripherals from our code there are multiple strategies that could be used. This post will explore multiple alternatives and discuss their differences and fitness for their unique task.

Mastering the GNU linker script

Most people getting started with embedded development seem to find linker scripts just another piece of magic required to get up and running with their system. Even when they might already be familiar with memory-mapped peripherals and basic embedded concepts, the linker script and how it interacts with the GNU linker (ld) is still pretty mysterious.

Today we will go through the main functions of a linker script to try to shed some light onto their operation. We covered the basic of cross compilation in a previous post. We mentioned that the linker would be the last step in the compilation process. The job of the linker is to take all input object files and libraries (both shared and static) and generate a single executable file. Let’s start with some terminology.

Bootloaders and ARM Cortex-M microcontrollers: Booting the target application

In a previous blog we discussed the role of the NVIC in ARM Cortex-M microcontrollers. This peripheral will play a central role in booting our target application. First of all, we need to discuss the boot process in an ARM Cortex-M microcontroller.

Boot process

  • After Power On Reset the microcontroller assumes the NVIC table is located at address 0x00000000.
  • The processor fetches the first two words in the NVIC table, corresponding to the top of the stack and the reset vector.
  • It sets the MSP (Main stack pointer) to the top of the stack.
  • It jumps to the address indicated by the reset vector.
  • Application program execution begins.

In the case of our bootloader, the processor will be loading the top of the stack and the reset vector of our bootloader and then start executing it. Then, we the bootloader decides if it can boot an application already present at flash memory or if it needs to load an application using the loader. No matter which is chosen, it will eventually have to boot the target application.