Sida 1 av 1

GnuArm kompilerar fel för ARM9?

Postat: 9 april 2008, 16:25:15
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?

Postat: 9 april 2008, 20:46:12
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!

Postat: 10 april 2008, 08:57:48
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?

Postat: 10 april 2008, 14:47:11
av Andax
Du kan kanske deklarera TimerExpired som volatile?

Postat: 11 april 2008, 08:56:07
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.

Problem löst

Postat: 11 april 2008, 14:38:37
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.