cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 weak exception handler override in ASM not working (ARM-EABI-GCC)

Pavel Krupets
Associate III

Hello,

I think I tried almost everything. I couldn't find an easy portable way of overriding weak exception handlers when I write my handlers in ASM.

If I declare and export function in ASM it is simply ignored and weak one is used. Two ways I found of fixing it are:

  • remove weak function declaration in startup_stm32l496xx.s
  • add the following code in C:

extern void SVC_Handler(void);
void(*SVC_Handler_fp)(void) = &SVC_Handler;

9 REPLIES 9

I'd decompose this further, but don't have the patience, suspect it is the .global and .type that are most critical

	.section	.text.SVC_Handler,"ax",%progbits
	.align	1
	.global	SVC_Handler
	.thumb
	.thumb_func
	.type	SVC_Handler, %function
SVC_Handler:
	.cfi_startproc
 
	bx	lr /* your code here */
 
	.cfi_endproc
	.size	SVC_Handler, .-SVC_Handler

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Pavel Krupets
Associate III

Not working :(

Default SVC_Handler is being called.

Can it be because startup_stm32l496xx.s file and my ASM file are in different libraries (.a)?

Oh. Maybe order of libraries matter.

Pavel Krupets
Associate III

I can call function declared in ASM from C no problem so linker sees them fine. Just some bug with weak. Maybe it's a linker issue in ARM-EABI-GCC.

GCC v7.2

LD 2.29

Well it causes multiple definitions as a .s file if the body is left in stm32h7xx_it.c. If the body is removed there the linker binds it over the weak definition in the startup_stm32743xx.s

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

I don't have stm32h7xx_it.c at all. I defined mine in *.s file:

https://github.com/robot-corral/mazebot/blob/master/software/common/lib-det-os/src-asm/svc_handler.S

default weak one is in:

https://github.com/robot-corral/mazebot/blob/master/software/common/lib-stm32l4/src/startup_stm32l496xx.s

Was fighting this problem for quite a while. Might add manual make build using GCC. I was using VisualGDB to make things faster.

>>I don't have stm32h7xx_it.c at all. 

No doubt, I was using some other existing build to determine what it took to get closure with the linker and prove the assembler code in foo.s got pulled in over weak functions in startup.s, and would clash with existing non-weak definitions elsewhere.

Problem with libraries is that the linker can be very selective about what it sees, and multiple instances of very similar code can be put in a library.

I would watch for ordering and precedence rules the linker might apply, and would assume the closure is not a multi-pass affair. I'm not a heavy user of the GNU chain, but would suspect the behaviour is not a bug but rather an issue with expectations.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

> Can it be because startup_stm32l496xx.s file and my ASM file are in different libraries (.a)?

Linkers (including the GNU linker) treat libraries in a different way than they treat objects, even if the libraries appear to be only a collection of objects. This has both rational and historical reasons and I am yet to see a concise document outlining all the linker idiosyncrasies in historical context. One of the underlying (unwritten) idea is, that users are not supposed to create libraries, they are supposed to stick with objects, libraries are to be a domain of system creators. Nevertheless, users are often caught with unpleasant surprise when they move their objects into libraries to find that the result is quite different from what it used to be with standalone objects.

Here, in particular, the fact, that linkers don't search for symbols in libraries if they were already fulfilled, weak or not, is probably the surprising factor. The probable reason for this is the (unwritten, again, and with historic roots too) rule that you should be always able to override library functions with your own version (because of the potentially buggy library one); and the weak/strong mechanism is supposed to help resolving a similar problem entirely in the user (objects) domain.

Other such factor is that linkers don't iterate when searching for a symbol in libraries (unless forced to do so by some set of command-line switches), ie. if there's a new symbol found in the library (or, in a more rare case in an object linked *after* having linking libraries) it can't be fulfilled by a definition from a library linked earlier (but it can be fulfilled by a user definition, even if objects were liked earlier). The visible effect is, that library ordering in command line (and/or specs) does matter, and sometimes manual reordering or overriding specs-given ordering results in surprising faults.

So, the short answer is, don't make libraries from your objects, whatever good reason you think you might have for this.

JW

And if the linkers do multiple passes they frequently create circular dependencies or oscillations, which are significantly harder to manage or remedy.

The goals the embedded linker is shooting for are linear processing and dead code elimination.

There are cleverer tools available, but generally you're going to have to pay for the engineering required to write, support and maintain them.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
c:\SysGCC\arm-eabi\bin\arm-eabi-g++.exe -o ../../../VisualGDB/Release/det-os-example-stm32l496ze -Wl,-gc-sections -TC:/Users/USAGu/AppData/Local/VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32/STM32L4xxxx/LinkerScripts/STM32L496ZG_flash.lds --specs=nano.specs --specs=nosys.specs  -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mcpu=cortex-m4  -Wl,--start-group VisualGDB/Release/main.o ../../../VisualGDB/Release/lib-det-os-stm32l496ze.a ../../../VisualGDB/Release/lib-stm32l496ze.a -Wl,--end-group

Library with the strong definition (lib-det-os-stm32l496ze.a) comes first. But weak definition still wins.

VisualGDB/VS seem to produce proper order, I can even reverse it in project dependencies, but so far nothing helps.

Thanks guys for your help! Will try to fix that stuff.