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?
/** ****************************************************************************** * @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