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...
Så
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?
GnuArm kompilerar fel för ARM9?
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!
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:
Hur kan man lösa detta problemet?
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
}
Problem löst
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.
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.