About
This is a non-exhaustive, curated list of changes meant to help users quickly see what has improved since they last checked.
You can subscribe to this page via RSS.
Changes
initial-microbit-support
2025-04-28
Initial micro:bit support
Add support for the micro:bit 5x5 led display.
linker-script-generation
2025-06-18
Linker Script Generation
Every firmware needs a linker script that places stuff where it belongs in memory. When porting microzig to a new target you must face the challenge of dealing with a linker script. But fear not as microzig has your back (in most cases). Let’s checkout the linker_script
field in Target
.
linker_script: LinkerScript = .{},
pub const LinkerScript = struct {
/// Will anything be auto-generated for this linker script?
generate: GenerateOptions = .{ .memory_regions_and_sections = .{} },
/// Linker script path. Will be appended after what is auto-generated if it's not null.
file: ?LazyPath = null,
pub const GenerateOptions = union(enum) {
/// Only generates a comment with target info.
none,
/// Only generates memory regions.
memory_regions,
/// Generates memory regions and default sections based on the provided options.
memory_regions_and_sections: struct {
/// Where should rodata go?
rodata_location: enum {
/// Place rodata in the first region tagged as flash.
flash,
/// Place rodata in the first region tagged as ram.
ram,
} = .flash,
},
};
};
For an example let’s look at the target definition of rp2040. In this case we need a linker script that should also place the bootrom at the beginning of flash. Fortunately, we can still mostly auto-generate one and just patch it up a bit.
// port/raspberrypi/rp2xxx/build.zig
const chip_rp2040: microzig.Target = .{
// ...
.chip = .{
// ...
.memory_regions = &.{
.{ .tag = .flash, .offset = 0x10000000, .length = 2048 * 1024, .access = .rx },
.{ .tag = .ram, .offset = 0x20000000, .length = 256 * 1024, .access = .rwx },
},
},
.linker_script = .{
// The `generate` field defaults to `.memory_regions_and_sections`.
// This will be appended at the end of the auto-generated linker
// script.
.file = b.path("ld/rp2040/sections.ld"),
},
};
/* port/raspberrypi/rp2xxx/ld/rp2040/sections.ld */
SECTIONS
{
.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > flash0
ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")
}
INSERT BEFORE .flash_start;
This is the generated linker script:
/*
* Target CPU: cortex_m0plus
* Target Chip: RP2040
*/
/*
* This section was auto-generated by microzig.
*/
MEMORY
{
flash0 (rx!w) : ORIGIN = 0x10000000, LENGTH = 0x00200000
ram0 (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}
SECTIONS
{
.flash_start :
{
KEEP(*(microzig_flash_start))
} > flash0
.text :
{
*(.text*)
*(.srodata*)
*(.rodata*)
} > flash0
.ARM.extab : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash0
.ARM.exidx : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > flash0
.data :
{
microzig_data_start = .;
*(.sdata*)
*(.data*)
KEEP(*(.ram_text))
microzig_data_end = .;
} > ram0 AT> flash0
.bss (NOLOAD) :
{
microzig_bss_start = .;
*(.sbss*)
*(.bss*)
microzig_bss_end = .;
} > ram0
.flash_end :
{
microzig_flash_end = .;
} > flash0
microzig_data_load_start = LOADADDR(.data);
}
/*
* End of auto-generated section.
*/
SECTIONS
{
.boot2 : {
__boot2_start__ = .;
KEEP (*(.boot2))
__boot2_end__ = .;
} > flash0
ASSERT(__boot2_end__ - __boot2_start__ == 256,
"ERROR: Pico second stage bootloader must be 256 bytes in size")
}
INSERT BEFORE .flash_start;
FYI
- If the ram memory region used by the linker script generator is executable, a
.ram_text
section will be included for code that should be placed in ram. This applies to the rp2040 target where the section tagged as ram is executable.
Devlog Begins!
The MicroZig devlog is now set up for contributors to showcase their work. When adding your work, add to the top of the list.