avr-libc
avr-libc copied to clipboard
[bug #50811] using -Wl,-u,vfprintf -lprintf_min causes program to grow a lot
Sun 16 Apr 2017 01:38:22 AM CEST
The documentation seems to be saying that using those flags is supposed to save flash, but without them, a main() that does a single printf("foo\n"); gives me a 330 byte flash, while with them I get a 1330 byte flash.
If I remove the printf() call, I get flash sizes of 1228 or 228 with or without the above mentioned printf-min flags, respectively.
It looks like somehow the printf-min flag ends up dragging in a bunch extra code somehow?
The rest of my linker invocation looks like this:
avr-gcc -mmcu=atmega328p -lm -Wl,-gc-sections -Wl,-Map=program_to_upload.out.map -o program_to_upload.out main.o
I think probably the documentation ought to mention this possibility, assuming it isn't a bug.
This issue was migrated from https://savannah.nongnu.org/bugs/?50811
Dave Hylands
Calling printf("foo\n"); will be optimized to puts("foo"); so your test isn't really valid.
Try omparing a program which uses printf("foo: %d\n", 42); instead.
Mon 17 Apr 2017 08:18:07 AM CEST
Ok, with printf("foo: %d\n, 42), the program is indeed smaller with by 264 bytes when -Wl,-u,vfprintf -lprintf_min is used than when none of the printf linker flags are used.
I guess this is a wishlist item really: it would be nice if using printf_min didn't end up adding 1000 or so bytes to the program size when variadic vfprintf() invocations don't happen at all. I suppose given the realities of how the linker works that's unlikely. At least the issue deserves a mention in the discussion of these options in the vfprintf() documentation (that they can end up making your program a lot bigger, rather than smaller).
Dave Hylands
Using _Wl,-u,vfprintf is essentially forcing the symbol vfprintf to be undefined and added to the program. This is what's causing your code size to increase when not otherwise using vfprintf.
It isn't clear to me why that option should be required at all. You should only need to add the -lprintf_min option and that will pull in vprintf, if its used, and won't pull anything in if it isn't.
Mon 17 Apr 2017 08:54:57 PM CEST
You're correct, there's no reason when printf isn't being used to use those linker options. However:
- realistically at least some linker options are at least somewhat black magic to many users.- printf() is particularly likely to go from unused to used during debugging, during which large swings in code size may be extra confusingFor these reasons, I still think adding something to the documentation would make sense. It could be as simple as one sentence explaining what you just explained:
"Note that if your program doesn't end up calling vfprintf(), using the printf_min linker flags will increase code size because it forces the vfprintf() function to be included even though it isn't used."
Dave Hylands
I guess my point is that this statement (by itself) is false:
"Note that if your program doesn't end up calling vfprintf(), using the printf_min linker flags will increase code size because it forces the vfprintf() function to be included even though it isn't used."
It's only when both options are used together that you get that behaviour.
I think using -Wl,-u,vfprintf is incorrect and there is no need to use that option unless you want to keep unused code in your image.
Personally, I'd find the behaviour of keeping unused code in the image to be the confusing behaviour, not the fact that my debug builds are considerably larger than my release builds.
Joerg Wunsch <joerg_wunsch> Mon 17 Apr 2017 10:07:54 PM CEST
Well, the fact that the -u vfprintf needs to be forced is an unfortunate side effect of libprintf_min.a only containing a different definition of vfprintf(), but not e.g. for printf() or other members of the family.
Thus, if you only add -lprintf_min, this library will be processed by a time when the linker has not seen any obvious need to drag the vfprintf symbol in from it, so in effect, it will be ignored. Later on, when it comes to resolve the symbols needed by (e.g.) printf, it will suddenly also need vfprintf, but libprintf_min.a is already done by that time, so the standard version of vfprintf is used (from libc.a).
We could probably reorganize these libraries to also contain the other printf family members, but 1) that needs to be done by someone (who?), and 2) it won't fix the history, so the documentation has to remain the way it is for at least a while (a couple of years or more).
While the complaint this bug is focussing on is not completely invalid, I think it's practically a non-issue: except for the degraded testcase, nobody would want to drag in the full power (and bloat) of printf() & co. if all he wants to do is printing some constant strings without using any of the formatting functionality. As soon as a real printf functionality is needed, as seen, there is indeed a minimal saving of space by libprintf_min.a.
Mon 17 Apr 2017 11:04:22 PM CEST
If that's the case, why provide an optimized version of printf() for constant strings at all? I guess maybe it happens inevitably due to compiler machinations.
Anyway, at least one person (me) hit this issue and it took me some time to find the culprit. I set LDFLAGS for the printf_min long ago with the idea of generally keeping program size low, and this turns out to be a very poor general policy. The current docs don't give any indication of this, while they do describe smaller savings related to vfprintf choice in the presence of printf(). That's inconsistent and somewhat misleading.
Joerg Wunsch <joerg_wunsch> Tue 18 Apr 2017 08:02:58 AM CEST
I guess maybe it happens inevitably due to compiler machinations.
Exactly, it's a compiler thing we cannot influence.
Georg-Johann Lay
Re. the "compiler thing" mentioned above:
avr-gcc might replace a call to printf by a call to puts provided the arguments of printf allows to do so. You can avoid this optimization by means of -fno-builtin-printf which takes away any knowledge (except prototype information) about printf from the compiler. This will result in a call to printf (which you are using anyway), saving the call to fputs.