RFD: selective linking of floating point support for *printf / *scanf

Joern Rennecke joern.rennecke@embecosm.com
Thu Aug 14 08:52:00 GMT 2014

For embedded targets with small memories and static linking, the size of
functions like *printf and their dependencies is painful, particularily for
targets that need software floating point.

avr-libc has long had a printf / scanf implementation that by default does not
include floating point support.  There's a library that can be liked to provide
the floating-point enabled functions, but the required functions have
to be pulled
in manually with -Wl,-u if they are otherwise only referenced from libc, lest
these symbols got resolved with the integer-only implementations from
libc itself.
All in all, a rather unsatisfying state of affairs when trying to run the
gcc regression test suite.

Newlib also has an integer-only printf implementation, but in this case,
the default is the other way round - you have to use functions with nonstandard
names to use the integer-only implementations.  And a half-hearted approach to
use this can easily end up with linking in both the integer-only version and the
floating-point enabled one, resulting in increased executable size instead of
a saving.

I think we can do better with integrated compiler/linker support.
Trying to do a perfect job i of course impossible because of Rice's theorem,
but it doesn't have to be perfect to be useful.
Just looking statically at each *printf statement, we can look at the format
strings and/or the passed arguments.
Floating point arguments are easier to check for by the compiler than parsing
the format string.  There is already code that parses the format strings for the
purpose of warnings, but it would be a somewhat intrusive change to add this
functionality there, and the information is not available where a variable
format is used anyway.
In a standards-conformant application, floating point formats can only be used
with floating point arguments, so checking for the latter seems most effective.

So my idea is to make the compile emit special calls when there are no floating
point arguments.  A library that provides the floating point enabled
precedes libc in link order.
Libc contains the integer-only implementations of *scanf/*printf, in two parts:
entry points with the special function name, which in the same object file
also contain a reference to the ordinary function name, and another object file
with the ordinary symbol and the integer-only implementation.
Thus, if any application translation unit has pulled in a floating-point enabled
implementation, this is the one that'll be used.  Otherwise, the integer-only
one will be used.
Use of special sections and alphasorting of these in the linker script
ensures that the integer-only entry points appear in the right place at
the start of the chosen implementation.
If vfprintf is used

I've implemented this for AVR with these commits:

Although it could use some more testing, and thought how to best
introduce the change as to avoid getting broken toolchains when components
are out-of-sync.

Now Joerg Wunsch suggested we might want to facto out more pieces, like the
long long support.  This quickly leads to a combinatorial explosion.
If we want to support a more modular *printf / *scanf, than maybe a different
approach is warranted.
Say, if we could give a symbol and section attribute and/or pragma to individual
case labels of a switch, and put the different pieces into separate object
files (maybe with a bit of objcopy massaging).
The symbols references to trigger the inclusion of the case objects could be
generated by the gcc backend by processing suitably annotated function calls.
E.g. we might put something into CALL_FUNCTION_USAGE, or play with

More information about the Newlib mailing list