Skip to content

rp2: Link with nano.specs, add linker cref table#19299

Draft
projectgus wants to merge 2 commits into
micropython:masterfrom
projectgus:feature/rp2_nano_specs
Draft

rp2: Link with nano.specs, add linker cref table#19299
projectgus wants to merge 2 commits into
micropython:masterfrom
projectgus:feature/rp2_nano_specs

Conversation

@projectgus
Copy link
Copy Markdown
Contributor

@projectgus projectgus commented Jun 3, 2026

Summary

Passes --specs=nano.specs on the linker command line for rp2, meaning newlib-nano is used instead of regular newlib. As mentioned by @Gadgetoid in #11143. This reduces both the binary size and (significantly) the static RAM usage. Should also save some RAM at runtime, particularly the stack footprint of libc printf.

Includes a commit to add the --cref linker argument, which adds a cross-reference table in the linker map file. This is useful to figure out how/why certain symbols are linked.

The specific libc pieces which are linked in the default rp2 build seem to be malloc/free/realloc and some printf support.

  • The malloc/free/realloc looks like it's pulled in via pico_util queue.c and time.c, and operator new & delete (unclear why these are pulled in at all!) Can find via __wrap_free in the cross-reference table. This feels like with a small amount of work it could be removed, maybe...? Particularly as the default rp2 build has no C heap available.
  • snprintf looks like it's being pulled in via some mbedTLS features, shared/readline, and shared/netutils. Can find via __wrap_snprintf in the cross-reference table. This feels like it'd be harder to remove the dependency for.

I don't think any of these use cases require "full" newlib support.

The best description I know for gcc specs and nano vs normal newlib is https://metebalci.com/blog/demystifying-arm-gnu-toolchain-specs-nano-and-nosys/

Testing

  • Ran the default unit tests on RPI_PICO2.

Trade-offs and Alternatives

  • Keeping default newlib is the safer path, particularly if there are any C usermodules that happen to depend on "full" libc features. However, MicroPython itself doesn't depend on much libc at all.

Generative AI

I did not use generative AI tools when creating this PR.

Useful to see why particular symbols have been pulled in.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
Reduces binary, static RAM, and (probably) runtime memory usage.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
@projectgus projectgus changed the title Feature/rp2 nano specs rp2: Link with nano.specs, add linker cref table Jun 3, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Code size report:

Reference:  rp2/CMakeLists.txt: Require boards to define PICO_FLASH_SIZE_BYTES. [44a569b]
Comparison: rp2: Link nano.specs for newlib-nano. [merge of b353960]
  mpy-cross:    +0 +0.000% 
   bare-arm:    +0 +0.000% 
minimal x86:    +0 +0.000% 
   unix x64:    +0 +0.000% standard
      stm32:    +0 +0.000% PYBV10
      esp32:    +0 +0.000% ESP32_GENERIC
     mimxrt:    +0 +0.000% TEENSY40
        rp2:  -132 -0.014% RPI_PICO_W[incl -704(bss)]
       samd:    +0 +0.000% ADAFRUIT_ITSYBITSY_M4_EXPRESS
  qemu rv32:    +0 +0.000% VIRT_RV32

@dpgeorge
Copy link
Copy Markdown
Member

dpgeorge commented Jun 4, 2026

Thanks for doing this. I like the idea, and on RPI_PICO_W it saves 1624 bytes of flash and 960 bytes of RAM.

But... the tests/net_hosted/ssl_verify_callback.py now locks up! Also tests/net_inet/asyncio_tls_open_connection_readline.py and probably others (these were just the first two I found). Note that some SSL tests still work though.

snprintf looks like it's being pulled in via some mbedTLS features

I guess that's the cause of the crashes? I tried adding shared/libc/printf.c to the build to fix that (and noted that MICROPY_USE_INTERNAL_PRINTF is already enabled) but that didn't fix it. I think anyway shared/libc/printf.c is already included in the cmake builds due to it being in MICROPY_SOURCE_EXTMOD.

I'd be interested to know exactly what mbedTLS is pulling in from libc that doesn't work with newlib-nano... it's a bit scary that we don't fully understand the dependencies here, especially since ports like stm32 work just fine with -nostdlib (libc is provided by our own code in shared/libc/ for that port).

@Gadgetoid I'm surprised you didn't see failures with your firmware when using nano.specs. Did you test SSL with your firmware?

@projectgus
Copy link
Copy Markdown
Contributor Author

But... the tests/net_hosted/ssl_verify_callback.py now locks up! Also tests/net_inet/asyncio_tls_open_connection_readline.py and probably others (these were just the first two I found). Note that some SSL tests still work though.

Oh wow, sorry! I didn't realise those tests weren't part of the default run-tests.py coverage!

I wonder if it's to do with linker placement instead of the actual features, there might be something that's now reading from cached flash. I'll do a bit of spelunking and try to figure this out.

@projectgus projectgus marked this pull request as draft June 4, 2026 06:48
@dpgeorge
Copy link
Copy Markdown
Member

dpgeorge commented Jun 4, 2026

I didn't realise those tests weren't part of the default run-tests.py coverage!

You mentioned you ran the tests on RPI_PICO2, which won't be able to run the network tests anyway.

Eventually octoprobe will help here, by just running all tests regardless. But also probably we should think about merging #16112; I use it all the time now (and is how I tested this PR).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants