c++gccarmnewliblink-time-optimization

Using LTO with arm-none-eabi and newlib-nano


I'm working on an bare-metal embedded project for the STM32F103, and I'm using GNU ARM Embedded version 7-2017-q4-major toolchain. I'm currently compiling via GNU ARM Eclipse.

I'm at a point where I need to start optimizing the project for speed, and as a first thing to do I of course tried turning on all the optimizer flags. Everything else went fine, but when I try to turn on Link Time Optimization with -flto, I get linker errors in the final step:

Invoking: Cross ARM C++ Linker
arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -O3 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Wall -Wextra  -g3 -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"Project.map" -Xlinker --cref --specs=nano.specs -o "Project.elf"  ./tiny-mt/tinymt/tinymt32.o  ... .o   
/Users/me/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/libg_nano.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0xe): undefined reference to `_fstat'
/Users/me/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/lib/thumb/v7-m/libg_nano.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'
collect2: error: ld returned 1 exit status
make: *** [Project.elf] Error 1

This is apparently due to newlib-nano not being compiled with LTO?

So how do I make it work? I suppose I could try compiling newlib-nano myself and adding the necessary flags (and changing the tools to use -gcc-ar and so on), but I'd imagine/hope that someone would already have done this? My google-fu was not enough to find anything helpful.


Solution

  • nosys.specs specifyes to link -lnosys with should provide stub implementations for _fstat and _isatty and other standard/posix functions.
    From gcc manual link options:

    -llibrary
    Search the library named library when linking. ...
    It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded.

    So if you move --specs=nano.specs to the ending of your link command, your sources shold link with -lnosys and properly use _isatty and _fstat implementations from libnosys library. Like this:

    arm-none-eabi-g++ -mcpu=cortex-m3 -mthumb -O3 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Wall -Wextra  -g3 -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"Project.map" -Xlinker --cref -o "Project.elf"  ./tiny-mt/tinymt/tinymt32.o  ... .o --specs=nano.specs
    

    I can guess newlib-nano compiled without LTO has nothing to do with it. I am using multiple projects with LTO with newlib-nano and they work just perfectly. Usually LTO works really good, removes layers of abstraction functions, is predictable, optimizes really good, but i have only 2 years experience using it. I use -Ofast -flto -fno-fat-lto-objects if I really need speed (and can live with non-standard behavior).