Why `impure_data` appears on custom build and eats 1K memory? Need fix

Short description: when stm32hal been built from CumeMX sources, with the same options as PIO use, .data.impure_data appears in output and eats 1K RAM.

<tl;dr>

I use CubeMX to generate chip init configs. For consistency reasons, i’l like to build HAL from CubeMX sources, instead of PIO built-ins. So, carefully inspected stm32cube.py, _bare.py and created post-script to patch _bare.py output envs - make it look like after stm32cube.py.

In general, that works, but memory consumption increased for 1K due injected impure_data variable. CLI params of compiler/linker looks the same. HAL version is the same (F0 1.9.0). I did not edited HAL files and application files. Only added the same version, generated by CubeMX and builded project. Intrusion is zero.

Can anybody help to get rid of impure_data?

Sources:

For compare - use dev branch and see memory report after build.

To see missed size, in directory with elf file run:

objdump -x ./pio/build/hardware_usb/firmware.elf | grep impure`
# or
nm --print-size --size-sort --demangle --radix=d .pio/build/hardware_usb/firmware.elf | grep "\s[bB]\s"

Found working solution is to remove -Wl, prefix from -Wl,-T<path> variable in LINKFLAGS.

But i could not understand why this help :(. Could anyone explain?

Here is final version of post-hook script:

Import("env", "projenv")

for e in [ env, projenv ]:
    #
    # Fix options after "_bare.py"
    #
    e.Replace(LINKFLAGS = [i for i in e['LINKFLAGS'] if i not in [ '-nostartfiles', '-nostdlib' ]])
    e.Append(LINKFLAGS = [ "--specs=nano.specs", "--specs=nosys.specs" ])
    e.Replace(AS = '$CC', ASCOM = '$ASPPCOM')

    #
    # .ld script should be passed to linker directly as "-T<path>"
    # instead of "-Wl,-T<path>", to avoid 1K RAM loss for ".data.impure_data"
    #
    e.Replace(BUILD_FLAGS = [i for i in e['BUILD_FLAGS'] if not i.startswith('-Wl,-T')])
    e.Replace(LINKFLAGS = [(i[4:] if i.startswith('-Wl,-T') else i) for i in e['LINKFLAGS']])

#print('=====================================')
#print(env.Dump())

I can confirm this. When using the default linker script with “pio run -v”, I see a “-T …” arg on the final arm-none-eabi-g++ call. When adding my own “-Wl,-T…” to build_flags, the resulting binary is over 1 KB larger, with an “impure” data section added. When I add “-T…” to to build_flags, I can see with “pio run -v” that it’s not passed to the final link, instead using the default .ld file from pio.

To fix it, I can manually re-enter the “pio run -v” link command, removing the “-Wl,” prefix, and all is well.

Odd.

PS. For completeness, the 1k-larger result is with these settings:

platform = ststm32
framework = stm32cube
board = genericSTM32F407VET6
build_flags = -DSTM32F4 -Wl,-Tf407-sram2.ld

UPDATE - This should make it clearer, I think:

% arm-none-eabi-g++ -o .pio/build/black407ve/firmware.elf -Wl,-Tf407-sram2.ld -Os -Wl,–gc-sections,–relax -mthumb -mcpu=cortex-m4 --specs=nano.specs --specs=nosys.specs .pio/build/black407ve/src/main.o -L/Users/jcw/.platformio/platforms/ststm32/ldscripts -L.pio/build/black407ve -L/Users/jcw/.platformio/packages/framework-stm32cube/f4/Drivers/CMSIS/Lib/GCC -L/Users/jcw/.platformio/packages/framework-stm32cube/platformio/ldscripts -Wl,–start-group .pio/build/black407ve/liba7b/libJeeH_ID3082.a -lc -lgcc -lm -lstdc++ -lnosys .pio/build/black407ve/libFrameworkHALDriver.a .pio/build/black407ve/libFrameworkCMSISDevice.a -Wl,–end-group
% arm-none-eabi-size .pio/build/black407ve/firmware.elf
text data bss dec hex filename
3452 1092 4052 8596 2194 .pio/build/black407ve/firmware.elf

% arm-none-eabi-g++ -o .pio/build/black407ve/firmware.elf -Tf407-sram2.ld -Os -Wl,–gc-sections,–relax -mthumb -mcpu=cortex-m4 --specs=nano.specs --specs=nosys.specs .pio/build/black407ve/src/main.o -L/Users/jcw/.platformio/platforms/ststm32/ldscripts -L.pio/build/black407ve -L/Users/jcw/.platformio/packages/framework-stm32cube/f4/Drivers/CMSIS/Lib/GCC -L/Users/jcw/.platformio/packages/framework-stm32cube/platformio/ldscripts -Wl,–start-group .pio/build/black407ve/liba7b/libJeeH_ID3082.a -lc -lgcc -lm -lstdc++ -lnosys .pio/build/black407ve/libFrameworkHALDriver.a .pio/build/black407ve/libFrameworkCMSISDevice.a -Wl,–end-group
% arm-none-eabi-size .pio/build/black407ve/firmware.elf
text data bss dec hex filename
3224 20 4016 7260 1c5c .pio/build/black407ve/firmware.elf
%

Please file an issue to Issues · platformio/platform-ststm32 · GitHub

Indeed, it’s strange why the linker behaves differently if the ld-script is specified directly. Anyway, the impure_data section is part of the newlib-nano library’s reentrancy support and in order to disable it you need to comment call to __libc_init_array in your startup routine and specify -nostartfiles flag in LINKFLAGS. Besides, starting with the next release of ststm32 platform, -Wl-T flag will be considered as a deprecated way of specifying linker scripts, instead please use the following syntax to specify custom one:

board_build.ldscript = path/to/script.ld

In this case this script will be added using the -T flag.

1 Like

Thanks for the clarification, board_build.ldscript sounds like a good idea.