Grundlagen der Informatik III
Transcription
Grundlagen der Informatik III
Grundlagen der Informatik III WS 2008 / 2009 [Folien basierend auf VL von Prof. Dr. Claudia Eckert, WS 07/08] Prof. Dr. rer. nat. Frederik Armknecht Sascha Müller Daniel Mäurer Fachbereich Informatik / CASED Mornewegstraße 30 64293 Darmstadt Gliederung der Vorlesung GdI 3 1. Einführung 2. Assemblerprogrammierung 3. Leistungsbewertung 4. Speicherhierarchie 5. Assembler, Binder, Lader 6. Betriebssysteme und Ein-/Ausgabe (Grundlagen) 7. Rechnernetze (Grundlagen) 8. Compiler (Grundlagen) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 2 Gliederung dieses Kapitels 2.1 Instruktionssatz 2.2 Variablen und Register 2.3 Speicherorganisation 2.4 Speicherbefehle 2.5 Befehlsformate 2.6 Konzept der universellen Interpretierbarkeit 2.7 Übersetzung von Kontrollstrukturen 2.8 Verarbeitung von Zeichen 2.9 Höhere Kontrollstrukturen: Prozeduren 2.10 Adressierung 2.11 Fazit Ziel: systemnahes Programmieren auf der Assemblerebene unter Nutzung des MARS-Simulators für die MIPS-RISC-Architektur Achtung: Vorlesung ist kein Assemblerkurs; sie erläutert wichtige Prinzipien. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 3 Kapitel 2 Assemblerprogrammierung 2.1 Instruktionssatz (Befehlssatz, instruction set): • Maschinen-Sprache zur Beschreibung der einzelnen Aktionen, die ein Prozessor ausführen kann • so einfach wie möglich gehalten, primitive Sprache Beispiel in Vorlesung: • MIPS-R2000-Instruktionssatz • einfach, bietet alle wichtigen Konzepte Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 4 Instruktionssatz: Schnittstelle (Interface) zwischen Compiler und Rechner High-level language program (in C) swap(int v[], int k) {int temp; temp = v[k]; v[k] = v[k+1]; v[k+1] = temp; } Ccompiler Assembly language program (for MIPS) swap: muli $2, $5,4 add $2, $4,$2 lw $15, 0($2) lw $16, 4($2) sw $16, 0($2) sw $15, 4($2) jr $31 Assembler Binary machine language program (for MIPS) 00000000101000010000000000011000 00000000100011100001100000100001 10001100011000100000000000000000 10001100111100100000000000000100 10101100111100100000000000000000 10101100011000100000000000000100 00000011111000000000000000001000 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 5 MIPS-Arithmetik: Erstes Beispiel „ Addiere die Werte der beiden Variablen ‘b‘ und ‘c‘ und weise das Ergebnis der Variablen ‘a‘ zu “ add a, b, c Assemblerbefehle (instructions) stark formalisiert: • alle Arithmetikbefehle haben genau 3 Variablen: Zwei Argumente und einen Ergebnisoperanden • feste Reihenfolge der Variablen (Ergebnis zuerst) • jede Zeile ein Befehl Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 6 Pseudobefehle Maschinensprache umfasst normalerweise nur eine kleine Anzahl an möglichen Instruktionen Manche Operationen sind nicht direkt implementiert, sondern müssen durch andere realisiert werden. Einige Assembler unterstützen sogenannte Pseudobefehle. Dies sind Befehle, die es in der Maschinensprache nicht gibt, aber häufig gebraucht werden. Der Assembler übersetzt diese dann in eine geeignete Sequenz von „echten“ Assemblerbefehlen. Aus didaktischen Gründen werden wir im Folgenden gelegentlich Pseudobefehle verwenden. Diese sind mit eckigen Klammern markiert. Mehr dazu später … Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 7 Übersetzung einfacher C-Programme C MIPS-Assembler a = b + c; add a, b, c d = a - e; sub d, a, e ... oder etwas komplizierter: f=(g+h)–(i+j) temporäre Variable add t0, g, h add t1, i, j sub f, t0, t1 Beachten von Operator-Prioritäten ( Reihenfolge) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 8 2.2 Variablen und Register Variablen • Unterschied zu höheren Programmiersprachen: Operanden müssen auf begrenzte Anzahl elementarer Speichereinheiten („Register“) des Prozessors abgebildet werden. Register: • Register sind Teile der Programmierer-Schnittstelle • direkt vom Programm aus zugreifbar • besitzen eine feste, identische Länge (Wortbreite), • derzeit typischerweise noch 32 bit (künftig 64 bit) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 9 2.2 Variablen und Register MIPS-Architektur besitzt • 32 Register mit je 32 bit, • Register mit spezieller Funktion: • Register 0 und 31 • frei benutzbare Register: • Register 1, 2, ..., 30 • Register besitzen symbolische Namen: • Benennung: $ <name> Patterson/Hennessy: Benennung der Register entsprechend der Nutzung im GNU C Compiler Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 10 MIPS GNU C Registerbenutzung Name Nr. Funktion $zero 0 der konstante Wert 0 $at 1 reserviert für Assembler $v0, $v1 2, 3 Resultatwerte und Auswertung von Gesichert? bleibt Ausdrücken nein $a0 ... $a3 4-7 Argumente nein $t0 ... $t7 8-15 Zwischenwerte (temporär) nein $s0 ... $s7 16-23 gesichert (saved) ja Beispiel für Nutzung: add $t0, $s2, $t0 addiere Inhalte der Register $t0 und $s2 und speichere das Ergebnis in Register $t0 ab Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 11 MIPS GNU C Registerbenutzung Name Nr. Funktion Gesichert? $t8 ... $t9 24-25 weitere Zwischenwerte $k0, $k1 26, 27 Betriebssystem (OS kernel) $gp 28 globaler Zeiger (global pointer) $sp 29 Zeiger auf Kellerspeicher (stack pointer) ja $fp 30 Rahmenzeiger (frame pointer) ja $ra 31 Rücksprungadresse (return address) ja (vgl. Patterson/Hennessy, Seite A-24, Figure A.6.1) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 12 nein ja Das Beispiel mit Registern add t0, g, h add t1, i, j sub f, t0, t1 f=(g+h)–(i+j) add $t0, $s1, $s2 add $t1, $s3, $s4 sub $s0, $t0, $t1 Die Variablen der C-Anweisung wurden der Reihe nach den Registern $s0 - $s4 zugeordnet. Aber: Wie kommen die Variablenwerte in die Register? Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 13 Register versus Speicher Problem: Arithmetische Instruktionsoperanden müssen Register sein — nur 32 Register verfügbar • Übersetzer weist den Variablen Register zu • Was aber bei Programmen mit vielen Variablen ? • d.h. Datenstrukturen müssen im Speicher gehalten werden: wo, wie? Und wie kommen sie in Register? Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 14 2.3 Speicherorganisation Antwort: Ablage im Speicher, Zugriff über Adresse, Load/Store Befehle im Assembler 2.3.1 Byte-Adressierung Speicher: sehr großes, eindimensionales Bit-Feld • Elemente des Feldes sind über Adressen identifizierbar • Eine Speicheradresse ist als ein Index in das Feld zu interpretieren • „Byte Adressierung“ bedeutet, der Index zeigt auf ein Byte (=8 Bit) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 15 2.3.2 Worte Byte: relativ kleine Einheit Zur einfacheren Handhabung: größere Einheiten, die „Worte“, häufig: 1 word = 32 Bit (4 Byte) MIPS-Befehlssatz: jedes Wort besteht aus 4 Byte • Ein Register enthält 32 Bit an Daten • Mit dem Inhalt eines 32-bit Registers lassen sich 232 Byte mit Byte-Adressen von 0 bis 232–1 adressieren • 230 Worte mit Byte-Adressen 0, 4, 8, ... 232–4 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 16 2.3.2 Worte Worte sind sequentiell abgelegt und dürfen nur an Adressen beginnen, die durch die Wortgröße teilbar sind: diese Eigenschaft heißt Alignment Dadurch erreicht man effizientere Speicherzugriffe: pro Wort ist nur eine Adressberechnung erforderlich Ausnutzen dieser Organisation: • z.B. bei der Verarbeitung von Feldern • Array-Elemente werden sequentiell abgelegt • Ein Register z.B. $s3 enthält die Anfangsadresse (Basisadresse) • Element-Adresse A[i]: i-tes Element des Feldes A: Basisadresse + 4* i Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 17 2.3.3 Byte-Order Big Endian: das Byte mit höchstwertigsten Bits wird zuerst gespeichert, d.h. an der kleinsten Speicheradresse. Little-Endian das Byte mit niederwertigsten Bits wird zuerst gespeichert Beispiel aus dem täglichen Leben: Datumsformat yyyy-mm-dd : Big Endian dd-mm-yyyy : Little Endian Bem.: MIPS kennt Big- und Little Endian Order MARS-Simulator: arbeitet mit Little Endian Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 18 2.4 MIPS Speicherbefehle: Lade und Speichere lw: load word (lade Wort), sw: save word (speichere Wort) Beispiel: C: A[8] = h + A[8] MIPS: lw $t0, 32($s3) ($s3 enthalt Startadresse von A) add $t0, $s2, $t0 sw $t0, 32($s3) bei sw Zieladresse am Schluss Arithmetikoperanden müssen Register, können nicht Speicheradressen sein! MIPS-Adressierungsmodus: Konstante (Basisregister): Adresse = Konstante + Inhalt des Basisregisters z.B. 32($s3) = Offset/Index (32) + Basis-(Index-)Register ($s3) lw und sw einzige Befehlstypen, die auf Speicher zugreifen! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 19 2.4 MIPS Speicherbefehle (Beispiel 1) Beispiel: C: int V[6]; a = V[2]; V[4] = a; MIPS: $s1: Basisadresse von V $s0: a Ladebefehl: Datenübertragung Speicher Register lw $s0, 8($s1) Speicherbefehl: Datenübertragung Register Speicher sw $s0, 16($s1) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 20 2.4 MIPS Speicherbefehle (Beispiel 2) swap(int v[], int k); Wert von k steht in Register $5 {int temp; Startwert von v steht in Register $4 temp = v[k] v[k] = v[k+1] Erinnerung: Befehle in eckigen Klammern v[k+1]= temp; bezeichnen Pseudobefehle } swap: [mul $2, $5, 4] # $2 = k*4 Adressberechnung von v[k] add $2, $4, $2 # $2 = v + k*4 lw $16, 0($2) # lade Inhalt von v[k] lw $17, 4($2) # lade Inhalt v[k+1] Datentransport sw $17, 0($2) # v[k] = v[k+1] sw $16, 4($2) Rücksprung jr $31 # fahre beim Aufrufer fort Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 21 2.4 C-Programme mit variablen Array-Indizes Beispiel: C: MIPS Registerzuweisung: g = h + A[i] $s1: $s2: $s3: $s4: g h Basis von A i Index auf Speicheradressen abbilden (mit 4 multiplizieren): mul: Normale Multiplikation (effizienter) sll: Shift 2 Stellen nach links [mul $2, $5, 4] sll $t1, $s4, 2 Wortadresse zu Basisadresse addieren add $t1, $t1, $s3 Array-Element laden (Adresse von A(i) in $t1) lw $t0, 0($t1) Addition ausführen add $s1, $s2, $t0 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 22 2.4 Zwischenbilanz MIPS Laden von Worten, Adressieren von Bytes Arithmetik nur auf Registern Instruktionen Bedeutung add $s1, $s2, $s3 $s1 = $s2 + $s3 sub $s1, $s2, $s3 lw $s1, 100($s2) sw $s1, 100($s2) $s1 = $s2 - $s3 $s1 = Memory[$s2+100] Memory[$s2+100] = $s1 und auch bereits: Immediate Befehle, Shift Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 23 2.5 MIPS Befehlsformate Background • Auch Instruktionen sind 32 Bits lang • Beispiel: Repräsentation eines Additionsbefehls • Beispiel: MIPS-Assembler: add $t0, $s1, $s2 • Jedes Register hat eigene Nummer: $t0=8, ..., $t7=15, $s0=16, ..., $s7=23 • Dezimaldarstellung des Additionsbefehls: 0 17 18 Addition Zielregister Operandenregister Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 24 8 0 32 hier unbenutzt 2.5 MIPS Befehlsformate 0 17 18 8 0 Addition Zielregister Operandenregister 32 hier unbenutzt In Binärdarstellung: 000000 10001 10010 01000 00000 100000 6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit Beispiel: 10010binär = 1×24 + 0×23 + 0×22 + 1×21 + 0×20 = 18dezl Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 25 2.5.1 MIPS-Befehlsformat „R“ (für Register) op rs rt rd shamt funct 6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit • • • • • op: „opcode“; Grundtyp des Befehls (instruction) rs: erster Operand (Register!) rt: zweiter Operand (Register!) rd: Ziel (Register!) shamt: „shift amount“, für sogenannte Schiebeoperationen wichtig (siehe später) • funct: „Funktionscode“; Ergänzung zu op: genaue Spezifikation der durchzuführenden Operation Zusammenfassung der MIPS-Architektur bis hierher siehe: Patterson/Hennessy, Seite 67, Figure 2.7 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 26 2.5.2 MIPS-Befehlsformat „I“ (Immediate) • • • • op rs rt adress 6 Bit 5 Bit 5 Bit 16 Bit op: „opcode“; Grundtyp des Befehls (instruction) rs: Basisadressregister rt: Zielregister adress: Konstante, die Offset bzgl. Basisregister angibt • lw, sw benötigen 2 Register und 1 Konstante als Array-Offset • Konstante kann länger als 5 oder 6 Bit sein • op-Kodierung von lw ist 35 (dezimal) bzw. 100011 (binär) • op-Kodierung von sw ist 43 (dezimal) bzw. 101011 (binär) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 27 Beispiel C-Programmtext A[300] = h + A[300] Maschinencode dezimal Maschinencode binär Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 28 MIPS-Assembler lw $t0, 1200($t1) add $t0, $s2, $t0 sw $t0, 1200($t1) 2.5.3 MIPS-Befehlsformat „J“ (Jump) op adress 6 Bit 26 Bit • op: „opcode“; Grundtyp des Befehls (instruction) • adress: Zieladresse Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 29 2.6 Konzept der universellen Interpretierbarkeit Hintergrund: • Programme sind gespeicherte Daten • Befehle sind Bitfolgen bzw. Binärzahlen Konsequenz: • Programme werden im Speicher als Maschinencode abgelegt und sie werden gelesen und geschrieben wie Daten Speicher Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 30 Speicher für Daten, Programme, Compiler, Editoren, etc. 2.6.1 Uniforme Verwaltung Uniforme Verwaltung (Programme, Daten) keine speziellen Verwaltungsoperationen für Befehlsund Datenspeicher notwendig Bem: • Es gibt spezielle Architekturen, die explizit zwischen Befehls- und Datenspeicher unterscheiden • welche Vorteile hätte das ggf. doch? Uniformität • Speicher ist als uniformer Bit-Container realisiert • vereinheitlichte, einfache Abläufe, z.B. Grundzyklus der CPU Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 31 2.6.1 Uniforme Verwaltung Grundzyklus der CPU Fetch and Execute • Befehle werden aus dem Speicher geladen (fetch) und in ein spezielles Register abgelegt • Die Bits in diesem Register „steuern“ die nachfolgenden Aktionen (vgl. Kontrollpfad der CPU wie in Technischer Informatik behandelt) • Befehl wird ausgeführt (execute) • Holen des „nächsten“ Befehls etc. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 32 2.6.2 Mögliche Probleme Mögliche Probleme durch universelle Interpretierbarkeit kein Schutz der Daten und Programme Daten können als Befehle interpretiert werden, auch wenn das so eigentlich nicht vorgesehen ist Beispiel: Buffer-Overflow-Exploits Programme können verändert werden und inkorrektes (schädliches) Verhalten aufweisen Beispiel: Schadsoftware: Viren, Trojaner Lösungsansatz: Aufteilung des Speicherbereichs eines Programms in Daten und Code-Bereich Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 33 Typisches Speicherlayout eines Programms 0xff…f Daten Code 0 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 34 64-bit Adressraum - 64-bit Adressräume erlauben es, gut 16 Millionen Terabyte Speicher zu adressieren => immenser Verwaltungsaufwand -Lösung: Adresse auf weniger Bits reduzieren -Beispiel (AMD64): Höchstes Bit wird entweder als 0xF..F bzw. als 0x0..0 interpretiert Bild: Wikipedia Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 35 Bedeutung für die Assemblerprogrammierung Konzept der Segmentierung Trennen in Daten-, Code- (Text) und Stack-Segment Datensegment enthält die Daten Textsegment den Programmcode Stacksegment wird für Prozeduraufrufe benötigt dies ist eine übliche Aufteilung des Adressraums eines Prozesses in heutigen Betriebssystemen Frage: woher weiß der Assembler, welche Assemblerbefehle in welches Segment zu speichern sind? Antwort: über Direktiven: .text , .data Assembler sortiert dann automatisch Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 36 2.7 Übersetzung von Kontrollstrukturen 2.7.1 Background: In höheren Programmiersprachen gibt es programmiersprachliche Konzepte, um die sequentielle Ausführung von Befehlen zu beeinflussen bedingte Programmausführung: u.a. if ... then ... [else ...] switch ... case ... wiederholte Programmausführung: u.a. for ... while ... repeat … until Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 37 2.7.1 Background Auf der Maschinenbefehlsebene gibt es keine Befehle, um Kontrollstrukturen direkt abzubilden Es stehen lediglich bedingte und unbedingte Sprungbefehle zur Verfügung Sprungbefehle im MIPS-Befehlssatz: beq reg1, reg2, label (branch if equal) bne reg1, reg2, label (branch if not equal) j addr (jump to address), unbedingter Sprung Problem: Die Semantik der Kontrollstrukturen muss mit den Sprungbefehlen effizient nachgebildet werden Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 38 2.7.2 Übersetzung einfacher Kontrollstrukturen in Assemblercode Hier betrachtet: if-then-else, while IF-Anweisung einer höheren Programmiersprache: if <bedingung> then <statement1> else <statement2> Übersetzungsschritte: Variablen und Werte, die zur Auswertung der Bedingung benötigt werden, in Register ablegen Beginn der Befehlsfolge <statement2> mit Marke <marke> versehen Sprung zu <marke>, falls Bedingung nicht erfüllt Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 39 Beispiel: If .. then .. else Anweisung C-Programmtext if (i==j) f = g + h; else f = g - h; MIPS-Assembler Testen und Verzweigen bne $s3, $s4, Else Addition (im TRUE-Fall) add $s0, $s1, $s2 Else-Fall überspringen j Exit Subtraktion (im FALSE-Fall) Else: sub $s0, $s1, $s2 Ausgang Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 40 Exit: Beispiel: while Schleife Schleifen, z.B. while Schleife While <bedingung> do <statementlist> endwhile Übersetzungsschritte: analog zur If-Anweisung: Variablen und Werte zur Auswertung der Bedingung werden in Register geladen markiere den ersten Befehl der Statementlist mit einer Marke, z.B. LOOP füge als letzten Befehl der Statementliste einen bedingten Sprung zur Marke LOOP ein Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 41 Weitere Kontrollfluss-Steuerungen Wie realisiert man einen Vergleich der Art if a < b ? Neuer Befehl: Bedeutung: slt $t0, $s1, $s2 (set on less than) if $s1 < $s2 then $t0 = 1 else $t0 = 0 Damit lässt sich if a < b goto less wie folgt übersetzen: slt $t0, $s1, $s2 bne $t0, $zero, less Bem.: Die MIPS-Architektur verwendet ein spezielles Register, das konstant den Wert „0“ enthält. Es wird in der Assemblersprache als $zero bezeichnet. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 42 Die MIPS-Architektur bis hierher Instruktion Bedeutung add $s1,$s2,$s3 $s1 = $s2 + $s3 sub $s1,$s2,$s3 $s1 = $s2 – $s3 lw $s1,100($s2) $s1 = Memory[$s2+100] sw $s1,100($s2) Memory[$s2+100] = $s1 bne $s4,$s5,L nächste Instruktion ist bei L, wenn $s4 != $s5 beq $s4,$s5,L nächste Instruktion ist bei L, wenn $s4 = $s5 slt $t0,$s1,$s2 wenn $s1 < $s2, dann $t0=1, sonst $t0=0 j Label nächste Instruktion ist bei Label Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 43 Die MIPS-Architektur bis hierher add immediate | addi $s1,$s2,100| $s1= $s2+100 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 44 | used to add constants addi | I | 8 | 18 | 19 | 100 | addi $s1,$s2,100 Quelle: Buch von Patterson/Hennessy, Seite 131, Figure 3.9 (2. A) R I op op J op rs rs Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 45 rt rt rd shamt funct 16 Bit Adresse 26 Bit Adresse Zwischenfazit Grundprinzipien heutiger Rechnerarchitekturen: • Instruktionen als (binäre) Zahlen repräsentiert. • Programme im Speicher abgelegt und können dort gelesen und geschrieben werden wie Zahlen. • Dies ist das Prinzip des speicherprogrammierbaren Rechners (stored program computer) • Daten und Programme können beliebig im Speicher angeordnet werden. • Programme können auch als Daten interpretiert werden (z.B. Compiler betrachten Programme als Daten.) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 46 2.8 Verarbeitung von Zeichen 2.8.1 Darstellung von Zeichen: • eine Möglichkeit: ASCII-Format (siehe nächste Folie) • Darstellung eines Zeichens durch einen 8Bit Code • Zugriffe auf einzelne Zeichen: Assemblerbefehle: • Lade Byte (lb), speichere Byte (sb) • Ladeoperation: lb $t0, 0($sp) (load byte) Lädt ein Byte aus dem Speicher und platziert es in die niederwertigen Bits eines Registers • Speicheroperation: sb $t0, 0($a1) (save byte) niederwertiges Byte in Speicherposition speichern Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 47 Darstellung von Zeichen: ASCII-Tabelle Mit acht Bit (ein Byte) lassen sich in ASCII (American Standard Code for Information Interchange) 28=256 Zeichen darstellen gemäß Konvention: • • Groß- und Kleinbuchstaben unterscheiden sich um 32= 25 Nicht angegeben: u.a. Formatierungszeichen wie „Tab“ (9), „Carriage Return“ (13), „Backspace“ (8), „Null“ (0) (in C zur Markierung des Endes einer Zeichenkette verwendet). Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 48 2.8.2 Zeichenketten Kombination von Zeichen zu Zeichenketten (strings) •Darstellung von Zeichenketten: 3 typische Varianten • Die erste Position der Zeichenkette wird reserviert für die Länge der Zeichenkette. • Eine zweite, zusätzliche Variable enthält die Länge der Zeichenkette. • Die letzte Position einer Zeichenkette wird durch ein Sonderzeichen markiert. (z.B. in C verwendet) • Beispiel: Zeichenkette „GdI3“ in C dargestellt durch 5 Byte mit den ASCII-Werten: 71, 100, 73, 51, 0. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 49 2.8.2 Zeichenketten • Typische Operation auf Strings: Kopieren • Beispiel: Kopieren eines Zeichenstrings unter Prozedur strcpy kopiert Zeichenkette y auf x void strcpy (char x[], char y[]) { int i; i = 0; while ((x[i]=y[i]) != 0) /* Kopieren, Prüfen des i-ten Byte*/ i = i + 1; } Festlegung: • Basisadresse des Feldes (array) x steht in $a0 und Adresse von y in $a1 • $s0 wird für i verwendet. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 50 2.9 „Höhere Kontrollstrukturen“: Prozeduren 2.9.1 Allgemeines • Prozeduren (Unterprogramme, Methoden) wichtigstes Strukturierungskonzept moderner Programmiersprachen • Moderne Rechner-Architekturen bieten Hardware-Unterstützung zur effizienten Bearbeitung von Prozeduren Konzept: Prozedurrahmen (procedure frame): • Speicherblock, in dem alles abgelegt wird, was zur Verwaltung des Prozeduraufrufs notwendig ist. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 52 2.9.1 Allgemeines Vorteile des Konzeptes: Einheitliche Behandlung von Prozeduraufrufen, d.h. Abstraktion von unterschiedlichen Aufrufkonzepten: • iterative und rekursive Prozeduren • geschachtelte Prozeduren • Im Prinzip wird auch ein entfernter Prozeduraufrufe (RPC, RMI) analog bearbeitet Bem.: Prinzip wird auch an anderer Stelle eingesetzt: u.a. beim Prozess- und Kontextwechsel durch das BS Retten von Zuständen, Kontrollwechsel etc. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 53 2.9.1 Allgemeines Schritte zur Ausführung einer Prozedur • Parameter so bereit stellen, dass Prozedur darauf zugreifen kann: • Argumentregister $a0, $a1, $a2, $a3 • Eingangsparameter bleiben durch Prozedur unverändert • Ablaufsteuerung (control) der Prozedur übergeben: • jal Prozeduradresse (jump and link) • Sonderbefehl für Prozedurausführung: springt zur angegebenen Adresse und speichert die Adresse der folgenden Instruktion in $ra Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 54 2.9.1 Allgemeines Schritte zur Ausführung einer Prozedur (Forts.) •Benötigten Speicherbereich für Prozedur bereit stellen • Prozedur ausführen • Ergebniswert so bereit stellen, dass aufrufendes Programm darauf zugreifen kann: • Ergebniswertregister $v0,$v1 • Ablaufsteuerung an Aufrufstelle zurückgeben durch Sprung zurück zum Ausgangspunkt: • jr $ra (jr: jump register, ra: return address) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 55 2.9.1 Allgemeines Nutzung des speicherprogrammierbaren Rechners: • zur Realisierung einer Prozedur wird ein Register mit Adresse der aktuell ausgeführten Instruktion benötigt • Dieses Register nennt man traditionell program counter (PC), gemeint ist das „instruction address register“ Problem: nach der Prozedurausführung muss bei der korrekten Instruktion beim Aufrufer weitergearbeitet werden: d.h. alter PC-Stand muss bewahrt werden Lösung: Befehl jal speichert PC+4 in Register $ra. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 56 2.9.2 Übersetzung von Prozeduren in Assembler Einfache Parameterübergabe über Register: • Die Register $a0-$a3 dienen zur Übergabe der ersten vier Parameter • $v0-$v1 dienen zur Speicherung der Return-Werte • $ra enthält die Rücksprungadresse zum Aufrufer Probleme: • Was ist bei mehr als 4 Parametern? • Zur Bearbeitung der Prozedur werden auch Register benötigt, die enthalten ggf, noch Werte des Aufrufers: was soll damit geschehen? Retten? Überschreiben? Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 57 2.9.2 Übersetzung von Prozeduren in Assembler Antworten: • gespeicherte Registerwerte des Aufrufers (Zustand) werden in Form einer Keller-Datenstruktur (stack) im Speicher verwaltet (LIFO-Prinzip) • Bem.: Stack-Verwaltung muss explizit in Assembler programmiert werden Ein Keller enthält: • Argumentwerte, bei mehr als 4 Parametern • die vor dem Prozeduraufruf gültigen Inhalte derjenigen Register, die von der Prozedur verwendet werden. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 58 2.9.2 Übersetzung von Prozeduren in Assembler Kellerverwaltung: Ein Register weist auf das letzte Element im Kellerspeicher ($sp: stack pointer) Der Keller ist am „oberen Ende“ des Speichers angeordnet und wächst in Richtung kleinerer Speicheradressen (von oben nach unten) Push: erniedrigt den Stack-Pointer Pop: erhöht ihn Synonyme Begriffe: Keller, Stapel, stack Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 59 $sp 2.9.2 Übersetzung von Prozeduren in Assembler Notwendig für Verwaltung: • Kellerpegel (engl. stack pointer) $sp muss vom Assemblerprogrammierer manuell verwaltet werden • Anpassung des Kellerpegels in 1-Wort-Schritten für Speicherung oder Zurückspeicherung eines Registerwerts Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 60 Einfaches Beispiel für Prozedur C-Programmtext int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } MIPS-Assembler first_proc: Phase 1: Registerinhalte auf den Stack retten Phase 2: Berechnungen durchführen Phase 3: Resultatwert speichern Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 61 Keller (stack) hohe Adresse $sp (vor Phase 1) niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); Phase 1: Registerinhalte auf den return f; } Stack retten [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: Berechnungen durchführen Phase 3: Resultatwert speichern Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 62 sub ist ein Pseudobefehl, der mit Registern bzw. kleinen Konstanten arbeiten kann (siehe MIPS-R2000 Befehlssatz). Keller (stack) hohe Adresse $sp (vor Phase 1) niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); Phase 1: Registerinhalte auf den return f; } Stack retten [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: Berechnungen durchführen Phase 3: Resultatwert speichern Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 63 Keller (stack) hohe Adresse $sp (vor Phase 1) $t1 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); Phase 1: Registerinhalte auf den return f; } Stack retten [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: Berechnungen durchführen Phase 3: Resultatwert speichern Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 64 Keller (stack) hohe Adresse $sp (vor Phase 1) $t1 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 2: Berechnungen durchführen Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Keller (stack) hohe Adresse Phase 3: Resultatwert speichern Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 65 $t1 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 2: Berechnungen durchführen Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Keller (stack) add $t0, $a0, $a1 hohe Adresse add $t1, $a2, $a3 sub $s0, $t0, $t1 $t1 Phase 3: Resultatwert speichern $t0 Phase 4: Register zurückspeichern $s0 $sp (nach Phase 1) Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 66 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; Phase 3: Resultatwert speichern } Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 Keller (stack) hohe Adresse $t1 Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 67 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; Phase 3: Resultatwert speichern } Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 [move $v0, $s0] Phase 4: Register zurückspeichern Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 68 Keller (stack) hohe Adresse $t1 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 4: Register zurückspeichern Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 Phase 3: [move $v0, $s0] Keller (stack) hohe Adresse $t1 $t0 $sp (nach Phase 1) Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 69 $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 4: Register zurückspeichern Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 Phase 3: [move $v0, $s0] lw $s0, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) [add $sp, $sp, 12] Phase 5: Rücksprung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 70 Keller (stack) hohe Adresse $sp (nach Phase 4) $t1 $t0 $sp (nach Phase 1) $s0 niedrige Adresse Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 5: Rücksprung Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 Phase 3: [move $v0, $s0] Phase 4: lw $s0, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) [add $sp, $sp, 12] Keller (stack) hohe Adresse $sp (nach Phase 4) niedrige Adresse Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 71 Einfaches Beispiel für Prozedur int first_proc (int g, int h, int i, int j) { int f; f = (g + h) – (i + j); return f; } Phase 5: Rücksprung Phase 1: [sub $sp, $sp, 12] sw $t1, 8($sp) sw $t0, 4($sp) sw $s0, 0($sp) Phase 2: add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 Phase 3: [move $v0, $s0] Phase 4: lw $s0, 0($sp) lw $t0, 4($sp) lw $t1, 8($sp) [add $sp, $sp, 12] jr $ra Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 72 Keller (stack) hohe Adresse $sp (nach Phase 4) niedrige Adresse Einfaches Beispiel für Prozedur Anmerkungen zum Beispiel: • Annahme war: die Werte der verwendeten Register $t0, $t1, $s0 werden gesichert und müssen nach Beendigung der Prozedur zurück gespeichert werden. • Zur Vermeidung von Speicheroperationen für Register, deren Werte nicht verwendet: zwei Klassen von Registern: • $t0 - $t9: 10 Register für temporäre Variablen, deren Inhalte von der aufgerufenen Prozedur verändert werden können und nicht gesichert werden müssen. • $s0 - $s7: 8 Register für langlebige Variablen, die von aufgerufenen Prozeduren nicht verändert werden dürfen. D.h. Inhalte müssen nach Aufruf und Abarbeitung einer Prozedur gesichert bzw. wiederhergestellt sein. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 73 2.9.3 Geschachtelte Prozeduren (nested) Beispiel zur Motivation der Problematik • Hauptprogramm (main) ruft Prozedur A auf: Effekt: main belegt Argumentregister $a0 und Rücksprungregister $ra • Prozedur A ruft Prozedur B auf: Effekt: A belegt Argumentregister $a0 und Rücksprungadresse $ra. Probleme: Konflikte in $a0 und Register $ra ! • Rücksprungadresse in das Hauptprogramm main geht verloren! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 74 2.9.3 Geschachtelte Prozeduren (nested) Schwierigkeiten: • Alle Prozeduren verwenden dieselben Register für ihre Argumente ($a0 - $a3). • Alle Prozeduren verwenden ein einziges (dasselbe) Rücksprungregister ($ra). • Alle Prozeduren verwenden die Register ($s0 - $s7). Eine mögliche Lösung: • Die aufrufende Prozedur (caller) sichert die jeweils benötigten der Argumentregister ($a0 - $a3) und temporären Register ($t0 - $t9) auf den Stack („push“-Operation). Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 75 2.9.3 Geschachtelte Prozeduren (nested) Eine mögliche Lösung: (Forts.) • Die aufgerufene Prozedur (callee) sichert auf dem Stack die Rücksprungregister ($ra) und die von ihr zu verwendenden langlebigen Register ($s0 - $s7) • Der Kellerpegel (stack pointer) $sp wird angepasst gemäß der Anzahl der gespeicherten Register • Beim Rücksprung aus der aufgerufenen Prozedur werden alle gesicherten Register zurück geladen („pop“-Operation) und der Kellerpegel zurück gesetzt. Bem.: Rekursive Prozeduraufrufe sind ein Spezialfall von geschachtelten Aufrufen, analoge Behandlung Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 76 2.9.3 Geschachtelte Prozeduren (nested) Beispiel: Rekursiver Prozeduraufruf C-Programmtext: Berechnung der Fakultät n! int fact (int n) { if (n < 1) return (1); else return (n * fact(n-1)); } Zwischenüberlegung: Umformung in C int fact (int n) { int t0; if (n < 1) t0 = 1; else t0 = 0; if (t0 == 0) goto L1; return (1); L1: return (n * fact(n-1)); } Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 77 Beispiel (Forts.): MIPS-Assembler (mit Verwendung direkter Addition/Subtration von Konstanten) fact: L1: [sub sw sw [slt beq [add $sp,$sp,8] $ra, 4($sp) $a0, 0($sp) $t0,$a0,1] $t0,$zero,L1 $v0,$zero,1] [add jr [sub jal lw lw [add mul jr $sp,$sp,8] $ra $a0,$a0,1] fact $a0, 0($sp) $ra, 4($sp) $sp,$sp,8] $v0,$a0,$v0 $ra Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 78 # Anpassung des Kellerpegels um 2 Worte # Speicherung der Rücksprungadresse # Speicherung des Arguments n # Test auf n < 1 # falls n >=1, gehe zu L1 # Ergebnis ist 1 # Zurückspeichern von $a0, $ra unnötig bei n<1 # Entfernen („pop“) zweier Worte vom Stapel # Rücksprung hinter jal # falls n>=1: ersetze Argument n durch n-1 # Aufruf von fact mit (n-1) # Rückkehr von jal; Rückspeicherung Argument n # Rückspeicherung der Rücksprungadresse # Entfernen zweier Worte vom Kellerpegel # Ergebnis ist n * fact(n-1); Multiplikation s.Kap.4 # Rücksprung zum aufrufenden Programm Langlebige und temporäre Registerwerte Inhalte der Register nach Aufruf einer Prozedur: langlebig temporär (bzw. zu erhalten) (bzw. nicht zu erhalten) langlebige Register: $s0 - $s7 temporäre Register: $t0 - $t9 Kellerpegelregister: $sp Argumentregister: $a0 - $a3 Rücksprungadressregister: $ra Ergebniswertregister: $v0 Keller (stack) oberhalb des Kellerpegels (stack pointer) Keller (stack) unterhalb des Kellerpegels (stack pointer) Die Inhalte von Rahmenzeigerregister (frame pointer register) $fp und Globalem-Zeiger-Register (global pointer register) $gp sind gegebenenfalls auch zu erhalten. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 79 2.9.4 Speicherverwaltung: Prozedurrahmen • Speicherung aller lokalen Variablen und Datenstrukturen einer Prozedur, die nicht in die verfügbaren Register passen, auf dem Stack • Das Kellersegment (stack segment) mit den Daten eines Prozeduraufrufs heißt Prozedurrahmen (procedure frame, activation record). • Rahmenzeiger (frame pointer) $fp zeigt auf Anfang des Prozedurrahmens. • Über $fp sind lokale Prozedurdaten unabhängig vom aktuellen Kellerpegel ($sp) adressierbar Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 80 Verwaltung der Prozedurrahmen vor Prozeduraufruf • • während Prozedurausführung nach Prozeduraufruf Rahmenzeiger $fp zeigt auf erstes Wort des Rahmens; er verändert sich während Prozedurausführung nicht. Kellerpegel $sp zeigt auf Anfang des Stacks; er kann sich während Prozedurausführung verändern. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 81 Aufgabenverteilung Frage: Welche Informationen schreibt Aufrufender (caller) welche Aufgerufener (callee) in den Rahmen ? Antwort: allgemeine Konvention Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 82 Prolog des Aufrufers Prolog des Aufrufers (caller) (vor Prozeduraufruf) • Sichern aller Register, die der Aufrufer auch nach dem Aufruf benötigt. • MARS: Register: $a0 - $a3, $t0 - $t9, $v0,$v1 • Übergabe der Eingabeparameter beim MARS: • Die ersten 4 Argumente in den Registern $a0, ..., $a3 • Die restlichen in umgekehrter Reihenfolge auf den Keller • Bei „Call-by-Value“-Parametern: Laden des Wertes • Bei „Call-by-Reference“-Parametern: • Laden der Adresse (mit la-Befehl) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 83 Beispiel für Prolog-Schema für Caller main: <...> [sub sw sw # Berechnungen im Hauptprogramm # --- Prolog des Aufrufers: --$sp,$sp,8] # Platz auf Stack reservieren (2 Worte f. 2 Regist.) $t0, 4($sp) # Speicherung des noch benötigten Inhalts von $t1, 0($sp) # $t-Registern (hier: $t0, $t1) vom Aufrufer selbst [move $a0, $t5] # Argumente übergeben (hier nur eines) Aufruf der Prozedur mit jal-Befehl, • d.h. Start der Prozedur durch Sprung zu deren erstem Befehl. • Wichtig: jal sichert automatisch die Rücksprungadresse des Aufrufers im Register $ra. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 84 Epilog des Aufrufers Epilog des Aufrufers (caller) (nach Rückkehr vom Prozeduraufruf) • Wiederherstellen der gesicherten Register • Wiederherstellen des ursprünglichen Kellerpegels (stack pointer) (durch „Pop“ der Einträge): $sp := $sp + (|Argumente| + |gesicherte Register|) × 4 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 85 Beispiel für Prolog/Epilog-Schema main: <...> [sub sw sw $sp,$sp,8] $t0, 4($sp) $t1, 0($sp) # irgendwelche Berechnungen im Hauptprogramm # --- Prolog des Aufrufers: --# Platz auf Stack reservieren (2 Worte f. 2 Regist.) # Speicherung des noch benötigten Inhalts von # $t-Registern (hier: $t0, $t1) vom Aufrufer selbst [move $a0, $t5] # Argumente übergeben (hier nur 1) jal proc # --- Aufruf der Prozedur --- $t1, 0($sp) $t0, 4($sp) $sp,$sp,8] # --- Epilog des Aufrufers: --# Registerinhalte wiederherstellen # # Kellerpegel zurücksetzen lw lw [add # Aufruf der Prozedur ist beendet Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 86 Prolog des Aufgerufenen Prolog des Aufgerufenen (callee) (vor Ausführung der Prozeduranweisungen) • Speicherplatz reservieren: Versetzen des Kellerpegels: $sp := $sp – (|zu sichernde Register| + |lokale Variablen|) × 4 • Sichern aller Register, die von der Prozedur verändert werden; MARS: • zuerst $fp sichern, • restliche Register in beliebiger Reihenfolge, • $ra sichern, falls weiterer Prozeduraufruf erfolgt! • Rahmenzeiger $fp setzen: Element nach Eingabepar. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 87 Beispiel für Prolog-Schema (Callee) proc: [sub sw sw sw sw sw [add <...> # Einsprungadresse der Prozedur # --- Prolog des Aufgerufenen: --$sp,$sp,20] # Platz auf Stack reservieren (hier: 5 Worte) # hier: 5 Register sichern $fp, 16($sp)# “alten“ Rahmenzeiger sichern $ra, 12($sp)# Rücksprungadresse sichern $s0, 8($sp)# die benötigten $s-Register müssen von der $s1, 4($sp)# aufgerufenen Prozedur gesichert werden $s2, 0($sp)# $fp, $sp,20]# Rahmenzeiger erstellen # Prozedurkörper mit eigentlichen Befehlen # --- Epilog des Aufgerufenen: --- Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 88 Epilog des Aufgerufenen Epilog des Aufgerufenen (callee) (nach Ausführung des Prozedurkörpers) • Rückgabe des Funktionswertes • MARS: in den Registern $v0 bzw. $v1 • Wiederherstellen der gesicherten Registerinhalte • z.B. Rahmenzeiger $fp, Rücksprungadresse $ra • „Pop“ der für die Prozedur angelegten Werte durch Zurücksetzen des Kellerpegels (stack pointer) $sp • $sp := $sp + (|gesicherte Register| + |lokale Variablen|) × 4 • Rücksprung zum Aufrufer: im MARS durch: jr $ra Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 89 Beispiel für Prolog/Epilog-Schema (Forts.) proc: [sub $sp,$sp, 20] sw sw sw sw sw [add <...> $fp, 16($sp) $ra, 12($sp) $s0, 8($sp) $s1, 4($sp) $s2, 0($sp) $fp, $sp,20] lw $s2, 0($sp) lw $s1, 4($sp) lw $s0, 8($sp) lw $ra, 12($sp) lw $fp, 16($sp) [add $sp, $sp,20] Fachbereich Informatik Frederik Armknecht | 90 jr | Prof. Dr.$ra # Einsprungadresse der Prozedur # --- Prolog des Aufgerufenen: --# Platz auf Stack reservieren (hier: 5 Worte) # hier: 5 Register sichern # “alten“ Rahmenzeiger sichern # Rücksprungadresse sichern # die benötigten $s-Register müssen von der # aufgerufenen Prozedur gesichert werden # # Rahmenzeiger erstellen # Prozedurkörper mit eigentlichen Befehlen # --- Epilog des Aufgerufenen: --# $s-Registerinhalte wiederherstellen # # # Rücksprungadresse wiederherstellen # Rahmenzeiger wiederherstellen # Kellerpegel zurücksetzen (pop) # Rücksprung zum Aufrufenden Pseudobefehle In den bisherigen Beispielen wurden unter anderem Pseuobefehle verwendet. Diese waren durch Klammern („[…]“) markiert. Pseudobefehle sind Befehle, die es nicht im Maschinenbefehlssatz gibt. Einige Assembler unterstützen bestimmte Pseudobefehle, um die Programmierung zu erleichtern. Beispiel: move $t0, $t1 (Kopiere Inhalt eines Registers ($t1) in ein anderes ($t0)) Einen solchen Befehl gibt es nicht! Mögliche Realisierung: add $t0, $t1, $zero (Addiere Null auf $t1 und schreibe das Ergebnis in $t0) Weiteres Beispiel: Arithmetik mit Konstanten (siehe folgende Folien) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 91 2.10 Adressierung MIPS-Befehlsformat „R“: • Operanden sind immer Register • Beispiele: add und sub Schwächen der bisherigen Instruktionen: • Die Verwendung von Konstanten ist unhandlich: • über ein spezielles Register ($zero) oder • Ablage der Konstante im Speicher an bekannter Stelle, bzw. erst Laden in ein Register Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 92 2.10 Adressierung • Konstanten (z.B. für Inkrement/Dekrement-Operationen bei Datenzugriffen in Schleifen) treten häufig auf, z.B. C Compiler gcc: > 52% aller arithmetischen Befehle nutzen Konstanten Effizienter Zugriff speziell auf kleine Konstanten ist wünschenswert ! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 93 2.10.1 Konstanten als unmittelbare Operanden Lösung: I- Befehlsformat (immediate): • Konstanten als unmittelbare Operanden op rs rt 6 Bit 5 Bit 5 Bit Beispiel: immediate 16 Bit addi $sp, $sp, 4 Dezimaldarstellung 8 29 29 Binärdarstellung 001000 11101 11101 Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 94 # $sp = $sp + 4 4 0000 0000 0000 0100 Weiteres Beispiel MIPS: unmittelbare Adressierung in MIPS: slti $t0, $s1, 10 slt # falls $s1 < $s2: $t0=1, sonst $t0=0 $t0, $s1, $s2 Dezimaldarstellung 10 17 8 Binärdarstellung 001010 10001 01000 # falls $s1 < 10: $t0=1, sonst $t0=0 10 0000 0000 0000 1010 Vorteil der direkten Adressierung: Die Verwendung häufig vorkommender, kleiner Konstanten wird effizient (schnell) ausgeführt ! Frage: Was tun, wenn Konstante größer als 216-1 = 65535 ist, und mehr als 16 Bit zur Darstellung benötigt ? Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 95 Behandlung großer Konstanten maximal 32 Bits große Konstanten (d.h. 232-1 = 4,29... ×109) Der Befehl lui (load upper half word immediate) lädt angegebene Konstante in die höherwertigen 16 Bits des Zielregisters. Beispiel: lui $t0, 255 Binärdarstellung Inhalt von $t0 00000 01000 0000 0000 1111 1111 0000 0000 1111 1111 0000 0000 0000 0000 Setzen der niederwertigen 16 Bits von $t0 z.B. mit addi $t0, $t0, 2304 Inhalt von $t0 001111 0000 0000 1111 1111 0000 1001 0000 0000 Laden einer Zahl mit lui in höherwertige 16 Bits entspricht Multiplikation mit 216 ! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 96 2.10.2 Adressierung von Sprungzielen Einfachste Sprungzieladressierung in MIPS im J-Format: j 10000 # go to Position 10000 Dezimaldarstellung 2 10000 (eigentlich: 2500) 6 Bit 26 Bit (für Sprungadresse) Bedingte Verzweigung mit bne oder beq benötigt neben der Sprungadresse zwei Operanden: Beispiel: bne $s0,$s1,Exit # go to Exit, if $s0 != $s1 Dezimaldarstellung 5 16 17 6 Bit 5 Bit 5 Bit Exit 16 Bit (für Sprungadresse) Problem: Wie kann man größere Adressen als 216-1 realisieren? Beobachtung: Verzweigungen in Schleifen und Fallunterscheidungen haben Sprungadressen „in der Nähe“ der aktuellen Instruktion Idee: Verwende relative Adressierung zum Instruktionsadress-Register PC Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 97 while (save[i] == k) i = i + j; Beispiel: Erneut: While-Schleife MIPS: 80000 Loop: add $t1, add $t1, add $t1, lw $t0, bne $t0, add $s3, j Loop $s3, $s3 $t1, $t1 $t1, $s6 0($t1) $s5, Exit $s3, $s4 # $t1=2×i # $t1=4×i # $t1=Adresse[save(i)] # $t0=save[i] # falls save[i] != k, go to Exit #i=i+j Achtung: PC wird # go to Loop jeweils vor eigentlicher Befehlsausführung um 4 erhöht. Exit: Darstellung in Maschinencode (symbolisch): 80000 0 19 19 9 0 32 80004 0 9 9 9 0 32 80008 0 9 22 9 0 32 80012 35 9 8 0 80016 5 8 21 8 80020 0 19 20 80024 2 80028 ... Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 98 19 80000 0 32 PC= PC+8 (Byte) (oder PC+2 (words)) Verzweigungen mit Zielen, die weiter entfernt sind • Verzweigungsbefehle können Verzweigungen um ± 216-1 Speicherworte realisieren. • Für weit entfernte Verzweigungen wird vom Assembler eine indirekte Verzweigungsmethode implementiert: • invertierter Verzweigungsbefehl • unbedingter Sprung zum Sprungziel (26 statt 16 Bit Adresse) Beispiel: beq $s0, $s1, L1 wird ersetzt durch bne $s0, $s1, L2 # j L1 # unbedingter Sprung, ‚weite Entfernung‘ L2: Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 99 Zusammenfassung der Adressierungsmodi 1. Unmittelbare Adressierung: Operand ist Konstante im Befehl selbst. 2. Registeradressierung: Operand ist Register 3. Basisadressierung: Operandenadresse ist Summe von Registerinhalt und Konstante im Befehl Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 100 Zusammenfassung der Adressierungsmodi 4. PC-relative Adressierung: Operandenadresse ist Summe von PC und Konstante im Befehl 5. Pseudodirekte Adressierung: Sprungadresse setzt sich aus 26 Bits im Befehl und (!) den oberen 4 Bits im PC zusammen Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 101 Zusammenfassung: MIPS-Operanden • einfache Befehle mit je 32 Bits • sehr strukturiert, kein überflüssiges „Gepäck“ • nur drei Befehlsformate Aufgabe des Compilers ist es, Leistung zu erbringen: • Als Programmierer dem Compiler wo immer möglich helfen! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 102 Bisherige MIPS-Instruktionen Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 103 Design Alternative: CISC • Bereitstellung leistungsfähigerer Operationen mit Ziel der Reduktion der auszuführenden Befehle • Gefahr ist eine langsamere Taktzeit und/oder eine höhere, durchschnittliche Anzahl von Takten per Instruktion • RISC (reduced instruction set computer) versus • CISC (complex instruction set computer): • fast alle neuen Instruktionssätze seit 1982 waren RISC z.B. MIPS, Sun SPARC, Hewlett-Packard PA-RISC, IBM/Motorola PowerPC, DEC Alpha Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 104 2.11 Fazit: Vom C-Programm zur Ausführung C-Programm Compiler Assemblerprogramm Assembler Objektcode: Maschinensprachmodul Binder (Linker) Executable: Maschinenprogramm Lader (Loader) Speicher Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 105 Objektcode: Bibliotheksroutinen 2.11 Fazit: Assemblerprogrammierung • über Adressierung: Zugriff auf beliebige Objekte im Speicher: flexibel, hoch performant • Aber: kein Schutz durch Typisierung, z.B. IntegerWert kann beliebig als Adresse interpretiert werden • Assemblerprogramme sind maschinenabhängig, d.h. nicht portierbar • Assemblersprache: • viel einfacher als mit Binärzahlen umzugehen • niedriges Niveau der Konzepte, darum Programmentwicklung schwierig (bzw. herausfordernd!) Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 106 2.11 Fazit: Assemblerprogrammierung • Programmtext in Assembler wird schnell sehr lang und unübersichtlich und damit fehleranfällig • nur wenige Konzepte für Kontrollstrukturen, Programmsteuerungsfluss: schwer wartbarbar • kein „Information Hiding“: z.B. bei geschachtelten Prozeduren über Rahmenzeiger-Kette beliebiger Zugriff auf Daten der vorherigen Prozeduraufrufe! Einsatzbereiche für Assemblerprogrammierung: • Bereiche die sehr effizienten Code benötigen, wie • Eingebettete Systeme, Controller, • elektronische Steuerungen: Auto, Flugzeug, … Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 107 2.11 Fazit: Eingebettete Systeme: Die Spitze des Eisbergs • In Vorlesung betrachtet: Hochleistungsprozessoren für allgemeine Computeranwendungen. • Aber: Die meisten Anwendungen der digitalen Datenverarbeitung findet man in Geräte des täglichen Lebens (embedded) • Markt für eingebettete (Computer-)Systeme wächst sehr stark • Deutschland hat eine führende Position bei der Entwicklung eingebetteter Systeme! Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 108 Eingebettete Prozessoren und Prozessorkerne • ARM, 486SX, Hitachi SH7000, … • nur ein Programm • einfache, oft Realzeit-Betriebssysteme • Mobiltelefone, Consumerelektronik Microcontroller • extrem Kosten sensitiv • geringe Wortbreite – 8-bit üblich • bei weitem die höchsten Stückzahlen • Automobil, Fahrstühle, Rolläden, Klimaanlage, Toaster, .. Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 109 Zunehmende Stückzahl General Purpose Prozessoren – Hohe Leistung • Pentiums, Alphas, SPARC, … • nützlich für allgemeine Software • komplexe Betriebssysteme – Unix, Win XP • Workstations, PCs Zunehmende Kosten 2.11 Fazit: Prozessorklassen 2.11 Fazit: Der Prozessor-Design-Raum Leistung Anwendungsspezifische Architekturen für hohe Leistung Eingebettete Prozessoren Mikroprozessoren Leistung ist alles & Software regiert Microcontroller Kosten sind alles! Kosten Fachbereich Informatik | Prof. Dr. Frederik Armknecht | 110