EmbeddedRelated.com
Forums
Memfault Beyond the Launch

{To TomW} GCC-Bug in IRQs

Started by Sten March 25, 2006
David Hawkins wrote:
>>YES, something like that! ;-) But without nesting and change of cpu-mode.
> Then perhaps this :)
>
> irq_isr:
> sub lr, lr, #4
> stmfd sp!, {r0-r3, ip, lr}
> bl irq_handler
> ldmfd sp!, {r0-r3, ip, pc}^
> /* VICVectAddr dispatch loop */
> void irq_handler(void)
> {
> /* Process IRQ interrupts */
> irq_handler_t handler;
> while (VICIRQStatus) {
> /* Get the address of the highest priority handler */
> handler = (irq_handler_t)VICVectAddr;
>
> /* Execute the handler */
> (*handler)();
>
> /* Acknowledge the VIC */
> VICVectAddr = 0;
> }
> }
>

Wonderful! ;-)
But why to save r0..r3 and ip in your irq_isr?!? Only lr will be changed by bl and registers used by
irq_handler() should be saved in its function prologue by irq_handler() itself!

Sten
--
/************************************************
Do you need a tiny and efficient real time
operating system (RTOS) with a preemtive
multitasking for LPC2000 or AT91SAM7?

http://nanortos.net-attack.de/

Or some open-source tools and code for LPC2000?

http://www.net-attack.de/

************************************************/

Yahoo! Groups Links

An Engineer's Guide to the LPC2100 Series

Marko Panger wrote:
> Hi Sten,
>
> I was experiencing the same GCC bug as you encountered. It came out only
> with optimization enabled.
>
> I've searched around I and discovered that there seems to be some
> patches out there but all of them are not 100% confirmed as working
> patches. I read about the patches on bugzilla. After that I decided that
> is better for me not to apply unconfirmed patches and I simply tricked
> GCC by calling the "ISR_Body()" function from my ISR.
>
> Like you I was also surprised that this bug has not been still fixed.
>
> Regards,
> marko
>
>
> Sten wrote:
>
>
>>Tom Walsh wrote:
>>
>>
>>
>>>Sten wrote:
>>>
>>>
>>>
>>>
>>>
>>>>Tom Walsh wrote:
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>Sten wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>>Hello Tom,
>>>>>>
>>>>>>some days ago I discovered a GCC bug on interrupt service routines for functions with
>>>>>>__attribute__((interrupt("IRQ"))). At GCC-Bugzilla I found that this bug has still been reported in
>>>>>>2005 under bug report #16634 in which you are involved in. Do you know why this bug is still
>>>>>>"UNCONFIRMED"?!?
>>>>>>
>>>>>>The bug still persists in:
>>>>>>arm-elf-gcc (GCC) 4.0.1
>>>>>>arm-elf-gcc (GCC) 4.1.0
>>>>>>
>>>>>>Do you (or somebody else) have a gcc-patch to solve this problem? I took a look to the gcc sources
>>>>>>by myself but the problem occurs in conjunction with optimization under conditions, where LR
>>>>>>register is used for subroutine branches, and this could a little bit more tricky to solve it than
>>>>>>just hacking the ARM section of GCC!
>>>>>>
>>>>>>Can somebody confirm this bug in the binary-tool-chain from www.gnuarm.com or on other GCC-based
>>>>>>cross compiler versions? It seems gnuarm don't have any special patches against this problem, too.
>>>>>>(See test-case below!)
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>I am not sure what your question is. Why do you feel you have to
>>>>>intentionally suppress the apcs stack frame?
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>With -mapcs-frame the code produced looks good but due to the APCS a lot of overhead at entry and
>>>>exit of my functions is generated. Without that option (or with -mno-apcs-frame) gcc generates wrong
>>>>entry/exit code but the code footprint is more slim.
>>>>In my opinion an arm-elf-gcc should produce correct code for ARM cores in any case.
>>>>
>>>>GCC manual says for ARM option -mapcs-frame:
>>>>"Generate a stack frame that is compliant with the ARM Procedure Call Standard for all functions,
>>>>even if this is not strictly necessary for correct execution of the code."
>>>>
>>>>My question was if you know something about the detailed status of bug report #16634? I'm wondering
>>>>why it is still UNCONFIRMED since 2005.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>>No, I don't. AFAIK, the apcs frame is used for backtracing code. So
>>>far, the Insight debugger has been fine for backtracing with the options
>>>I specify for compiles:
>>>
>>>arm-elf-gcc -c -O0 -mthumb -mcpu=arm7tdmi -march=armv4t
>>>-DTOPLEVEL=/home/tom/MuxPad3Devel/EvntCPU/../ -I. -gstabs -DROM_RUN
>>>-I/home/tom/MuxPad3Devel/EvntCPU/../include
>>>-I/home/tom/MuxPad3Devel/EvntCPU/../libs/include -Wall
>>>-Wstrict-prototypes -Wcast-align -Wcast-qual -Wimplicit
>>>-Wmissing-declarations -Wmissing-prototypes -Wnested-externs
>>>-Wpointer-arith -Wswitch -Wredundant-decls -Wreturn-type -Wshadow
>>>-Wstrict-prototypes -Wunused -Wa,-adhlns=main2138.lst -std=gnu99
>>>-nostdlib -nodefaultlibs
>>>-L/home/tom/devtools/armThumb-4.0.2/arm-elf/lib/thumb/interwork/
>>>-L/home/tom/devtools/armThumb-4.0.2/lib/gcc/arm-elf/4.0.2/interwork/ -MD
>>>-MP -MF .dep/main2138.o.d -DLPC2138
>>>-I/home/tom/MuxPad3Devel/EvntCPU//include -DLPC2138 main2138.c -o
>>>main2138.o
>>>
>>>I am not optimizing as yet for two reasons:
>>>
>>>1. I have adequate codespace, yet.
>>>2. It is a nightmare to debug optimized code!
>>>
>>>
>>>
>>
>>Ok, that's the reason! I explored that it happens only in conjunction with optimization options. It
>>seems that gcc is mixing up optimized code with non-optimized.
>>
>>Sometimes gcc results in very neat optimized code like this:
>>irq:
>> sub lr, lr, #4
>> stmdb sp!, {r1,r2,lr}
>> ...
>> ldmia sp!, {r1,r2,pc} @ loading pc with lr-4 directly from stack
>>
>>or in the default code recommended in ARM manual:
>>
>>irq:
>> stmdb sp!, {r1,r2,lr}
>> ...
>> ldmia sp!, {r1,r2,lr}
>> subs pc, lr, #4
>>
>>The erronous output when optimizing looks like a mixture of both:
>>
>>irq:
>> sub lr, lr, #4
>> stmdb sp!, {r1,r2,lr}
>> ...
>> ldmia sp!, {r1,r2,lr}
>> subs sp, lr, #4
>>
>>Has nobody else recognized this?!?
>>
>>Regards.
>> Sten
>>
>>
>>

Hello Marko,

do you still know where you to find these patches? I would take a look into, because I started to
search the gcc sources for the root of this problem. Maybe there is a simple patch which do not
touch sensible code in gcc. To fix something in the ARM section of GCC would be more easy, but the
fact that this occurs along with optimization makes it very tricky!

Sten

--
/************************************************
Do you need a tiny and efficient real time
operating system (RTOS) with a preemtive
multitasking for LPC2000 or AT91SAM7?

http://nanortos.net-attack.de/

Or some open-source tools and code for LPC2000?

http://www.net-attack.de/

************************************************/


> I'm thinking of writing a generic IRQ handler instead of a
> direct branch to VIC-vector register from vector table,

You mean something like this ....

irq_isr:
/* Save IRQ context, including the APCS registers, and r4-6 */
sub lr, lr, #4
stmfd sp!, {r0-r6, ip, lr}

/* Save the SPSR_irq register */
mrs r4, spsr

/* Read the VICVectAddr */
ldr r5, VICVECTADDR
ldr r6, [r5]

/* Change to SYS mode and enable IRQ */
msr cpsr_c, #SYS_MODE

/* Debug:
* Comment out the change to system mode with IRQs enabled
* and uncomment the following to leave IRQs disabled. IRQs
* are then handled non-nested (with more overhead than normal)
*/
/* msr cpsr_c, #SYS_MODE|IRQ_DISABLE*/

/* Save the banked SYS mode link register */
stmfd sp!, {lr}

/* Call the C-coded handler */
mov lr, pc
mov pc, r6

/* Restore SYS mode link register */
ldmfd sp!, {lr}

/* Change to IRQ mode and disable IRQ */
msr cpsr_c, #IRQ_MODE|IRQ_DISABLE

/* Restore the SPSR */
msr spsr, r4

/* Acknowledge the VIC */
mov r0, #0
str r0, [r5]

/* Restore IRQ context and return from interrupt */
ldmfd sp!, {r0-r6, ip, pc}^

VICVECTADDR: .word 0xFFFFF030

At 09:33 PM 3/25/2006 +0100, Sten wrote:
>Robert Adsett wrote:
> > At 08:17 PM 3/25/2006 +0100, Sten wrote:
> >
> >>Robert Adsett wrote:
> >>
> >>>Rather than go through all this hand-wringing why not just write an
> >>>assembly stub? You'd know it was correct and you'd be done already. At
> >>>most it would cost you an extra call from the stub to your C
> >>>function. Heck if it was small enough it might make sense to do the whole
> >>>thing in asm. For that matter you could steal one of my stubs.
> >>
> >>At the moment I declare my IRQ functions as "naked" and write my own
> >>prologue/epilogue with inline
> >>assembler. But it is less efficient because I don't know which registers
> >>are really used, so I have
> >>to save all non-banked registers (r0..12 for IRQ and r0..r7 for FIQ) which
> >>is a wast of performance.
> >
> >
> >
> > If you write a stub that problem disappears. The procedure call standard
> > ensures that the proper registers are saved when you call out of the stub.
> > You only have to save something like 6 registers for IRQ, the called
> > routine preserves any of the others it uses..
> >
> > Also are you sure you actually really care about the extra saves? Beware
> > of premature optimization. Didn't Knuth call it the root of all evil?
> > :) If your response time is sufficient and your are not overloading the
> > CPU forget about the wasted cycles, you are spending time doing something
> > that simply does not matter.
> >
> > I do a stub not for efficiency but because experience has taught me to
> > never trust any compiler to produce correct interrupt code. Correct does
> > sometimes mean efficient but it can also mean the more obvious things.
> >
> > Robert
>
>Ok, what exactly did you mean by a "stub"? You write a piece of assembler
>code for a particular IRQ
>and then branch to your (normal) C service function, don't you?

As a matter of fact, yes. That would be a stub.

>I'm thinking of writing a generic IRQ handler instead of a direct branch
>to VIC-vector register from
>vector table, I'm using at the moment. This IRQ handler (in clean
>assembler) could have correct
>entry and exit code and is branching to the service function from
>VIC-vector. The overhead would be
>very less.

That would also be a stub. I don't see any reason off hand not to do it
that way although I also don't see that it will change the overhead at all.

branch to irq source specific stub
save registers
call service function

versus

branch to stub
save registers
call irq source specific function

Since you cannot take advantage of the 'wrap-around indexing' into the VIC
table it might even be a little more overhead in the second case. I doubt
it matters in most cases and I can see some real clarity advantages to
doing it that way. Hmmmm....

Robert

" 'Freedom' has no meaning of itself. There are always restrictions, be
they legal, genetic, or physical. If you don't believe me, try to chew a
radio signal. " -- Kelvin Throop, III
http://www.aeolusdevelopment.com/
At 12:04 AM 3/26/2006 +0100, Sten wrote:
>Wonderful! ;-)
>But why to save r0..r3 and ip in your irq_isr?!? Only lr will be changed
>by bl and registers used by
>irq_handler() should be saved in its function prologue by irq_handler()
>itself!

According to the APCS "A (called)subroutine must preserve the contents of
the registers r4-r8, r10, r11 and SP ".

R0-R3 are temporary/parameter registers and must be saved by the caller if
needed R12 is the intra-procedure call scratch register so similar
restrictions apply to it, R14 is the link register so make sure you've
saved it properly or you won't be able to return.

That leaves R9 the platform specific register, which I believe gcc treats
the same as r4-r8 (I can't lay my hands on my reference for that at the
moment).

Robert

" 'Freedom' has no meaning of itself. There are always restrictions, be
they legal, genetic, or physical. If you don't believe me, try to chew a
radio signal. " -- Kelvin Throop, III
http://www.aeolusdevelopment.com/

Yahoo! Groups Links
Robert Adsett wrote:
> At 09:33 PM 3/25/2006 +0100, Sten wrote:
>
>>Robert Adsett wrote:
>>
>>>At 08:17 PM 3/25/2006 +0100, Sten wrote:
>>>
>>>
>>>>Robert Adsett wrote:
>>>>
>>>>
>>>>>Rather than go through all this hand-wringing why not just write an
>>>>>assembly stub? You'd know it was correct and you'd be done already. At
>>>>>most it would cost you an extra call from the stub to your C
>>>>>function. Heck if it was small enough it might make sense to do the whole
>>>>>thing in asm. For that matter you could steal one of my stubs.
>>>>
>>>>At the moment I declare my IRQ functions as "naked" and write my own
>>>>prologue/epilogue with inline
>>>>assembler. But it is less efficient because I don't know which registers
>>>>are really used, so I have
>>>>to save all non-banked registers (r0..12 for IRQ and r0..r7 for FIQ) which
>>>>is a wast of performance.
>>>
>>>
>>>
>>>If you write a stub that problem disappears. The procedure call standard
>>>ensures that the proper registers are saved when you call out of the stub.
>>>You only have to save something like 6 registers for IRQ, the called
>>>routine preserves any of the others it uses..
>>>
>>>Also are you sure you actually really care about the extra saves? Beware
>>>of premature optimization. Didn't Knuth call it the root of all evil?
>>>:) If your response time is sufficient and your are not overloading the
>>>CPU forget about the wasted cycles, you are spending time doing something
>>>that simply does not matter.
>>>
>>>I do a stub not for efficiency but because experience has taught me to
>>>never trust any compiler to produce correct interrupt code. Correct does
>>>sometimes mean efficient but it can also mean the more obvious things.
>>>
>>>Robert
>>
>>Ok, what exactly did you mean by a "stub"? You write a piece of assembler
>>code for a particular IRQ
>>and then branch to your (normal) C service function, don't you?
>
>
> As a matter of fact, yes. That would be a stub.
>
>
>>I'm thinking of writing a generic IRQ handler instead of a direct branch
>>to VIC-vector register from
>>vector table, I'm using at the moment. This IRQ handler (in clean
>>assembler) could have correct
>>entry and exit code and is branching to the service function from
>>VIC-vector. The overhead would be
>>very less.
>
>
> That would also be a stub. I don't see any reason off hand not to do it
> that way although I also don't see that it will change the overhead at all.
>
> branch to irq source specific stub
> save registers
> call service function
>
> versus
>
> branch to stub
> save registers
> call irq source specific function
>
> Since you cannot take advantage of the 'wrap-around indexing' into the VIC
> table it might even be a little more overhead in the second case. I doubt
> it matters in most cases and I can see some real clarity advantages to
> doing it that way. Hmmmm....
>
> Robert
>

You're right, the overhead is exceptable. And it needs less clocks than my current work-around. I
think, I will write a stub tomorrow! ;-)

Sten

--
/************************************************
Do you need a tiny and efficient real time
operating system (RTOS) with a preemtive
multitasking for LPC2000 or AT91SAM7?

http://nanortos.net-attack.de/

Or some open-source tools and code for LPC2000?

http://www.net-attack.de/

************************************************/

David Hawkins wrote:
>>I'm thinking of writing a generic IRQ handler instead of a
>>direct branch to VIC-vector register from vector table,
>
>
> You mean something like this ....
>
> irq_isr:
> /* Save IRQ context, including the APCS registers, and r4-6 */
> sub lr, lr, #4
> stmfd sp!, {r0-r6, ip, lr}
>
> /* Save the SPSR_irq register */
> mrs r4, spsr
>
> /* Read the VICVectAddr */
> ldr r5, VICVECTADDR
> ldr r6, [r5]
>
> /* Change to SYS mode and enable IRQ */
> msr cpsr_c, #SYS_MODE
>
> /* Debug:
> * Comment out the change to system mode with IRQs enabled
> * and uncomment the following to leave IRQs disabled. IRQs
> * are then handled non-nested (with more overhead than normal)
> */
> /* msr cpsr_c, #SYS_MODE|IRQ_DISABLE*/
>
> /* Save the banked SYS mode link register */
> stmfd sp!, {lr}
>
> /* Call the C-coded handler */
> mov lr, pc
> mov pc, r6
>
> /* Restore SYS mode link register */
> ldmfd sp!, {lr}
>
> /* Change to IRQ mode and disable IRQ */
> msr cpsr_c, #IRQ_MODE|IRQ_DISABLE
>
> /* Restore the SPSR */
> msr spsr, r4
>
> /* Acknowledge the VIC */
> mov r0, #0
> str r0, [r5]
>
> /* Restore IRQ context and return from interrupt */
> ldmfd sp!, {r0-r6, ip, pc}^
>
> VICVECTADDR: .word 0xFFFFF030
>

YES, something like that! ;-) But without nesting and change of cpu-mode.

Sten

--
/************************************************
Do you need a tiny and efficient real time
operating system (RTOS) with a preemtive
multitasking for LPC2000 or AT91SAM7?

http://nanortos.net-attack.de/

Or some open-source tools and code for LPC2000?

http://www.net-attack.de/

************************************************/


> YES, something like that! ;-) But without nesting and change of cpu-mode.

Then perhaps this :)

irq_isr:
sub lr, lr, #4
stmfd sp!, {r0-r3, ip, lr}
bl irq_handler
ldmfd sp!, {r0-r3, ip, pc}^
/* VICVectAddr dispatch loop */
void irq_handler(void)
{
/* Process IRQ interrupts */
irq_handler_t handler;
while (VICIRQStatus) {
/* Get the address of the highest priority handler */
handler = (irq_handler_t)VICVectAddr;

/* Execute the handler */
(*handler)();

/* Acknowledge the VIC */
VICVectAddr = 0;
}
}

David Hawkins wrote:
>>YES, something like that! ;-) But without nesting and change of cpu-mode.
>
>
> Then perhaps this :)
>
> irq_isr:
> sub lr, lr, #4
> stmfd sp!, {r0-r3, ip, lr}
> bl irq_handler
> ldmfd sp!, {r0-r3, ip, pc}^
>
>
> /* VICVectAddr dispatch loop */
> void irq_handler(void)
> {
> /* Process IRQ interrupts */
> irq_handler_t handler;
> while (VICIRQStatus) {
> /* Get the address of the highest priority handler */
> handler = (irq_handler_t)VICVectAddr;
>
> /* Execute the handler */
> (*handler)();
>
> /* Acknowledge the VIC */
> VICVectAddr = 0;
> }
> }
>

Wonderful! ;-)
But why to save r0..r3 and ip in your irq_isr?!? Only lr will be changed by bl and registers used by
irq_handler() should be saved in its function prologue by irq_handler() itself!

Sten
--
/************************************************
Do you need a tiny and efficient real time
operating system (RTOS) with a preemtive
multitasking for LPC2000 or AT91SAM7?

http://nanortos.net-attack.de/

Or some open-source tools and code for LPC2000?

http://www.net-attack.de/

************************************************/

At 12:04 AM 3/26/2006 +0100, Sten wrote:
>Wonderful! ;-)
>But why to save r0..r3 and ip in your irq_isr?!? Only lr will be changed
>by bl and registers used by
>irq_handler() should be saved in its function prologue by irq_handler()
>itself!

According to the APCS "A (called)subroutine must preserve the contents of
the registers r4-r8, r10, r11 and SP ".

R0-R3 are temporary/parameter registers and must be saved by the caller if
needed R12 is the intra-procedure call scratch register so similar
restrictions apply to it, R14 is the link register so make sure you've
saved it properly or you won't be able to return.

That leaves R9 the platform specific register, which I believe gcc treats
the same as r4-r8 (I can't lay my hands on my reference for that at the
moment).

Robert

" 'Freedom' has no meaning of itself. There are always restrictions, be
they legal, genetic, or physical. If you don't believe me, try to chew a
radio signal. " -- Kelvin Throop, III
http://www.aeolusdevelopment.com/

Memfault Beyond the Launch