Assembler-Programmierung Dr.-Ing. Volkmar Sieh Institut für Informatik 3: Rechnerarchitektur Friedrich-Alexander-Universität Erlangen-Nürnberg SS 2011 Assembler-Programmierung 1/48 2012-02-29
Assembler-Programmierung Einleitung Hochsprache (z.b. C, C++, Java, Pascal,...) nicht direkt ausführbar Übersetzung der Hochsprache in die Muttersprache (Maschinensprache) des Rechners symbolische Maschinensprache: Assembler-Code Transformation normalerweise Aufgabe eines Compilers Assembler-Programmierung in Ausnahmefällen: Ausnutzung von Spezialfällen, für die die CPU bessere Befehle kennt Compiler erzeugt schlechten/falschen Code Programmteile, die in Hochsprache nicht programmierbar sind; z.b. I/O-Operationen Interrupt-/Exception-/System-Call-Handler Assembler-Programmierung 2/48 2012-02-29
Assembler-Programmierung Einleitung Assembler-Code-Wissen unverzichtbar für Hardware-Entwurf und -Bewertung Compiler-Bau, Programmiersprachenentwurf Realzeit- und Embedded-System-Programmierung Betriebssystem-Programmierung (auch in Hochsprache!) Programmierung effizienter Algorithmen (auch in Hochsprache!) Programmierung System-naher Programmteile (auch in Hochsprache!) Assembler-Programmierung 3/48 2012-02-29
Assembler-Programmierung Einleitung Konstrukte von Hochsprachen: Konstanten, Variablen und Zugriffe darauf (I/O-Operationen) Arithmetik Kontrollstrukturen Unterprogramme (Interrupts, Exceptions, System-Calls) Zerlegung von Datenzugriffen, arithmetischen Ausdrücken, Schleifen usw. in einfachere Bestandteile Assembler-Programmierung 4/48 2012-02-29
Assembler-Programmierung Variablen Variablen: Zwei Typen von Variablen: Register-Variablen: Variablen, die in der CPU gespeichert werden gekennzeichnet durch ihre Register-Nummer häufig Nummer durch symbolischen Namen ersetzt häufig mit % -Präfix geschrieben (z.b. %r0) nur kleine Anzahl vorhanden... Assembler-Programmierung 5/48 2012-02-29
Assembler-Programmierung Variablen Variablen: Zwei Typen von Variablen:... Speicher-Variablen: Variablen, die ausserhalb der CPU gespeichert werden gekennzeichnet durch ihre Speicherzellennummer (Adresse) häufig Nummer durch symbolischen Namen ersetzt (z.b. buffer) Anzahl der Speicher-Variablen nur durch Speichergröße begrenzt Assembler-Programmierung 6/48 2012-02-29
Assembler-Programmierung Variablen Um Konstanten von Speicherzellennummern zu unterscheiden, werden diese mit $ -Präfix geschrieben. Assembler-Programmierung 7/48 2012-02-29
Assembler-Programmierung Variablen Zusammenfassung: 4: Wert der Variablen in der Speicherzelle mit der Adresse 4 %4: Wert der Variablen in dem Register mit der Nummer 4 $4: Konstante mit dem Wert 4 Assembler-Programmierung 8/48 2012-02-29
Assembler-Programmierung Variablen Zugriff auf Variablen nicht durch Geltungsbereiche o.ä. beschränkt. Parameter-Übergabe bei Unterprogrammaufruf einfach Rückgabe des Result einfach versehentliche Änderungen leicht möglich keine lokalen Variablen (=> Rekursion u.ä. aufwändiger) Register und Speicherzellen haben bestimmte Bit-Breite: kleine CPUs/Mikro-Controller häufig 8-Bit große CPUs häufig 32- oder 64-Bit Assembler-Programmierung 9/48 2012-02-29
Assembler-Programmierung Variablen Reicht Register- bzw. Speicherzellengröße nicht, muss man mehrere Register bzw. Speicherzellen zum Speichern einer Variablen verwenden. Assembler-Programmierung 10/48 2012-02-29
Assembler-Programmierung Variablen Moderne Programmiersprachen kennen Strukturen / Records Arrays sowie Kombinationen davon. Zur Speicherung von Variablen dieser Typen müssen mehrere (normalerweise aufeinander folgende) Speicherzellen verwendet werden. Beispiel: zur Speicherung eines Charakters benötigt man ein Byte zur Speicherung eines Arrays bestehend aus N Charakters benötigt man N Byte (die Struktur geht verloren) Assembler-Programmierung 11/48 2012-02-29
Assembler-Programmierung Variablen Speicher ist eindimensionales Array Problem: wie speichert man mehrdimensionale Arrays? Array mit N Zeilen und M Spalten enthält insgesamt N M Elemente. Diese werden von 0 bis N M 1 durchnummeriert => eindimensionales Array. Beispiel: zweidimensionales Array: int f1[10][5]; int i; int j;... = f1[i][j]; eindimensionales Array: int f2[10 * 5]; int i; int j;... = f2[i * 5 + j]; Assembler-Programmierung 12/48 2012-02-29
Assembler-Programmierung Variablen C-Struktur struct { int8_t c; /* 1 Byte */ int16_t i; /* 2 Bytes */ double f; /* 8 Bytes */ } x; Abbildung auf Speicher Adresse Inhalt N + 0 x.c N + 1 x.i (erstes Byte) N + 2 x.i (zweites Byte) N + 3 x.f (erstes Byte)...... N + 10 x.f (achtes Byte) Assembler-Programmierung 13/48 2012-02-29
Assembler-Programmierung Variablen Folgende Speicher-Operationen stehen i.a. zur Verfügung: datum = load(address); store(address, datum); Die load- bzw. store-funktionalität des Speichers ist auch per CPU-Operation verfügbar direkt als Teil von komplexeren CPU-Operationen Zugriff auf Register i.a. mit beliebigen (Rechen-) Befehlen Assembler-Programmierung 14/48 2012-02-29
Assembler-Programmierung Variablen Beispiele: move $13, %r4 add $5, %r6, %r6 move %r1, %r2 load 14, %r0 add %r4, 1576, %r3store %r14, 1562 In dieser Vorlesung: Quell-Operand(en) stehen links Ziel-Operand steht rechts Assembler-Programmierung 15/48 2012-02-29
Assembler-Programmierung Code Normale Hochsprachen-Programme werden in der Regel sequentiell abgearbeitet. Ähnliches gilt für Assembler-Programme: Befehle ( Befehls-Codes, Code ) stehen im Speicher an aufeinanderfolgenden Adressen Program-Counter (PC) oder Instruction Pointer (IP) enthält die (Start-) Adresse des nächsten, auszuführenden Befehls Assembler-Programmierung 16/48 2012-02-29
Assembler-Programmierung Code Beispiel: Adresse Code symbolischer Code 00000000: 80600001 add $0x1, %r0, %r3 00000001: b463001f shl $0x1f, %r3, %r3 00000002: 80400001 add $0x1, %r0, %r2 00000003: 24020003 store %r2, (%r3) 00000004: 20400003 load (%r3), %r2......... Assembler-Programmierung 17/48 2012-02-29
Assembler-Programmierung Adressierungsarten Beispiel (C, C++, Java): i n t a, b, c [ 1 0 ] ; s t r u c t { char y ; i n t x ; i n t p } d, e, f [ 5 ] ;... = 1 3 ;... = a ;... = b ;... = c [ i ] ;... = d. x ;... = e >x ;... = f [ i ]. x ;... und Kombinationen davon: c [ f [ e >x ]. y ] =... ; f [ b ]. p =... ; a =... ; b =... ; c [ i ] =... ; d. x =... ; e >x =... ; f [ i ]. x =... ; Assembler-Programmierung 18/48 2012-02-29
Assembler-Programmierung Adressierungsarten Bei vielen Adressierungsarten wird eine sogenannte effektive Adresse dynamisch zur Laufzeit berechnet. Gründe (Beispiele): Basisadresse einer Datenstruktur fest, Index variabel (z.b. beim Array-Zugriff) Basisadresse einer Datenstruktur variabel, Displacement bekannt (z.b. beim Zugriff über Pointer auf Records) Assembler-Programmierung 19/48 2012-02-29
Assembler-Programmierung Adressierungsarten Beispiel: Zugriff auf Array-Elemente: short i n t i ; // A d r e s s e 8 short i n t f [ 5 ] ; // A d r e s s e 14 f [ i ] = 3 00; Adresse von i bekannt (8) Adresse von f bekannt (14) Größe der Elemente von f bekannt (2) Adresse(f [i]) = Adresse(f ) + i 2 Assembler-Programmierung 20/48 2012-02-29
Assembler-Programmierung Adressierungsarten Beispiel: Zugriff auf Record-Elemente über Pointer: s t r u c t r e c { short i n t x ; long i n t i ; short i n t y ; short i n t z ; } ; s t r u c t r e c p ; // A d r e s s e 8 s t r u c t r e c s ; // A d r e s s e 14 p >y = 9 ; Adresse von p bekannt (8) Displacement von s.y bezüglich s bekannt (6) Adresse(p > y) = p + 6 Assembler-Programmierung 21/48 2012-02-29
Assembler-Programmierung Adressierungsarten Bei der Ausführung von Befehlen mit Parametern (z.b. Addition zweier Werte) sind folgende Punkte sind zu unterscheiden: wo stehen die eigentlichen Parameter (im Befehl, im Register oder im Speicher) wo stehen die Informationen, wie man an die Parameter kommt (i.a. sind diese Informationen Teil des Befehls) wie berechnet sich die effektive Adresse (wenn die Parameter im Speicher stehen) Assembler-Programmierung 22/48 2012-02-29
Assembler-Programmierung Adressierungsarten Adressierungsarten Überblick: Register Immediate Operand Direct (Absolute) Address Register Indirect Register Indirect with Displacement Register Indirect with Index Register Indirect with Displacement / PC-relative Register Indirect with Index and Displacement Memory Indirect Register Indirect with Pre-/Post-Decrement Register Indirect with Pre-/Post-Increment... Assembler-Programmierung 23/48 2012-02-29
Assembler-Programmierung Adressierungsarten Adressierungsart Register : Beispiele: Register-Name bzw. -Nummer ist Bestandteil des Befehls Operand liegt im Register mov %r3, %r4 add %r3, %r4, %r6 Assembler-Programmierung 24/48 2012-02-29
Assembler-Programmierung Adressierungsarten Adressierungsart Immediate Operand : Beispiele: Operand ist Bestandteil des Befehls mov $14, %r4 add $25, %r4, %r6 Assembler-Programmierung 25/48 2012-02-29
Assembler-Programmierung Adressierungsarten Adressierungsart Register indirekt : Beispiele: Register-Name/-Nummer ist Bestandteil des Befehls Register enthält effektive Adresse Operand liegt im Speicher mov (%r7 ), %r4 add $25, (%r4 ), %r6 Assembler-Programmierung 26/48 2012-02-29
Assembler-Programmierung Adressierungsarten Adressierungsart Register indirekt mit Displacement : Register-Name/-Nummer ist Bestandteil des Befehls Displacement ist Bestandteil des Befehls Register ( Basis-Register ) enthält Basis-Adresse effektive Adresse berechnet sich als Adresse = Basisadresse + Displacement Beispiele: Operand liegt im Speicher mov 14(% r3 ), %r4 add $25, %r4, 4(% r6 ) Assembler-Programmierung 27/48 2012-02-29
Assembler-Programmierung Adressierungsarten Hinweise: nicht alle CPUs können alle Adressierungsarten (insbesondere viele Einschränkungen bei RISC-CPUs und kleinen Mikro-Controllern) nicht alle Adressierungsarten sind mit allen Registern möglich (z.b. ist der Instruction Pointer nicht als Basis-Register erlaubt) nicht alle Kombinationen von Adressierungsarten (Ziel und Quelle) sind möglich (z.b. erlauben viele CPUs keine zwei Speicheroperanden) es existieren i.a. Einschränkungen für die möglichen Werte bzw. die Größe des Displacements einige CPUs erlauben Speicheroperanden nur bei load- und store-befehlen... Assembler-Programmierung 28/48 2012-02-29
Assembler-Programmierung Arithmetik Ziel: Vereinfachung von Ausdrücken Zerlegung der Ausdrücke entsprechend der Grammatik Einführung von temporären Variablen Beispiel: y = (x + 2z)/(z ( x)) t1 = 2 z ; t2 = x + t1 ; t3 = x ; t4 = z t3 ; y = t2 / t4 ; Optimierung =====> t1 = 2 z ; t1 = x + t1 ; t2 = x ; t2 = z t2 ; y = t1 / t2 ; Assembler-Programmierung 29/48 2012-02-29
Assembler-Programmierung Arithmetik Standard-Integer-Rechenbefehle: not, and, or, xor shr, shl, asr, (asl) ror, rol, rcr, rcl neg, add, adc, sub, sbb mul, div, mod... Nicht jede CPU kennt alle Rechenbefehle! Assembler-Programmierung 30/48 2012-02-29
Assembler-Programmierung Arithmetik Ersatz für fehlende Arithmetik-Befehle: Befehl Ersatzbefehl(e) not %r1, %r2 xor $0xffffffff, %r1, %r2 neg %r1, %r2 mov $0, %r2 sub %r1, %r2, %r2 mov $k, %r1 xor %r1, %r1, %r1 add $k, %r1, %r1 mul $4, %r1, %r2 shl $2, %r1, %r2 mul $5, %r1, %r2 shl $2, %r1, %r2 add %r1, %r1, %r2 mod $4, %r1, %r2 and $3, %r1, %r2...... Assembler-Programmierung 31/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Hochsprachen bieten i.a. eine Vielzahl verschiedener Konstrukte zur bedingten und wiederholten Ausführung von Anweisungen. Beispiele: i f (... ) {... } e l s e {... } switch (... ) { case... :... d e f a u l t :... } while (... ) {... } do {... } while (... ) ; f o r (... ;... ;... ) {... } goto... ; l a b e l :...... Assembler-Programmierung 32/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Komplexere Kontrollstrukturen lassen sich auf einfachere zurückführen. Beispiel: f o r ( i = 0 ; i < 1 6 ; i ++) { anw ( ) ; } erster Vereinfachungsschritt: i = 0 ; while ( i < 16) { anw ( ) ; i ++; } Assembler-Programmierung 33/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen i = 0 ; while ( i < 16) { anw ( ) ; i ++; } nächste Vereinfachung: i = 0 ; goto t e s t ; l o o p : anw ( ) ; i ++; t e s t : i f ( i < 16) goto l o o p ; Assembler-Programmierung 34/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Wichtig: Es gibt für alle Programmiersprachen allgemeingültige Regeln, wie komplexe Kontrollstrukturen auf einfachere abzubilden sind! Assembler-Programmierung 35/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Komplizierte Bedingungen lassen sich vereinfachen. Beispiel: i f ( a > b && a!= 0) { anw ( ) ; } erster Vereinfachungsschritt: i f (! ( a > b ) ) goto end ; i f (! ( a!= 0 ) ) goto end ; anw ( ) ; end : ; Assembler-Programmierung 36/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen i f (! ( a > b ) ) goto end ; i f (! ( a!= 0 ) ) goto end ; anw ( ) ; end : ; nächste Vereinfachung: i f ( a <= b ) goto end ; i f ( a == 0) goto end ; anw ( ) ; end : ; Assembler-Programmierung 37/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Generelle Beobachtung: alle bedingten Ausführungen von Anweisungen sowie alle Schleifenkonstrukte lassen sich auf folgende zwei Anweisungs-Typen abbilden: goto label; if (a OP b) goto label; mit OP {<, >, =,! =, <=, >=,...} Assembler-Programmierung 38/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Assembler-Code für unbedingte Sprünge: goto l a b e l ; => jmp l a b e l ; Assembler-Code für bedingte Sprünge: i f ( a OP b ) goto l a b e l ; => jop a, b, l a b e l Assembler-Programmierung 39/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen jop a, b, l a b e l jop erfordert drei Adressen (a, b, label). Zusätzlich: label ist u.u. größere Zahl. Befehl muss daher häufig aufgespalten werden: cmp a, b jop l a b e l Für die Zwischenspeicherung des Vergleichsergebnisses ist ein Register notwendig: Condition-Codes - oder Flags -Register Assembler-Programmierung 40/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen mögliche Bedingungen: = je!= jne < jl >= jge...... Assembler-Programmierung 41/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Auch viele Arithmetik-Befehle setzen die Condition-Codes ( CC ) im Flags-Register; Beispiele: Zero-Flag: gesetzt, wenn Ergebnis 0 ist Negative-/Sign-Flag: gesetzt, wenn das höchstwertige Bit des Ergebnisses 1 ist Carry-Flag: bei Übertrag gesetzt...... cmp-befehl entspricht Subtraktion ohne Speicherung des eigentlichen Ergebnisses Assembler-Programmierung 42/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Statt einer Adresse als Sprungziel wird häufig die Differenz zur Adresse der aktuellen (oder nächsten) Instruktion angegeben (meist eine kleinere Zahl); Beispiel: 0 8 :... 0 9 : j l e 25 1 0 :... => 0 8 :... 0 9 : j l e +16 1 0 :... Assembler-Programmierung 43/48 2012-02-29
Assembler-Programmierung Kontrollstrukturen Vorteile: weniger Speicheraufwand schnellere Befehlsausführung unabhängig von der tatsächlichen Lage des Programms im Speicher ( Position-Independant-Code (PIC)) Nachteile: mühsamere Berechnung (wird meist vom Assembler/Linker übernommen) nicht alle Sprungziele erreichbar (lange Version zusätzlich notwendig) Assembler-Programmierung 44/48 2012-02-29
Assembler-Programmierung Beispiele if (a < b) { cmp a, b jl else sub %r2, %r3, %r0 jl else c = a; } else { c = b; } mov a, c jmp endif else: mov b, c endif: add $0, %r2, %r4 jmp endif else: add $0, %r3, %r4 endif: Assembler-Programmierung 45/48 2012-02-29
Assembler-Programmierung Beispiele for (i = 0; i < 10; i++) { func(i); } i = 0; while (i < 10) { func(i); i++; } Assembler-Programmierung 46/48 2012-02-29
Assembler-Programmierung Beispiele i = 0; while (i < 10) { func(i); i++; } i = 0; goto test; loop: func(i); i++; test: if (i < 10) goto loop; Assembler-Programmierung 47/48 2012-02-29
Assembler-Programmierung Beispiele i = 0; goto test; loop: func(i); i++; test: if (i < 10) goto loop; add %r0, %r0, %r2 jmp test loop: add $0, %r2, %r16 call func add $1, %r2, %r2 test: sub $10, %r2, %r0 jl loop Assembler-Programmierung 48/48 2012-02-29