The C Runtime
Hopefully, you've read this intro to runtimes.
The C runtime follows the third meaning. ie The C runtime is the startup code that gets executed in preparation for the call to the main
function.
Unlike the JAVA runtime and JS runtime, the C runtime is not an application that runs independent of the user-program. The C runtime is a set of library files that get statically compiled together with your C code. C runtime is not an independent application, it is a dependency that gets linked and compiled together with the program that you are writing.
This C runtime is usually nick-named CRT-0
and is typically written in assembly code.
Functions of the C runtime code
There are many variations of the C-runtime.
It is a free-world. It is up to you to decide what your C-runtime does.
However, here are some of the typical functions found in any C-runtime library.
- Loading elf programs from ROM/secondary_memory to RAM.
- Allocating space for the stack and initializing the stack pointer
- Allocating space for a heap (if used)
- Initializing global static variables before the program execution begins. This is achieved by copying values from Flash into variables declared with initial values
- Zero-ing out all uninitialized global variables.
- Clearing uninitialized RAM
- Populating the vector table so the device can properly dispatch exceptions and interrupts.
- Calling the
main()
function safely.
Extra and non-vital functions include :
- Setting up overlay control code.
- Setting up Stack protection code.
- Setting up stack unwinding code.
Quite a mouthful ha? So many functions!
Here are resources that will help you understand the C-runtime :
- The C Runtime Environment by microchip.com. This summarizes things in a clean way. Best resource here.
- This c_startup blog by Vijay Kumar B on bravegnu.com takes you through writing a simple Runtime targeting the ARM board. If you have no interest in ARM, you can just skim through the tutorial and get the gist.
- Good old wikipedia.
Examples of C runtimes
You can look at the code found in these repos in order to get a gist of how the internals of a C-runtime look like.
- An implementation in Rust : r0 by rust-embedded group
- An implementation in Assembly + Rust targeting Riscv boards : riscv-rt by rust-embedded group
Later, we will write our own Runtime targeting the Riscv Board that we will be working with
You can always skip the whole process of writing your own runtime and instead use
riscv-rt
, but where is the fun in that?