pico-sdk icon indicating copy to clipboard operation
pico-sdk copied to clipboard

rp2_common/pico_standard_link: implement customizable linker script

Open mvds00 opened this issue 2 years ago • 2 comments

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.ld which 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 #ifdef for each and every variable in the template; yet another option (for integers) is to use linker variables (i.e. simply setting MAIN_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.

mvds00 avatar Nov 13 '23 23:11 mvds00

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 ?

lurch avatar Dec 20 '23 14:12 lurch

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 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.

mvds00 avatar Dec 20 '23 14:12 mvds00