2

I debug STM32 project created with CMake. It uses HAL library and at the beginning I configure HAL and SysTick.

root/
├─ core/
│  ├─ core.c
│  ├─ core.h
│  ├─ stm32g4xx_it.c
│  ├─ stm32g4xx_it.h
│  ├─ CMakeLists
├─ main.c
├─ startup.s
├─ CMakeLists.txt

startup.s file contains weak SysTick_Handler, as follows:

.weak   SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler

stm32g4xx_it.c also contains SysTick_Handler which overrides weak declaration. The problem is when compile, link and load the app as it looks like above, SysTick interrupt ends in Default_Handler. If I remove weak declaration from startup.s file, then it works properly and correct handler function is executed. I think this is a result of how cmake works. In the root directory there's a main CMakeLists.txt file which compiles startup.s and main.c files, then links core library. The correct SysTick handler is placed in the core library, thus compilation of startup.s file "doesn't see" the other implementation of this handler function. What is the correct yet elegant approach to solve it?

Another question which comes to my mind is how should I write code for other interrupt handlers and how to link them in CMake building system? Let's say I have a UART module and that module has its own interrupt handlers. Should I create a separate library which is based on startup.s file and link all other modules which have interrupt handlers to it? I thought CMake should make building more transparent, readable and easy but that way it looks more like spaghetti. Probably I'm missing something...


EDIT 4/14/2021

I found out that the problem is only related to startup asm file. For example, I can create a weak function symbol in main.c, e.g.:

__attribute__((weak)) void SystemInit(void)

In the core library, in core.c I create function:

void SystemInit(void)

then after compilation and linking the correct function from core.c is used. So it looks like there's something strictly related to asm file here.

VIPPER
  • 326
  • 4
  • 24
  • I would suggest that perhaps stm32g4xx_it is application specific and doesn't belong in the library. Is the copy of stm32g4xx_it.o from the library being included in the build at all? On the other hand startup.o doesn't change from application to application and might make sense to be in a library. – Tom V Apr 11 '21 at 18:43
  • It looks like I hit the same problem as described here: https://jonathanhamberg.com/post/gcc-archive-linker-oddity/. Other possible solution, I think, would be to use OBJECT libraries, as described here: https://www.scivision.dev/cmake-object-libraries/. However there's one small problem in my case. My HAL library is created with a lot of small, single file based libraries, as proposed in https://github.com/ObKo/stm32-cmake. All these HAL libraries have the same common HAL file in dependency which mean there will multiple objects of the same file created... and that causes another problem. – VIPPER Apr 11 '21 at 21:13
  • The solution with an additional startup library doesn't work – VIPPER Apr 11 '21 at 21:31

1 Answers1

1

The reason for such linker behavior is the fact it treats libraries in different way. When it finds weak symbol in source files, it stops looking for the same symbols in libraries. The reason for that is libraries provides some functionalities and developers should be able to override these functionalities to align them with own projects.

There's no need to use libraries in embedded projects for microcontrollers. I found it causes more pain. Some developers doesn't use libraries add_library() in their CMakeLists.txt. I don't find it very reasonable while using CMake. It's used to better organize project files and manage dependencies between modules.

The problem here can be simply solved with use OBJECT libraries. That type of link has been added to target_link_libraries in the version of 3.12. I think it has been added for the microcontroller projects specifically and it really works excellent.

VIPPER
  • 326
  • 4
  • 24