From 09610f59debc59d9b4ff845afb9fdf5a140aefc1 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Tue, 19 Nov 2024 12:33:26 +0100 Subject: [PATCH] stdlib: fix atoi()/strto*() pulling in the entirety of scanf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was due to the few base __scanf() functions, used by strto*() and co. to share their framework with scanf() specifiers, being in the main scanf() file. Not sure why it ended up pulling the entire file even with LTO, but now that it's separate there's no issue anymore. Pulling in the entirety of scanf() is mostly expensive because it contains specifiers(), including strtod(), which itself computes on floating point numbers, leading to many libm functions being linked in, some of them with their internal data tables. In the end you'd call atoi() and get a 24-kB size increase. Which is not ✨great✨ :) --- CMakeLists.txt | 3 ++- src/stdio/scanf/scan.c | 33 --------------------------------- src/stdio/scanf/scan_base.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 src/stdio/scanf/scan_base.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 83c13e1..cb40793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,7 @@ if(FXLIBC_PIC) add_compile_options(-fpic) endif() if(FXLIBC_LTO) - add_compile_options(-flto) + add_compile_options(-flto -ffat-lto-objects) # Generate the archive with gcc-ar instead of ar as it will load the LTO # plugin which is required to generate a usable archive. set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER_AR} qcs ") @@ -157,6 +157,7 @@ set(SOURCES src/stdio/rewind.c src/stdio/scanf.c src/stdio/scanf/scan.c + src/stdio/scanf/scan_base.c src/stdio/setbuf.c src/stdio/setvbuf.c src/stdio/snprintf.c diff --git a/src/stdio/scanf/scan.c b/src/stdio/scanf/scan.c index baecbe3..30af440 100644 --- a/src/stdio/scanf/scan.c +++ b/src/stdio/scanf/scan.c @@ -27,39 +27,6 @@ - TODO: Maximum field width for floating-point is mostly untested and likely has bugs when the field ends in the middle of the number. */ -void __scanf_start(struct __scanf_input *in) -{ - if(in->fp) - in->buffer = fgetc(in->fp); - else { - in->buffer = (*in->str ? *in->str : EOF); - in->str += (in->buffer != EOF); - } -} - -int __scanf_fetch(struct __scanf_input *in) -{ - if(in->fp) - return fgetc(in->fp); - - int c = *in->str; - if(c == 0) - return EOF; - in->str++; - return c; -} - -void __scanf_end(struct __scanf_input *in) -{ - if(in->buffer == EOF) - return; - - if(in->fp) - ungetc(in->buffer, in->fp); - else - in->str--; -} - static void __skip_spaces(struct __scanf_input *in) { while(isspace(__scanf_peek(in))) diff --git a/src/stdio/scanf/scan_base.c b/src/stdio/scanf/scan_base.c new file mode 100644 index 0000000..c2cf768 --- /dev/null +++ b/src/stdio/scanf/scan_base.c @@ -0,0 +1,36 @@ +#include "../stdio_p.h" +#include "../../stdlib/stdlib_p.h" +#include + +void __scanf_start(struct __scanf_input *in) +{ + if(in->fp) + in->buffer = fgetc(in->fp); + else { + in->buffer = (*in->str ? *in->str : EOF); + in->str += (in->buffer != EOF); + } +} + +int __scanf_fetch(struct __scanf_input *in) +{ + if(in->fp) + return fgetc(in->fp); + + int c = *in->str; + if(c == 0) + return EOF; + in->str++; + return c; +} + +void __scanf_end(struct __scanf_input *in) +{ + if(in->buffer == EOF) + return; + + if(in->fp) + ungetc(in->buffer, in->fp); + else + in->str--; +}