Assemblerprogrammering, ARM-Cortex M4 del 3 Ur innehållet: Fler pekartyper Användning av stacken Lagringsklasser, synlighet - lokala variabler Funktioner - returvärden och parametrar Läsanvisningar: Arbetsbok kap 1 STM32F4xx Cortex M4 programming manual: Kapitel 3.3.7, 3.4.6, 3.4.7, 3.9.4-3.9.5, 3.9.7. Assemblerprogrammering för ARM-Cortex M4 del 3 1
Pekare till pekare Först skapar vi en typ COORD utan att detaljera hur den ser ut (ofullständig deklaration). Därefter kan vi använda en pekare till denna typ i den fullständiga deklarationen EXEMPEL: Vi har deklarationerna: COORD *list,start,end; Koda följande tilldelningar i assemblerspråk list = &start; list->ptr = &end; Vi löser på tavlan... EXEMPEL: Datatyp för koordinater typedef struct coord COORD; typedef struct coord{ int x,y,z; COORD *ptr; } COORD; Assemblerprogrammering för ARM-Cortex M4 del 3 2
Pekare till pekare efter... före... EXEMPEL: Sätt in posten middle mellan posterna start och end: COORD *p = &middle;... list = &start; p->ptr = list->ptr; list->ptr = p; Assemblerprogrammering för ARM-Cortex M4 del 3 3
Pekare till C-funktioner void func(void); /* funktion utan parametrar och returvärde */ void * func(void); /* funktion utan parametrar, returnerar pekare */ void (*func)(void); /* pekare till funktion utan parametrar och returvärde */ EXEMPEL: En parameterlös subrutin init för att initiera hårdvaran i MD407 finns med ingång på adress adress 0x800200 i minnet. Visa hur denna kan anropas: a) från ett C-program b) i assemblerspråk Vi löser på tavlan... Assemblerprogrammering för ARM-Cortex M4 del 3 4
Lagringsklasser och synlighet Variabler med permanent adress i minnet: int gi; /* global synlighet */ static int si; /* synlig i denna källtext */ void sub(void) { static int li; /* synlig i funktionen sub */ } I assemblerspråk: gi:.space 4;.globl gi $si:.space 4; $sub_li:.space 4; Symboler med begränsad synlighet tilldelas unika namn av kompilatorn. Samma namn kan därför användas i olika sammanhang utan konflikt Assemblerprogrammering för ARM-Cortex M4 del 3 5
Permanenta och tillfälliga variabler char gc; gc:.space 1 void sub( void ) { char lc; lc = 5; } Som en direkt följd är variabeln gc åtkomlig hela tiden, i hela programmet medan variabeln lc finns endast i subrutinen sub. sub: push sub add movs strb adds mov ldr bx lr {r7} sp,sp,#12 r7,sp,#0 r3,#5 r3,[r7,#7] r7,r7,#12 sp,r7 r7,[sp],#4 I subrutinen refereras variabeln lc som [r7,#7]. Assemblerprogrammering för ARM-Cortex M4 del 3 6
Stackanvändning lokal variabel sub: push sub add movs strb adds mov ldr {r7} sp,sp,#12 r7,sp,#0 r3,#5 r3,[r7,#7] r7,r7,#12 sp,r7 r7,[sp],#4 prolog epilog Observera att stackens utrymme för lokala variabler ska vara en multipel av 8 Prolog som multipel av 8 Lokala variabler som multipel av 8 bx lr Assemblerprogrammering för ARM-Cortex M4 del 3 7
Parameteröverföring till, och returvärden från subrutiner Parametrar, två metoder kombineras Via register: snabbt, effektivt och enkelt, begränsat antal Via stacken: generellt Returvärden Via register: för enkla datatyper som ryms i processorns register R0 och ev. R1 Via stacken: sammansatta datatyper (poster och fält) Detaljerna styrs av konventioner application binary interface (ABI) Procedure call standard Assemblerprogrammering för ARM-Cortex M4 del 3 8
Användning av register - konventioner Läsanvisning: IHI0042E_aapcs.pdf ("Procedure call standard") Assemblerprogrammering för ARM-Cortex M4 del 3 9
Parameteröverföring via register Konventionerna sägar att vi använder register R0,R1,R2,R3, (i denna ordning) för parametrar som skickas till en subrutin. Övriga parametrar läggs på stacken. EXEMPEL: Följande deklarationer är gjorda: int a,b,c,d; Visa hur följande funktionsanrop kodas i assemblerspråk: sub(a,b,c,d); Vi löser på tavlan... Assemblerprogrammering för ARM-Cortex M4 del 3 10
Tänkbar komplikation: Registerspill" Dvs. register behövs i den anropade subrutinen. Lösning: Skapa tillfälliga variabler använd stacken för temporär lagring sub: @ parametrar finns i register, @ spara dessa på stacken push {r7} sub sp,sp,#20 add r7,sp,#0 str r0,[r7,#12] str r1,[r7,#8] str r2,[r7,#4] str r3,[r7]... Assemblerprogrammering för ARM-Cortex M4 del 3 11
Parameteröverföring via stacken EXEMPEL: Följande deklarationer är gjorda: int a,b,c,d,e; Visa hur följande funktionsanrop kodas i assemblerspråk: sub(a,b,c,d,e); LÖSNING: push {r4,r7,lr} sub sp,sp,#12 add r7,sp,#8...a,b,c,d som tidigare ldr r4,e str r4,[sp] bl sub adds r7,r7,#4 mov sp,r7 pop {r4,r7,pc} Assemblerprogrammering för ARM-Cortex M4 del 3 12
Stackens utseende i sub aktiveringspost Funktionen: void sub(int a,int b,int c,int d,int e); Aktiveringsposten kan sedan utvidgas ytterligare med lokala variabler. Assemblerprogrammering för ARM-Cortex M4 del 3 13
Returvärden via register Storlek C-typ Register 8-32 bitar char/short/int R0 64 bitar long long R1:R0 EXEMPEL: Visa hur följande funktionsanrop kodas i assemblerspråk: int sub(int a) { return a+1; } respektive long long sub(int a) { return a+1; } Vi löser på tavlan... Assemblerprogrammering för ARM-Cortex M4 del 3 14
Returvärden via stack Krävs typiskt då en subrutin ska returnera en komplett post, eller ett helt fält. Den anropande funktionen ska då först reservera utrymme för returvärdet. En pekare till detta utrymme läggs sedan som första parameter vid anropet: typedef struct coord COORD; typedef struct coord{ int x,y,z; COORD *ptr; } COORD; COORD sub( void ) { static COORD start; return start; } GCC genererar följande kod: sub: push {r4,r7} ldr r2,=start mov r4,r0 ldmia r2,{r0,r1,r2,r3} stmia r4,{r0,r1,r2,r3} mov r0,r4 pop {r4,r7} bx lr Assemblerprogrammering för ARM-Cortex M4 del 3 15
Kodningsexempel: Anropssekvens: (formellt): LDR R0,=from LDR R1,=to LDR R2,size BL memcpy void memcpy( unsigned char from[], unsigned char to[], unsigned int size ) { while (size > 0){ size = size - 1; to[size] = from[size]; } } Stackens utseende i memcpy efter prolog Inträde prolog Utträde epilog Assemblerprogrammering för ARM-Cortex M4 del 3 16
"Naiv kodning", av blocken memcpy: memcpy_prolog: push {r7} sub sp,sp,#20 add r7,sp,#0 str r0,[r7,#12] str r1,[r7,#8] str r2,[r7,#4] memcpy_1: ldr r3,[r7,#4] cmp r3,#0 beq memcpy_epilog memcpy_2: ldr r3,[r7,#4] subs r3,r3,#1 str r3,[r7,#4] ldr r2,[r7,#8] ldr r3,[r7,#4] add r3,r3,r2 ldr r1,[r7,#12] ldr r2,[r7,#4] add r2,r2,r1 ldrb r2,[r2] strb r2,[r3] memcpy_epilog: adds sp,sp,#20 pop {r7} bx lr Assemblerprogrammering för ARM-Cortex M4 del 3 17
Kodförbättring, ingen onödig minneanvändning, "förbättrad för hand" Registerallokering: R0: from, ersätter [R7,#12] R1: to, ersätter [R7,#8] R2: size, ersätter [R7,#4] R3: temporär R4: temporär Vi gör dessa substitutioner och kommenterar därefter ut de instruktioner som då blir överflödiga... memcpy: memcpy_prolog: push {r7} sub sp,sp,#20 add r7,sp,#0 str r0,[r7,#12] str r1,[r7,#8] str r2,[r7,#4] memcpy_1: ldr r3,[r7,#4] cmp r3,#0 beq memcpy_epilog memcpy_2: ldr r3,[r7,#4] subs r3,r3,#1 str r3,[r7,#4] ldr r2,[r7,#8] ldr r3,[r7,#4] add r3,r3,r2 ldr r1,[r7,#12] ldr r2,[r7,#4] add r2,r2,r1 ldrb r2,[r2] strb r2,[r3] b memcpy_1 memcpy_epilog: adds sp,sp,#20 pop {r7} bx lr memcpy: memcpy_prolog: push {r4,lr} @ sub sp,sp,#20 @ add r7,sp,#0 @ str r0,[r7,#12] @ str r1,[r7,#8] @ str r2,[r7,#4] memcpy_1: @ ldr r3,[r7,#4] cmp r2,#0 beq memcpy_epilog memcpy_2: @ ldr r3,[r7,#4] subs r2,r2,#1 @ str r3,[r7,#4] @ ldr r2,[r7,#8] @ ldr r3,[r7,#4] mov r3,r0 add r3,r3,r2 mov r4,r1 add r4,r4,r2 @ add r3,r3,r2 @ ldr r1,[r7,#12] @ ldr r2,[r7,#4] @ add r2,r2,r1 ldrb r3,[r3] strb r3,[r4] b memcpy_1 memcpy_epilog: @ adds sp,sp,#20 pop {r4,pc} @ bx lr Assemblerprogrammering för ARM-Cortex M4 del 3 18
så här gör GCC... vår förbättrade kod.. memcpy: memcpy_1: cmp r2,#0 beq memcpy_epilog memcpy_2: subs r2,r2,#1 mov r3,r0 add r3,r3,r2 mov r4,r1 add r4,r4,r2 ldrb r3,[r3] strb r3,[r4] b memcpy_1 memcpy_epilog: pop {r4,pc} GCC-genererad kod (-O2) @void memcpy( unsigned char from[], @ unsigned char to[], @ unsigned int size ) @{ memcpy: @while (size > 0){ cbz r2,.l1 add r1, r1, r2 add r2, r2, r0.l3: @size = size - 1; @to[size] = from[size]; ldrb r3, [r2,#-1]! strb r3, [r1,#-1]! @while (size > 0){ cmp r2, r0 bne.l3.l1: bx lr } } Assemblerprogrammering för ARM-Cortex M4 del 3 19