GnuArm kompilerar fel för ARM9?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

GnuArm kompilerar fel för ARM9?

Inlägg av Rick81 »

Jag håller på med ett projekt där en ARM9 kör kod som kompileras med GnuArm (GCC) 4.1.1.

Den kompilerade koden blir inte som den borde.
Av någon anledning så lagras inte r0, r1, r2, r3 på stacken i början på funktioner. Detta gör att när en funktion anropas och den använder r0-r3 så kommer dessa register att ändras utanför funktionen vilket gör att processorn blir väldigt instabil och kraschar till och från.

Exempel:
En funktion borde bli så här:
void Function()
{
stmdb sp!, {r0,r1,r2,r3, lr}
mov r0, #256 ; 0x100
mov r1, #1 ; 0x1
...

Men istället blir den:
void Function()
{
mov r0, #256 ; 0x100
mov r1, #1 ; 0x1
...
Så r0, r1 kommer att få dessa värden där funktionen anropades.

Däremot så lagras alla register efter r3 dvs r4, r5 osv...


void Function()
{
stmdb sp!, {r4,r5, lr}
mov r4, #256 ; 0x100
mov r5, #1 ; 0x1
...
Fungerar utmärkt.

Finns det någon inställning för kompilatorn för att få den att lagra undan r0-r3?

Är det en kompilatorbugg?

Kan det ha något med kodoptimering att göra?
Användarvisningsbild
Earendil
EF Sponsor
Inlägg: 448
Blev medlem: 2 juni 2004, 09:06:43
Ort: Lund

Inlägg av Earendil »

Saken är den att enligt standard anropskonventioner för ARM (ARM EABI) så är just r0-r3 så kallade scratchregister, vilket innebär att ett funktionsanrop alltid kan förstöra dem (alltså, de pushas inte på stacken _inifrån_ funktioner). Vet inte om man forcera kompilatorn att pusha alla register, men det är hur som helst ingen bugg utan helt i sin ordning!
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Inlägg av Rick81 »

Ok.

Jag har ett interupt på Timer3 som kör en funktion via en funktionspekare i interuptfunktionen.

Kan mitt problem bero på att kompilatorn inte vet vilken funktion som kommer köras av funktionspekaren och att den då använder r2,r3 i denna funktion utan att veta att den förstör för föregående?

dvs min kod ser ungefär ut så här:

Kod: Markera allt

Tim3Interupt()
{
   timer.Function();//funktionspekare som sätts när timern startar
}

Function()
{
   TimerExpired = TRUE; // ändrar r2 och r3 utan att lägga dem på stacken
}
Hur kan man lösa detta problemet?
Användarvisningsbild
Andax
Inlägg: 4379
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Inlägg av Andax »

Du kan kanske deklarera TimerExpired som volatile?
Användarvisningsbild
Earendil
EF Sponsor
Inlägg: 448
Blev medlem: 2 juni 2004, 09:06:43
Ort: Lund

Inlägg av Earendil »

Normalt sett så sparar man alla register på stacken när man får ett interrupt. Även scratchregistren. Detta är inget man låter kompilatorn göra (den vet ju inte vad ett interrupt är), utan det får OS:et göra. Har du inget OS i ditt projekt? I så fall måste du fixa till det själv.
Rick81
Inlägg: 755
Blev medlem: 30 december 2005, 13:07:09

Problem löst

Inlägg av Rick81 »

Nej jag har inget OS.

Problemet är nu löst. GnuArm har en bug som gör att återhoppsadressen (lr) vid interrupt minskas med 2*4 byte. Detta är fel och återhoppsadressen ska minskas med 4 byte vid interrupt.

Detta ska göras eftersom interruptet utförs innan instruktionen körs. I en vanlig funktion ska lr inte modifieras eftersom instruktion har körts innan PC hoppar till funktionen.

För att fixa denna bug hade jag gjort egna assembler-macron som sparar undan register på stacken och sedan lämnade tillbaks dem när interruptfunktionen var klar. Dessvärre hade minskningen med 4 byte fallit bort och därför hoppas alltid en instruktion över när interrupt inträffade och skapade en väldigt instabil kod.
Skriv svar