# ARM Hochsprache Strukturen ## Unterprogrammtechnik - wird durch `bl Unterprogramm` aufgerufen - _Unterprogramm_ muss zu dem Zeitpunkt bereits ein bekanntes Label sein | Blatt-Routinen | Nicht-Blatt-Routinen | |--------------------------------|--------------------------| | rufen keine Unterprogramme auf | rufen Unterprogramme auf | ## Unterprogrammaufruf ![image_482.png](image_482.png) ## Indirekte Unterprogrammaufrufe - Falls Adresse zur Compilezeit nicht bekannt ist - Annahme: aufzurufende Programmadresse steht in r0 - `mov lr, pc` - `mov pc, r0` - Durch Pipelining entsteht im PC die aktuelle Bitadresse +8 - Da jeder Befehl Länge von 4 Byte hat - Linkregister zeigt auf Rücksprungadresse ## ARM Procedure Calling Standard (APCS) - Schnittstelle zwischen Programmteilen - Wie werden Parameter an Unterprogramme übergeben - Welche Register dürfen zerstört werden - Wie werden Ereignisse zurückgegeben - Wie sieht das Stackframe eines Unterprogramms aus ### Konvention zur Parameterübergabe von 32Bit-Daten - ![image_483.png](image_483.png) - Parameter 1-4 werden in den Registern r0-r3 übergeben - Rückgabewert von Funktionen steht im Register r0 oder r0/r1 - Register r0-r3 und Register ip sind Scratch Register - Inhalt darf im Unterprogramm zerstört werden - Informationen in r4-r10, fp, sp müssen erhalten werden - Inhalt von lr wird zur Rückkehr ins aufrufende Programm benötigt ## Parameterübergabe bei anderen Prozessoren (CISC) - ![image_484.png](image_484.png) - Übergabe in Registern typisch für Load/Store-Architekturen - vermeidet Zugriffe auf Speicher - Andere Prozessoren verwenden Stack - Parameter - Rücksprungadresse (PC) - Ergebnis im ACC zurückgeben ## Blatt-Funktionen - können lokale Variablen in Scratch-Registern speichern - Rückkehradresse kann im Linkregister bleiben - ![image_485.png](image_485.png) ## Nicht-Blatt-Funktionen - Linkregister wird durch neue Rücksprungadresse überschrieben - vorher auf Stack retten - Scratchregister dürfen durch neues Unterprogramm frei verwendet werden - keine lokalen Variablen speichern - Variablenregister verwenden - von Anfang an auf Stack - ![image_486.png](image_486.png) ## Unterprogramm - Unterprogrammaufruf mit Parameterübergabe - Dokumentation - Übergabewerte & lokale Variablen - Eingangsprüfung Parameter - ggf. Abbruch - ggf. Register retten - Initialisation Rückgabeparameter, lokale Variablen - Programmkörper beachten - Anweisungen, Schleifen, Verzweigungen: Grenzfälle der Indizes - Speicherzugriffe passend zur Datengröße - ggf. Register restaurieren - Rückgabewert setzen - Rücksprung ## Operanden in Ausdrücken - Argument im Register - Argument auf dem Stack - Stackpointer - Relative Adressierung - Stackpointer + Offset - Als Konstante im Literal-Bereich der Prozedur - PC-relative Adressierung mit Offset - Als lokale Variable - liegt im Stack - Zugriff relativ zum Stack-Pointer / Frame-Pointer mit LDR - Als globale Variable - liegt im statischen Datenbereich im Speicher - Adresse liegt relativ zur statischen Basisadresse - Zeiger - Array - Kurzschreibweise für Zeiger + Offset ## Kontrollfluss ### IF-ELSE ![image_487.png](image_487.png) ### Switch ![image_488.png](image_488.png) ```c++ int testswitch( int a, int* b, int c ) { switch (a) { case 0: *b = 0; break; case 1: if ( c > 100 ) *b = 0; else *b = 3; break; case 2: *b = 1; break; case 3: break; case 4: *b = 2; break; } } ``` ### While ![image_489.png](image_489.png) ### Do-While ![image_490.png](image_490.png) ### For ![image_491.png](image_491.png) ```c++ void testfor( int a[]) { for (int i = 0; i < 10; i++){ a[i] = 0; } } ``` ## Objekte, (virtuelle) Methoden ### Methodenaufrufe bei Objekten - Methode bekommt als ersten Parameter immer einen Zeiger auf das betreffende Objekt (this) - Zugriff auf Daten des Objektes gewährleistet ### Statischer Objektaufruf - Falls Methoden einer Klasse nicht virtuell - Compiler kann zur Compile-Zeit schon Klasse bestimmen und Adresse der Methode einsetzen ### Dynamischer Methodenaufruf - ![image_492.png](image_492.png) ## Beispiele Assemblerprogramme ### my_max ```c++ #include void my_max(int a, int b, int* c) {} if (a > b) *c = a; else *c = b; } ``` #### my_max ohne Optimierung ![image_493.png](image_493.png) #### my_max mit Optimierung ![image_494.png](image_494.png)