Hi,
While upgrading a project from the 11.2 to 12.2 releases of the GNU ARM Embedded toolchain, I'm encountering a problem:
[344/346] cmd.exe /C "cd . && C:\tools\jetbrains\apps\CLion\ch-0\223.8617.54\bin\cmake\win\x64\bin\cmake.exe -E rm -f ext\soup\hal\libstm32h7_hal_resmgr.a && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\ARM-NO~2.EXE qc ext\soup\hal\libstm32h7_hal_resmgr.a ext/soup/hal/CMakeFiles/stm32h7_hal_resmgr.dir/STM32CubeH7/Utilities/ResourcesManager/res_mgr.c.obj && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR17F9~1.EXE ext\soup\hal\libstm32h7_hal_resmgr.a && cd ." [345/346] cmd.exe /C "cd . && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR19DD~1.EXE -O0 -g3 -DDEBUG -TC:/src/h7-eval/CM4/STM32H757XIHX_FLASH.ld -Wl,--cref -Wl,--print-memory-usage -Wl,-Map=C:/src/cmake-build-h7m4-debug-gnu-arm-113/h7-eval/CM4/h7-eval-m4.map -mthumb -mcpu=cortex-m4 -mabi=aapcs --specs=nano.specs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/Common/Src/system_stm32h7xx_dualcore_boot_cm4_cm7.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/adc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/crc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/cryp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dcmi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dma2d.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/eth.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/fmc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/gpio.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/hash.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/i2c.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/main.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/resmgr_utility.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/rng.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/spi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_hal_msp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_it.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/syscalls.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/sysmem.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/usart.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Startup/startup_stm32h757xihx.s.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/tx_initialize_low_level.S.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/stm32h7xx_hal_timebase_tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/__/ext/soup/threadx/threadx/utility/execution_profile_kit/tx_execution_profile.c.obj -o h7-eval\CM4\h7-eval-m4.elf ext/soup/hal/libstm32h7_hal.a ext/soup/hal/libstm32h7_hal_resmgr.a ext/soup/threadx/threadx/libthreadx.a ext/soup/hal/libstm32h7_hal.a && cd ." FAILED: h7-eval/CM4/h7-eval-m4.elf cmd.exe /C "cd . && C:\PROGRA~2\ARMGNU~1\12DBAB~1.2RE\bin\AR19DD~1.EXE -O0 -g3 -DDEBUG -TC:/src/h7-eval/CM4/STM32H757XIHX_FLASH.ld -Wl,--cref -Wl,--print-memory-usage -Wl,-Map=C:/src/cmake-build-h7m4-debug-gnu-arm-113/h7-eval/CM4/h7-eval-m4.map -mthumb -mcpu=cortex-m4 -mabi=aapcs --specs=nano.specs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/Common/Src/system_stm32h7xx_dualcore_boot_cm4_cm7.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/adc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/crc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/cryp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dcmi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/dma2d.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/eth.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/fmc.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/gpio.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/hash.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/i2c.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/main.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/resmgr_utility.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/rng.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/spi.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_hal_msp.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/stm32h7xx_it.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/syscalls.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/sysmem.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Src/usart.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/Core/Startup/startup_stm32h757xihx.s.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/tx_initialize_low_level.S.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/ThreadX/stm32h7xx_hal_timebase_tim.c.obj h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/__/ext/soup/threadx/threadx/utility/execution_profile_kit/tx_execution_profile.c.obj -o h7-eval\CM4\h7-eval-m4.elf ext/soup/hal/libstm32h7_hal.a ext/soup/hal/libstm32h7_hal_resmgr.a ext/soup/threadx/threadx/libthreadx.a ext/soup/hal/libstm32h7_hal.a && cd ." c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:84: multiple definition of `__lock___sfp_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___sfp_recursive_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:87: multiple definition of `__lock___atexit_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___atexit_recursive_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:90: multiple definition of `__lock___at_quick_exit_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___at_quick_exit_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:93: multiple definition of `__lock___malloc_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___malloc_recursive_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:96: multiple definition of `__lock___env_recursive_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___env_recursive_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:99: multiple definition of `__lock___tz_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___tz_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:102: multiple definition of `__lock___dd_hash_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___dd_hash_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj:C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:105: multiple definition of `__lock___arc4random_mutex'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):(.bss.__lock___arc4random_mutex+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_init': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:114: multiple definition of `__retarget_lock_init'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_init+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_init_recursive': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:123: multiple definition of `__retarget_lock_init_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_init_recursive+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_close': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:146: multiple definition of `__retarget_lock_close'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_close+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_close_recursive': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:155: multiple definition of `__retarget_lock_close_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_close_recursive+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_acquire': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:164: multiple definition of `__retarget_lock_acquire'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_acquire+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_acquire_recursive': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:174: multiple definition of `__retarget_lock_acquire_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_acquire_recursive+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_try_acquire': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:185: multiple definition of `__retarget_lock_try_acquire'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_try_acquire+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_try_acquire_recursive': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:196: multiple definition of `__retarget_lock_try_acquire_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_try_acquire_recursive+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_release': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:206: multiple definition of `__retarget_lock_release'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_release+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: h7-eval/CM4/CMakeFiles/h7-eval-m4.dir/__/ThreadSafe/newlib_lock_glue.c.obj: in function `__retarget_lock_release_recursive': C:/src/h7-eval/ThreadSafe/newlib_lock_glue.c:216: multiple definition of `__retarget_lock_release_recursive'; c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+fp/hard\libc_nano.a(libc_a-lock.o):lock.c:(.text.__retarget_lock_release_recursive+0x0): first defined here c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: h7-eval\CM4\h7-eval-m4.elf has a LOAD segment with RWX permissions Memory region Used Size Region Size %age Used FLASH: 53940 B 1 MB 5.14% RAM: 7 KB 288 KB 2.43% collect2.exe: error: ld returned 1 exit status ninja: build stopped: subcommand failed.
This is due to the version of libc_nano included with the 12.2 release including the retargetable locking functions (the stubs?). Is this a mistake? They aren't weak so can't be overridden by the project to provide its own locking implementation.
libc_a-lock.o: 00000000 B __lock___arc4random_mutex 00000000 B __lock___atexit_recursive_mutex 00000000 B __lock___at_quick_exit_mutex 00000000 B __lock___dd_hash_mutex 00000000 B __lock___env_recursive_mutex 00000000 B __lock___malloc_recursive_mutex 00000000 B __lock___sfp_recursive_mutex 00000000 B __lock___tz_mutex 00000001 T __retarget_lock_acquire 00000001 T __retarget_lock_acquire_recursive 00000001 T __retarget_lock_close 00000001 T __retarget_lock_close_recursive 00000001 T __retarget_lock_init 00000001 T __retarget_lock_init_recursive 00000001 T __retarget_lock_release 00000001 T __retarget_lock_release_recursive 00000001 T __retarget_lock_try_acquire 00000001 T __retarget_lock_try_acquire_recursive
These symbols were not exported by the 11.2 build. They conflict with the newlib_lock_glue.c generated by STM32CubeMX for STM32 projects (in this case, an H7 project). I thought these retargetable locking functions were supposed to be implemented by the user, and that a default implementation was not possible for a bare metal application. What is the intention for projects to do to work with GCC 12.2 newlib_nano?
Hi!Indeed, Newlib in the latest release has been configured with the `--enable-newlib-retargetable-locking` option and the stubs should not be included in your final build.The change in the configure options is intentional: Our previous releases up to GC10.3 did have the `--enable-newlib-retargetable-locking`, but it was then missed from the GCC11 releases. We re-introduced it, because it enables additional functionality: allowing users that want to use Newlib in a multithreaded environment to retarget the default locking routines.For some context on what this option does and how it works, see: https://sourceware.org/legacy-ml/newlib/2017/msg00080.html , but I suspect the error you're seeing is because of:> the dummy implementation is strongly defined such that a partial retargeting will cause a doubly defined link errorSo in your case, you (or your library) must be defining *some, but not all*, of the retargetable functions (i.e. in order for the object file with the dummy implementations to not be pulled in and avoid clashes, you need to define all of them). Could you provide those definitions or is that something that comes from the library/generated file you've mentioned? (sorry I'm familiar with the `newlib_lock_glue` you've mentioned)Hope this helps!Thanks,Stam
/** ****************************************************************************** * @file newlib_lock_glue.c * @author STMicroelectronics * @brief Implementation of newlib lock interface * * @details This file implements locking glue necessary to protect C library * functions and initialization of local static objects in C++. * Lock strategies are defined in stm32_lock.h that implements * different level of thread-safety. * * For more information about which C functions need which of these * low level functions, please consult the newlib libc manual, * see https://sourceware.org/newlib/libc.html * * For more information about the one-time construction API for C++, * see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor * ****************************************************************************** * @attention * * Copyright (c) 2022 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ #if !defined (__GNUC__) || defined (__CC_ARM) #error "newlib_lock_glue.c" should be used with GNU Compilers only #endif /* !defined (__GNUC__) || defined (__CC_ARM) */ /* Includes ------------------------------------------------------------------*/ #include <cmsis_compiler.h> /* Private functions ---------------------------------------------------------*/ /** * @brief Global Error_Handler */ __WEAK void Error_Handler(void) { /* Not used if it exists in project */ while (1); } #ifdef __SINGLE_THREAD__ #warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts #else /* Includes ------------------------------------------------------------------*/ #include <newlib.h> #include <stdatomic.h> #include "stm32_lock.h" /** * @defgroup _newlib_lock_functions newlib library locks * @see https://sourceware.org/newlib/libc.html * @{ */ #if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) #include <errno.h> #include <stdlib.h> #include <sys/lock.h> /* Private macros ------------------------------------------------------------*/ /** See struct __lock definition */ #define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data) /* Private variables ---------------------------------------------------------*/ struct __lock { LockingData_t lock_data; /**< The STM32 lock instance */ }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT }; /** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */ struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT }; /* Private functions ---------------------------------------------------------*/ /** * @brief Initialize lock * @param lock The lock */ void __retarget_lock_init(_LOCK_T *lock) { __retarget_lock_init_recursive(lock); } /** * @brief Initialize recursive lock * @param lock The lock */ void __retarget_lock_init_recursive(_LOCK_T *lock) { if (lock == NULL) { errno = EINVAL; return; } *lock = (_LOCK_T)malloc(sizeof(struct __lock)); if (*lock != NULL) { stm32_lock_init(STM32_LOCK_PARAMETER(*lock)); return; } /* Unable to allocate memory */ STM32_LOCK_BLOCK(); } /** * @brief Close lock * @param lock The lock */ void __retarget_lock_close(_LOCK_T lock) { __retarget_lock_close_recursive(lock); } /** * @brief Close recursive lock * @param lock The lock */ void __retarget_lock_close_recursive(_LOCK_T lock) { free(lock); } /** * @brief Acquire lock * @param lock The lock */ void __retarget_lock_acquire(_LOCK_T lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); } /** * @brief Acquire recursive lock * @param lock The lock */ void __retarget_lock_acquire_recursive(_LOCK_T lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); stm32_lock_acquire(STM32_LOCK_PARAMETER(lock)); } /** * @brief Try acquire lock * @param lock The lock * @return 0 always */ int __retarget_lock_try_acquire(_LOCK_T lock) { __retarget_lock_acquire(lock); return 0; } /** * @brief Try acquire recursive lock * @param lock The lock * @return 0 always */ int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { __retarget_lock_acquire_recursive(lock); return 0; } /** * @brief Release lock * @param lock The lock */ void __retarget_lock_release(_LOCK_T lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); stm32_lock_release(STM32_LOCK_PARAMETER(lock)); } /** * @brief Release recursive lock * @param lock The lock */ void __retarget_lock_release_recursive(_LOCK_T lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); stm32_lock_release(STM32_LOCK_PARAMETER(lock)); } #else #warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib /* Includes ------------------------------------------------------------------*/ #include <reent.h> /* Private variables ---------------------------------------------------------*/ /** Mutex used in __malloc_lock and __malloc_unlock */ static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT; /** Mutex used in __env_lock and __env_unlock */ static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT; /** Mutex used in __tz_lock and __tz_unlock */ static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT; /* Private functions ---------------------------------------------------------*/ #if __STD_C /** * @brief Acquire malloc lock * @param reent The reentrance struct */ void __malloc_lock(struct _reent *reent) { STM32_LOCK_UNUSED(reent); stm32_lock_acquire(&__lock___malloc_recursive_mutex); } /** * @brief Release malloc lock * @param reent The reentrance struct */ void __malloc_unlock(struct _reent *reent) { STM32_LOCK_UNUSED(reent); stm32_lock_release(&__lock___malloc_recursive_mutex); } #else /** * @brief Acquire malloc lock */ void __malloc_lock() { stm32_lock_acquire(&__lock___malloc_recursive_mutex); } /** * @brief Release malloc lock */ void __malloc_unlock() { stm32_lock_release(&__lock___malloc_recursive_mutex); } #endif /* __STD_C */ /** * @brief Acquire env lock * @param reent The reentrance struct */ void __env_lock(struct _reent *reent) { STM32_LOCK_UNUSED(reent); stm32_lock_acquire(&__lock___env_recursive_mutex); } /** * @brief Release env lock * @param reent The reentrance struct */ void __env_unlock(struct _reent *reent) { STM32_LOCK_UNUSED(reent); stm32_lock_release(&__lock___env_recursive_mutex); } /** * @brief Acquire tz lock */ void __tz_lock() { stm32_lock_acquire(&__lock___tz_mutex); } /** * @brief Release tz lock */ void __tz_unlock() { stm32_lock_release(&__lock___tz_mutex); } #endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */ /** * @} */ /** * @defgroup __cxa_guard_ GNU C++ one-time construction API * @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor * * When building for C++, please make sure that <tt>-fno-threadsafe-statics</tt> is not passed to the compiler * @{ */ /* Private typedef -----------------------------------------------------------*/ /** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */ typedef struct { atomic_uchar initialized; /**< Indicate if object is initialized */ uint8_t acquired; /**< Ensure non-recursive lock */ uint16_t unused; /**< Padding */ } __attribute__((packed)) CxaGuardObject_t; /* Private variables ---------------------------------------------------------*/ /** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */ static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT; /* Private functions ---------------------------------------------------------*/ /** * @brief Acquire __cxa_guard mutex * @param guard_object Guard object * @return 0 if object is initialized, else initialization of object required */ int __cxa_guard_acquire(CxaGuardObject_t *guard_object) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); if (atomic_load(&guard_object->initialized) == 0) { /* Object needs initialization, lock threading context */ stm32_lock_acquire(&__cxa_guard_mutex); if (atomic_load(&guard_object->initialized) == 0) { /* Object needs initialization */ if (guard_object->acquired) { /* Object initialization already in progress */ STM32_LOCK_BLOCK(); } /* Lock acquired */ guard_object->acquired = 1; return 1; } else { /* Object initialized in another thread */ stm32_lock_release(&__cxa_guard_mutex); } } /* Object already initialized */ return 0; } /** * @brief Abort __cxa_guard mutex * @param guard_object Guard object */ void __cxa_guard_abort(CxaGuardObject_t *guard_object) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); if (guard_object->acquired) { /* Release lock */ guard_object->acquired = 0; stm32_lock_release(&__cxa_guard_mutex); } else { /* Trying to release non-acquired lock */ STM32_LOCK_BLOCK(); } } /** * @brief Release __cxa_guard mutex * @param guard_object Guard object */ void __cxa_guard_release(CxaGuardObject_t *guard_object) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object); /* Object initialized */ atomic_store(&guard_object->initialized, 1); /* Release lock */ __cxa_guard_abort(guard_object); } /** * @} */ #endif /* __SINGLE_THREAD__ */
/** ****************************************************************************** * @file stm32_lock.h * @author STMicroelectronics * @brief STMicroelectronics lock mechanisms * * @details * This implementation supports the following strategies for handling * thread-safe locks. The strategy can be explicitly selected by * defining <tt>\STM32_THREAD_SAFE_STRATEGY = \<number></tt> in the project. * Please look at the '<toolchain/library>_lock_glue.c' file for more details. * * 1. User defined thread-safe implementation. * User defined solution for handling thread-safety. * <br> * <b>NOTE:</b> The stubs in stm32_lock_user.h needs to be implemented to gain * thread-safety. * * 2. [<b>DEFAULT</b>] Allow lock usage from interrupts. * This implementation will ensure thread-safety by disabling all interrupts * during e.g. calls to malloc. * <br> * <b>NOTE:</b> Disabling all interrupts creates interrupt latency which * might not be desired for this application! * * 3. Deny lock usage from interrupts. * This implementation assumes single thread of execution. * <br> * <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop * if used in interrupt context. * * 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks. * This implementation will ensure thread-safety by entering RTOS ISR capable * critical sections during e.g. calls to malloc. * By default this implementation supports 2 levels of recursive locking. * Adding additional levels requires 4 bytes per lock per level of RAM. * <br> * <b>NOTE:</b> Interrupts with high priority are not disabled. This implies * that the lock is not thread-safe from high priority interrupts! * * 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks. * This implementation will ensure thread-safety by suspending all tasks * during e.g. calls to malloc. * <br> * <b>NOTE:</b> Thread-safety dependent functions will enter an infinity loop * if used in interrupt context. * ****************************************************************************** * @attention * * Copyright (c) 2022 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ #ifndef __STM32_LOCK_H__ #define __STM32_LOCK_H__ /* Includes ------------------------------------------------------------------*/ #include <stdint.h> #include <stddef.h> #include <cmsis_compiler.h> #ifndef STM32_THREAD_SAFE_STRATEGY #define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */ #endif /* STM32_THREAD_SAFE_STRATEGY */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Function prototypes -------------------------------------------------------*/ void Error_Handler(void); /* Public macros -------------------------------------------------------------*/ /** Blocks execution */ #define STM32_LOCK_BLOCK() \ do \ { \ __disable_irq(); \ Error_Handler(); \ while (1); \ } while (0) /** Blocks execution if argument is NULL */ #define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x) \ do \ { \ if ((x) == NULL) \ { \ STM32_LOCK_BLOCK(); \ } \ } while (0) /** Blocks execution if in interrupt context */ #define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \ do \ { \ if (__get_IPSR()) \ { \ STM32_LOCK_BLOCK(); \ } \ } while (0) /** Hide unused parameter warning from compiler */ #define STM32_LOCK_UNUSED(var) (void)var /** Size of array */ #define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) #if STM32_THREAD_SAFE_STRATEGY == 1 /* * User defined thread-safe implementation. */ /* Includes ----------------------------------------------------------------*/ /** STM32 lock API version */ #define STM32_LOCK_API 1 #include "stm32_lock_user.h" #undef STM32_LOCK_API #elif STM32_THREAD_SAFE_STRATEGY == 2 /* * Allow lock usage from interrupts. */ /* Private defines ---------------------------------------------------------*/ /** Initialize members in instance of <code>LockingData_t</code> structure */ #define LOCKING_DATA_INIT { 0, 0 } /* Private typedef ---------------------------------------------------------*/ typedef struct { uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */ uint8_t counter; /**< Nesting level */ } LockingData_t; /* Private functions -------------------------------------------------------*/ /** * @brief Initialize STM32 lock * @param lock The lock to init */ static inline void stm32_lock_init(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); lock->flag = 0; lock->counter = 0; } /** * @brief Acquire STM32 lock * @param lock The lock to acquire */ static inline void stm32_lock_acquire(LockingData_t *lock) { uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */ __disable_irq(); __DSB(); __ISB(); STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); if (lock->counter == 0) { lock->flag = flag; } else if (lock->counter == UINT8_MAX) { STM32_LOCK_BLOCK(); } lock->counter++; } /** * @brief Release STM32 lock * @param lock The lock to release */ static inline void stm32_lock_release(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); if (lock->counter == 0) { STM32_LOCK_BLOCK(); } lock->counter--; if (lock->counter == 0 && lock->flag == 0) { __enable_irq(); } } #elif STM32_THREAD_SAFE_STRATEGY == 3 /* * Deny lock usage from interrupts. */ /* Private defines ---------------------------------------------------------*/ /** Initialize members in instance of <code>LockingData_t</code> structure */ #define LOCKING_DATA_INIT 0 /* Private typedef ---------------------------------------------------------*/ typedef uint8_t LockingData_t; /**< Unused */ /* Private functions -------------------------------------------------------*/ /** * @brief Initialize STM32 lock * @param lock The lock to init */ static inline void stm32_lock_init(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); } /** * @brief Acquire STM32 lock * @param lock The lock to acquire */ static inline void stm32_lock_acquire(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); } /** * @brief Release ST lock * @param lock The lock to release */ static inline void stm32_lock_release(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); } #elif STM32_THREAD_SAFE_STRATEGY == 4 /* * Allow lock usage from interrupts. Implemented using FreeRTOS locks. */ /* Includes ----------------------------------------------------------------*/ #include <FreeRTOS.h> #include <task.h> #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ /* Private defines ---------------------------------------------------------*/ /** Initialize members in instance of <code>LockingData_t</code> structure */ #define LOCKING_DATA_INIT { {0, 0}, 0 } #define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */ typedef struct { uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS]; uint8_t nesting_level; } LockingData_t; /* Private macros ----------------------------------------------------------*/ /** Blocks execution if reached max nesting level */ #define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock) \ do \ { \ if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri)) \ { \ STM32_LOCK_BLOCK(); \ } \ } while (0) /* Private functions -------------------------------------------------------*/ /** * @brief Initialize STM32 lock * @param lock The lock to init */ static inline void stm32_lock_init(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++) { lock->basepri[i] = 0; } lock->nesting_level = 0; } /** * @brief Acquire STM32 lock * @param lock The lock to acquire */ static inline void stm32_lock_acquire(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR(); } /** * @brief Release STM32 lock * @param lock The lock to release */ static inline void stm32_lock_release(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); lock->nesting_level--; STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]); } #undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL #undef STM32_LOCK_MAX_NESTED_LEVELS #elif STM32_THREAD_SAFE_STRATEGY == 5 /* * Deny lock usage from interrupts. Implemented using FreeRTOS locks. */ /* Includes ----------------------------------------------------------------*/ #include <FreeRTOS.h> #include <task.h> #if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 #warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe #endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ /* Private defines ---------------------------------------------------------*/ /** Initialize members in instance of <code>LockingData_t</code> structure */ #define LOCKING_DATA_INIT 0 /* Private typedef ---------------------------------------------------------*/ typedef uint8_t LockingData_t; /**< Unused */ /* Private functions -------------------------------------------------------*/ /** * @brief Initialize STM32 lock * @param lock The lock to init */ static inline void stm32_lock_init(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); } /** * @brief Acquire STM32 lock * @param lock The lock to acquire */ static inline void stm32_lock_acquire(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); vTaskSuspendAll(); } /** * @brief Release STM32 lock * @param lock The lock to release */ static inline void stm32_lock_release(LockingData_t *lock) { STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); xTaskResumeAll(); } #else #error Invalid STM32_THREAD_SAFE_STRATEGY specified #endif /* STM32_THREAD_SAFE_STRATEGY */ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* __STM32_LOCK_H__ */
I have attached the autogenerated files containing the libc locking glue code. I can certainly update these if there are partial definitions which result in the doubly-defined symbol error. However, the code generator which emits these might also need updating to match. Are these what you would expect for a custom implementation of the locking interface?
Thanks,
Roger
I have double-checked this and I don't see any missing functions or lock structures:
Newlib locking ============== In Cygwin lock.c: Variables (struct __lock) __lock___sfp_recursive_mutex __lock___atexit_recursive_mutex __lock___at_quick_exit_mutex __lock___malloc_recursive_mutex __lock___env_recursive_mutex __lock___tz_mutex __lock___dd_hash_mutex __lock___arc4random_mutex Functions __retarget_lock_init __retarget_lock_init_recursive __retarget_lock_close __retarget_lock_close_recursive __retarget_lock_acquire __retarget_lock_acquire_recursive __retarget_lock_try_acquire __retarget_lock_try_acquire_recursive __retarget_lock_release __retarget_lock_release_recursive GCC 12.2 newlib: $ nm c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+dp/hard/libc_nano.a | grep __retarget | sort | uniq U __retarget_lock_acquire U __retarget_lock_acquire_recursive U __retarget_lock_close_recursive U __retarget_lock_init_recursive U __retarget_lock_release U __retarget_lock_release_recursive 00000001 T __retarget_lock_acquire 00000001 T __retarget_lock_acquire_recursive 00000001 T __retarget_lock_close 00000001 T __retarget_lock_close_recursive 00000001 T __retarget_lock_init 00000001 T __retarget_lock_init_recursive 00000001 T __retarget_lock_release 00000001 T __retarget_lock_release_recursive 00000001 T __retarget_lock_try_acquire 00000001 T __retarget_lock_try_acquire_recursive $ nm c:/progra~2/armgnu~1/12dbab~1.2re/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7e-m+dp/hard/libc_nano.a | grep __lock | sort | uniq U __lock___arc4random_mutex U __lock___at_quick_exit_mutex U __lock___atexit_recursive_mutex U __lock___env_recursive_mutex U __lock___malloc_recursive_mutex U __lock___sfp_recursive_mutex U __lock___tz_mutex 00000000 B __lock___arc4random_mutex 00000000 B __lock___at_quick_exit_mutex 00000000 B __lock___atexit_recursive_mutex 00000000 B __lock___dd_hash_mutex 00000000 B __lock___env_recursive_mutex 00000000 B __lock___malloc_recursive_mutex 00000000 B __lock___sfp_recursive_mutex 00000000 B __lock___tz_mutex STM32 lock implementation: $ nm ThreadSafe/newlib_lock_glue.c.obj | grep __retarget | sort | uniq 00000001 T __retarget_lock_acquire 00000001 T __retarget_lock_acquire_recursive 00000001 T __retarget_lock_close 00000001 T __retarget_lock_close_recursive 00000001 T __retarget_lock_init 00000001 T __retarget_lock_init_recursive 00000001 T __retarget_lock_release 00000001 T __retarget_lock_release_recursive 00000001 T __retarget_lock_try_acquire 00000001 T __retarget_lock_try_acquire_recursive $ nm ThreadSafe/newlib_lock_glue.c.obj | grep __lock | sort | uniq 00000000 B __lock___arc4random_mutex 00000000 B __lock___at_quick_exit_mutex 00000000 B __lock___atexit_recursive_mutex 00000000 B __lock___dd_hash_mutex 00000000 B __lock___env_recursive_mutex 00000000 B __lock___malloc_recursive_mutex 00000000 B __lock___sfp_recursive_mutex 00000000 B __lock___tz_mutex
I've checked the newlib lock.c source, the symbols in the C library (arm-none-eabi/12.2.1/thumb/v7e-m+dp/hard/libc_nano.a) and in the STM32 generated code (newlib_lock_glue.c). The functions and data symbols are identical in all of them.
The symbols in libc_nano.a are not weak. Will this result in a doubly-defined symbol error if every symbol within the object file is defined elsewhere? Looking at the specific object file in the libc_nano.a archive:
$ nm ./libc_a-lock.o 00000000 b $d 00000000 b $d 00000000 b $d 00000000 b $d 00000000 b $d 00000000 b $d 00000000 b $d 00000000 b $d 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 t $t 00000000 B __lock___arc4random_mutex 00000000 B __lock___at_quick_exit_mutex 00000000 B __lock___atexit_recursive_mutex 00000000 B __lock___dd_hash_mutex 00000000 B __lock___env_recursive_mutex 00000000 B __lock___malloc_recursive_mutex 00000000 B __lock___sfp_recursive_mutex 00000000 B __lock___tz_mutex 00000001 T __retarget_lock_acquire 00000001 T __retarget_lock_acquire_recursive 00000001 T __retarget_lock_close 00000001 T __retarget_lock_close_recursive 00000001 T __retarget_lock_init 00000001 T __retarget_lock_init_recursive 00000001 T __retarget_lock_release 00000001 T __retarget_lock_release_recursive 00000001 T __retarget_lock_try_acquire 00000001 T __retarget_lock_try_acquire_recursive
I don't see any additional public symbols which would be confounding things here.
Unless I'm missing something very obvious, I can't see any cause for the linker error here, and this has left me somewhat confused.
If you have any suggestions for what else might be at fault here, I would certainly be very grateful.
Kind regards,
This turned out to be an odd issue with the linker. I made this change:
- -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group + -Wl,--gc-sections -static
For some reason (I'll need to dig further), this was being placed on the linker command-line before the application object files and any linked libraries, and that was the cause of the linker error. Removing it resolves this problem.
Ahhh nicely done! Yea I'd confirmed what you'd said about the symbols being identical, but never got around to experimenting with linker command line setups.It makes sense that this is the cause of the propblem we were seeing, though -- the {start/end}-group options would cause a loop where the linker would try to resolve all symbols it can from within the group, so that was pulling in the fault-stub library definitions before the overrides. Better practice would be to only do such grouping right at the end of the linker command line