Repository navigation
Description
Follow-up to #243 (ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off).
#243 lands the policy + decision function + flag injection in the ESP32 compiler path only. The same -fno-asynchronous-unwind-tables -fno-unwind-tables pair is a win on every GCC-based embedded target where C++ exceptions and platform-level backtrace are both off — which is most of fbuild's matrix. This ticket tracks propagating that machinery uniformly.
Why this is its own issue
The decision function eh_frame_policy::decide() from #243 is platform-neutral (its inputs are build_flags, build_unflags, profile, env vars, plus an optional platform-specific summary like SdkConfigSummary). The wiring into each per-platform compiler is platform-specific. Splitting them keeps #243's PR small and lets #243 prove out the savings on one platform before fanning out.
Platforms in scope
| Platform | Compiler crate | Notes |
|---|---|---|
| Generic ARM Cortex-M (STM32, RP2040, NRF52) | crates/fbuild-build/src/generic_arm/arm_compiler.rs |
Most users have no exceptions and no fault-handler unwind; expected savings comparable to ESP32 per-TU. |
| Teensy | crates/fbuild-build/src/teensy/teensy_compiler.rs |
Teensy 4.x has reasonable RAM, but flash is still a savings target. Teensy 3.0/LC are RAM-constrained and benefit any code-size cut indirectly. |
| ESP8266 | crates/fbuild-build/src/esp8266/* (if present) |
Same xtensa-gcc flag semantics as ESP32. |
| AVR | crates/fbuild-build/src/avr/* |
Probably out of scope. AVR-gcc emits .eh_frame only when exceptions are enabled, which fbuild's AVR config disables by default. Audit first; skip if zero impact. |
| WASM | n/a | Different unwind model; not GCC. Out of scope. |
Plan
-
Wait for ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243 to merge and confirm:
- The decision function (
crates/fbuild-build/src/esp32/eh_frame_policy.rs) is a pure function over plain inputs. - Tests cover the matrix (Preserve / Strip per trigger).
- Integration test asserts ≥ 150 KB savings on ESP32-S3 NEOPIXEL Blink.
- The decision function (
-
Hoist the decision function up out of
esp32/into a shared module (likelycrates/fbuild-build/src/eh_frame_policy.rsor a smallfbuild-build-policysub-module). The inputs stay generic; the per-platform extras (sdkconfig for ESP32, possibly Teensyusb_type/board config for Teensy) plug in as an optional trait or as a&dyn PlatformPolicyHints. -
Per platform, wire the policy into the existing
common_flags()(or equivalent) method:generic_arm/arm_compiler.rsteensy/teensy_compiler.rsesp8266/*(if applicable)
-
Per platform, add an integration test mirroring the ESP32 one: build a tiny canonical sketch, assert binary-size delta. Use the same
object-crate.eh_framesection-size diagnostic from ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243 so failure messages stay informative. -
Document in the same fbuild docs page ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243 created (
docs/.../size-optimization.mdor similar). One table of supported platforms, defaults, and overrides.
Decision policy — same as #243
Preserve eh_frame if ANY of:
- build_flags contains `-fexceptions` or `-funwind-tables`
or `-fasynchronous-unwind-tables`
- debug profile (-Og / -O0 / !NDEBUG)
- FBUILD_KEEP_EH_FRAME=1
- (platform-specific) backtrace / fault-decoder enabled in platform config
Strip otherwise (default for release builds with no override).
The platform-specific hint is what differs:
- ESP32:
CONFIG_ESP_SYSTEM_PANIC_*/CONFIG_ESP_DEBUG_OCDAWARE(already ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243). - Generic ARM: no equivalent today — STM32/RP2040/NRF52 fault handlers don't walk
.eh_frame. Default is Strip-unless-overridden. - Teensy: Teensy's fault handler doesn't use eh_frame either. Default is Strip-unless-overridden.
Estimated impact
The ESP32 measurement (#243) shows ~225 KB savings on FastLED Blink with full propagation. Per-platform numbers will be smaller because the framework cores are smaller, but the ratio is roughly the same (~30 % of release-build size is .eh_frame for an exception-handling-disabled C++ library).
Rough projections, to be validated against the integration test:
| Platform | Canonical example | Expected savings |
|---|---|---|
STM32F1 (stm32f103c8) |
FastLED Blink | 40–80 KB |
| RP2040 | FastLED Blink | 60–120 KB |
| Teensy 4.1 | FastLED Blink | 100–180 KB |
| Teensy 3.0 / LC | FastLED Blink | small absolute, may unblock the RAM overflow tracked in FastLED/FastLED#2406 |
Acceptance
- Shared
eh_frame_policy::decide()lives outside theesp32/module and is consumed by every GCC-based platform compiler. - Per-platform integration test: build canonical sketch with
FBUILD_KEEP_EH_FRAME=1andFBUILD_STRIP_EH_FRAME=1, assert positive delta. - No regression in existing per-platform tests (
crates/fbuild-build/tests/teensy_build.rs,stm32_acceptance.rs, etc.). - Docs page from ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243 expanded to list every supported platform's default + override.
- Optional bonus: the Teensy LC / 3.0 binary size drops enough to give the RAM-overflow work in Teensy 3.0 / LC link-time RAM overflow (.dmabuffers / .bss) across all examples FastLED#2406 some headroom (not a hard requirement; mostly a happy side effect).
Out of scope
- AVR. Audit first; almost certainly nothing to strip.
- WASM. Different unwind model.
- The decision policy itself. Owned by ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243; this ticket is wiring only.
- Per-platform fault-decoder semantics (e.g., if a Teensy CrashReport-style feature wants eh_frame, that goes in a separate decision-policy ticket).
Related
- ESP32: auto-strip .eh_frame when exception handling and panic backtrace are both off (~225 KB savings on FastLED Blink) #243 — ESP32-side implementation that lands the decision function.
- ESP32-S3 binary size: 657 KB on master vs 344 KB on 3.10.3 — remaining +313 KB delta breakdown FastLED#2473 — symbol-level audit that motivated the work.
- Teensy 3.0 / LC link-time RAM overflow (.dmabuffers / .bss) across all examples FastLED#2406 — Teensy 3.0 / LC RAM overflow; any code-size cut on those boards helps incidentally.
- feat(channels): compile-time Bus binding via templated ChannelConfig (eliminates Channel API binary bloat) FastLED#2428 — driver registry default-off (already merged); the other big size win.
Activity
feat(build): #243 #244 strip .eh_frame on release builds across all G…