Summary
The impure_data section appears because Newlib’s standard library pulls in global state for error handling, locale, and other runtime services. -fno-math-errno only suppresses the errno side‑effect of math functions; it does not eliminate the whole impure_data region. Switching to nano.specs swaps the full Newlib implementation for a slimmer “newlib‑nano” variant that removes many optional globals, drastically shrinking the section.
Root Cause
sqrt()links againstlibg.a, which depends on libc objects that define the _impure_ptr structure.- The structure resides in the .impure_data subsection and contains:
errnofield__localedata__atexithandler tables
-fno-math-errnodisables the errno side‑effect inside the math function, but the library still expects the globalerrnovariable to exist, so the linker still pulls in the object that defines it.- The default Newlib (
libc.a) pulls many additional globals (stdio buffers, reentrancy structures) that inflate the section.
Why This Happens in Real Systems
- Embedded toolchains ship with full Newlib for compatibility.
- Many C library functions are compiled with
__attribute__((weak))and resolve to the “full” implementations unless the nano variant is explicitly requested. - The linker pulls in whole object files, not individual symbols; any object that defines
_impure_ptrbrings the whole.impure_datasegment.
Real-World Impact
- Memory budget overflow on devices with < 2 KiB RAM (e.g., MSPM0C).
- Longer startup time because the C runtime has to zero‑initialize a larger data segment.
- Increased flash usage: the full Newlib objects are larger than the nano equivalents.
- Potential runtime failures if the RAM overrun corrupts other variables.
Example or Code (if necessary and relevant)
#include
How Senior Engineers Fix It
- Prefer nano libraries: add
--specs=nano.specs(and optionally--specs=nosys.specsfor stub syscalls). - Link only required objects: use
-Wl,--gc-sections(already present) and--specs=nosys.specsto avoid pulling syscalls that introduce extra globals. - Replace heavy functions with lightweight hand‑rolled alternatives when feasible (e.g., an integer square‑root approximation).
- Enable
-ffreestandingfor bare‑metal builds to suppress automatic inclusion of the full C library. - Audit library dependencies: run
arm-none-eabi-nm -C libg.a | grep impureto see which objects introduce the section and replace them with nano counterparts. - Use
-u _printf_floatonly when needed; otherwise avoid pulling floating‑point support altogether.
Why Juniors Miss It
- They assume
-fno-math-errnoremoves all errno handling, not just the math‑specific side‑effect. - They overlook that the C runtime (Newlib) introduces a global reentrancy structure independent of the math flags.
- They often don’t inspect the linker map closely enough to see which object file contributes to
.impure_data. - Lack of familiarity with the distinction between full Newlib and newlib‑nano specs leads to reliance on default settings that are too heavyweight for a 1 KiB RAM target.