pico-sdk
pico-sdk copied to clipboard
rp2_common/pico_standard_link: implement customizable linker script
Fixes #398
Background:
For cases where modifications to the linker script are required, pico-sdk only provides the option to provide an entire linker script using pico_set_linker_script. This patch adds a function pico_customize_linker_script to create a linker script in the build process, based on a template provided by pico-sdk and local settings provided by the user.
The tool of choice is the C preprocessor, but I am open to suggestions for an alternative.
Use cases for linker script modification include:
- using the linker script as a rudimentary file system for binary blobs
- sharing WiFi firmware blobs between bootloader and application (picowota)
- reducing the number of code duplication in linker scripts (e.g.
memmap_blocked_ram.ldwhich differs in only one line from the default)
In such cases, deriving the linker script from a template may/should lead to code that is easier to maintain.
Implementation:
The template is memmap.ld.in, the user input is provided by specifying a customization file to be included, and the linker script is generated by the C preprocessor. This of course is just one of many template solutions, but this one only requires a C compiler, which is available by definition.
The template exposes a few settings by #defining them before including the customization file, and provides a few hooks to add elements to the template.
Examples and hints for use, based on a working example where cyw43 firmware lives in a separate region in flash:
in CMakeLists.txt:
pico_customize_linker_script(my_target tweaks.h)
tweaks.h:
#undef MAIN_FLASH_LENGTH
#define MAIN_FLASH_LENGTH 256k
#undef ADDITIONAL_FLASH_REGIONS
#define ADDITIONAL_FLASH_REGIONS \
FLASH_CYWFW(rx): ORIGIN = 0x10040000, LENGTH = 256k
#undef ADDITIONAL_SECTIONS
#define ADDITIONAL_SECTIONS \
.fw_cyw43 : { \\
. = ALIGN(4k); \\
KEEP(*(.fw_cyw43.meta)) \\
. = ALIGN(512); \\
*(.fw_cyw43.blob) \\
} > FLASH_CYWFW
Details:
- The linker script will be a build product named
${TARGET}.ld - When using
\\at the end of lines, newlines are inserted in the resulting linker script in a postprocessing step. This is done to improve readability of the resulting linker script. - Lines starting with
#need to be removed from the output; they are now turned into/*comments*/ - Values that are to be overridden need to be
#undeffed before redefining them, which is a bit awkward; another option is to use#ifdeffor each and every variable in the template; yet another option (for integers) is to use linker variables (i.e. simply settingMAIN_FLASH_LENGTH=256k).
TODO:
This was only tested on OS X with makefile builds, so broader testing is probably needed (although this new feature doesn't change/break anything existing).
As mentioned above, at least memmap_blocked_ram.ld (and memmap_default.ld) could easily be derived at runtime from the template. Maybe the other linker scripts can also derive from the template with the right tweaks.
I know nothing about linker scripts, but replying to just your comment about #undef and #ifdef - maybe it'd make sense to use the same pattern used by e.g. https://github.com/raspberrypi/pico-sdk/blob/master/src/boards/include/boards/pico.h ?
I know nothing about linker scripts, but replying to just your comment about
#undefand#ifdef- maybe it'd make sense to use the same pattern used by e.g. https://github.com/raspberrypi/pico-sdk/blob/master/src/boards/include/boards/pico.h ?
I have thought about that, but it hides the default values (they come later, and only #ifndef) so it limits the options, unless you would also #define DEFAULT_PARAM 123 before the include, which would make it all very verbose with 4 times the amount of lines, split over 2 places, compared to the #undef strategy.