Sie sind auf Seite 1von 103

Vorlesung Rechnersysteme I

Kapitel 3
Architektur

© Christian Hochberger, TU Darmstadt


Abstraktionsebenen digitaler Systeme


Architektur definiert eine weitere Nicht Stoff
Abstraktionsebene digitaler Anwendung von RS1
Systeme
Betriebssystem

Beschreibt die Sicht des Dieses Kapitel
Programmierers auf die Architektur
Maschine
Mikroarchitektur Kommt nach
Architektur
Logische Grundschaltungen
Bekannt aus
Gatter
„Logischer Entwurf“
Transistoren
© Christian Hochberger, TU Darmstadt Architektur-Begriff 2
Elemente der Architektur


Definiert durch
– Befehlssatz der Maschine
– Art und Ort von Operanden

Befehlssatz
– Beschreibt die Sprache eines Computers
– Befehle (Instruktionen) sind die Worte der Sprache
– Ist für alle Programme gleich

Befehle
– Beschreiben Art der Operation (Was zu tun ist)
– Ort der Operanden (Womit es zu tun ist)

Operanden kommen aus
– dem Speicher / den Registern / dem Befehl selber
© Christian Hochberger, TU Darmstadt Architektur-Begriff 3
Maschinen- und Assembler-Sprache


Befehle sind binär codierte Zahlen
– Bitmuster sind Maschinensprache des Computers
– Mikroprozessoren lesen und verarbeiten Maschinen-Instruktionen

Menschen können Bitmuster schlecht lesen
– Alternative Darstellungsform: Assemblersprache
– Symbolische Beschreibung von Instruktionen

Fast alle Architekturen enthalten bestimmte Befehle
– Addition, Subtraktion, Sprünge
– Erlauben Zugriff auf Speicher und Register

„Kann man eine, kann man alle“
© Christian Hochberger, TU Darmstadt Architektur-Begriff 4
Architektur und Mikroarchitektur


Architektur ist unabhängig von konkreter HW-Implementierung

Zu einer Architektur können verschiedene Mikroarchitekturen existieren
– AMD und Intel nutzen beide IA32 (x86)
– Jeder stellt verschiedene Varianten her
– Varianten sind optimiert auf Performance, Kosten, Leistung, Energieeffizienz, ...

© Christian Hochberger, TU Darmstadt Architektur-Begriff 5


MIPS Architektur


Welche Architektur sollte man als erstes lernen?
– Reale Architekturen?
– Fantasie-Architekturen?
– Gute Architekturen?

MIPS stellt guten Kompromiss dar
– Kommerziell erfolgreich
– Aber nicht so kompliziert und mit historischem Ballast wie IA32

MIPS
– Erfunden ca. 1984 von John Hennessy in Stanford
– In vielen Geräten benutzt (Router, Spielekonsolen, ...)

© Christian Hochberger, TU Darmstadt Architektur-Begriff 6


Assembler Sprache


Assembler Befehle
– sind für Menschen lesbar
– Beschreiben Operation und zu verwendende Operanden

Einführung
– Zuerst nur einfache arithmetische Befehle
– Dann Art und Ort von Operanden in MIPS
– Viele Beispiele werden durch Vergleich mit Hochsprachen-Konstrukten erklärt
– Wir verwenden C (sollte aber für jeden verständlich sein)

© Christian Hochberger, TU Darmstadt Assembler 7


Einfache Befehle


Einfachster Fall: Addition

Beispiel zeigt
– Addition von b und c, Ergebnis wird nach a geschrieben
Hochsprache MIPS Assembler
a = b + c; add a, b, c


Kommentare
– C-Konstrukte enden mit ;
– add wird Mnemonic genannt (mnemotechnische Abkürzung)
– b und c sind die Quellen, a ist das Ziel
– Reihenfolge der Operanden legt Bedeutung fest
© Christian Hochberger, TU Darmstadt Assembler 8
Design Principle 1


„Simplicity favors regularity“

Bespiel zeigt Subtraktion
Hochsprache MIPS Assembler
a = b - c; sub a, b, c


Regularität
– Befehle mit gleicher Anzahl Operanden haben gleiche Struktur
– Vereinfacht Ausführung und Codierung
– Komplexere Fälle lassen sich so nicht beschreiben

© Christian Hochberger, TU Darmstadt Assembler 9


Design Principle 2


„Make the common case fast“ Hochsprache MIPS Assembler
a = b + c - d; # $s0=a, $s1=b, $s2=c, $s3=d

Komplexere Konstrukte als add $t0, $s1, $s2 # t=b+c
Komposition von einfachen: sub $s0, $t0, $s3 # a=t-d


Ausführung wird zusammengesetzt Kommentare in Assembler

Beginnen mit „#“
– t wird als Hilfsvariable benutzt ●
Gehen bis zum Ende der Zeile

– Nur einfache Rechenbefehle werden bereitgestellt


(sind leichter zu implementieren)

Komplexe Fälle seltener

Einfache Fälle häufiger (common case)

© Christian Hochberger, TU Darmstadt Assembler 10


RISC ↔ CISC


Wenige Befehle → Dekodierlogik einfach (und schnell)
– Komplexe Fälle seltener
– Einfache Fälle häufiger (common case)

MIPS gilt als Reduced Instruction Set Computer (RISC)

Alternative: Complex Instruction Set Computer (CISC)
– Beispiel: IA32 → Instruktion „String move“
– Muss in RISC durch viele (evtl. hunderte) Instruktionen ersetzt werden

RISC Architekturen minimieren HW Komplexität
– Durch niedrige Zahl unterschiedlicher Instruktionen
– Durch niedrige Zahl von Bits für die Kodierung
© Christian Hochberger, TU Darmstadt Assembler 11
Operanden


Befehle arbeiten mit Operanden
– Beispiele benutzen Variablen-Namen
– Computer muss aber wissen wo diese gespeichert sind

Operanden
– Können im Speicher oder in Registern liegen
– Können Konstanten sein

Sind dann Teil der Instruktion
– Alle Fälle treten auf

Schneller Zugriff, wenig Auswahlmöglichkeiten
– Konstanten oder Register

Langsamer Zugriff, große Kapazität
– Speicher
© Christian Hochberger, TU Darmstadt Assembler 12
Register


Befehle brauchen schnellen Zugriff auf Operanden
– Hauptspeicher langsam
– Nur kleine Zahl von Registern in Befehlen

MIPS
– 32 Register mit 32 Bit Breite
– Registersatz oder Register File genannt

Zugriffsgeschwindigkeit
– Wenige Register → kleiner Dekoder → Schnell
– Viele Register → großer Dekoder → nicht so schnell

Registersatz meist in SRAM realisiert
© Christian Hochberger, TU Darmstadt Assembler 13
Registernamen


Durch MIPS Konvention festgelegt

Nochmal das Additionsbeispiel:
Hochsprache MIPS Assembler
a = b + c; # $s0=a, $s1=b, $s2=c
add $s0, $s1, $s2 # a = b + c


MIPS Register
– Durch „$“ am Anfang gekennzeichnet
– Befehl addiert zwei 32-Bit Zahlen ($s1, $s2) und speichert das Ergebnis in einem
32-Bit Register ($s0)

© Christian Hochberger, TU Darmstadt Assembler 14


Registernamen (2)


Nochmal das komplexere Beispiel:
Hochsprache MIPS Assembler
a = b + c - d; # $s0=a, $s1=b, $s2=c, $s3=d
add $t0, $s1, $s2 # t=b+c
sub $s0, $t0, $s3 # a=t-d


MIPS Konvention
– Variablen werden in 18 von 32 Registern gespeichert
– $s0 - $s7 → Saved Registers (Variablen)

Besondere Bedeutung bei Funktionsaufrufen
– $t0 - $t9 → Temporary Registers (Hilfsvariablen)
– $t0 speichert Zwischenergebnis b+c

© Christian Hochberger, TU Darmstadt Assembler 15


Hochsprachenbeispiel


Aufgabe:
– Übersetze folgende Hochsprachenkonstrukte in Assembler
a = b – c;
f = (g + h) – (i + j);

– a-c sind in $s0 - $s2 gespeichert


– f-j sind in $s3 - $s7 gespeichert
# MIPS Assembly Code
# $s0=a, $s1=b, $s2=c, $s3=f, $s4=g, $s5=h, $s6=i, $s7=j

sub $s0, $s1, $s2 # a = b – c


add $t0, $s4, $s5 # $t0 = g + h
add $t1, $s6, $s7 # $t1 = i + j
sub $s3, $t0, $t1 # f = (g + h) – (i + j)

© Christian Hochberger, TU Darmstadt Assembler 16


MIPS Registersatz


Insgesamt 32 Register Name Nummer Bedeutung
verfügbar $0 0 constant 0
$at 1 assembler temporary

Spezialfall Register 0: $v0-$v1 2-3 function return value
– Beim Lesen immer 0 $a0-$a3 4-7 function arguments
$t0-$t7 8-15 temporary variables
– Schreiben wird ignoriert $s0-$s7 16-23 saved variables

Weitere Register $t8-$t9 24-25 temporary variables

→ werden später erklärt $k0-$k1 26-27 operating system temporaries


$gp 28 global pointer
$sp 29 stack pointer
$fp 30 frame pointer
$ra 31 return adress
© Christian Hochberger, TU Darmstadt Assembler 17
Speicher


Register als Speicher für Variablen zu klein

Hauptspeicher
– kann auch zum Speichern von Daten verwendet werden
– Aber: Zugriff langsam

Konsequenz:
– Oft benutzte Variablen in Registern halten
– Bedeutung der Register ändert sich während des Programms

MIPS:
– Speicher 32 Bit breit, Adressen 32 Bit breit

© Christian Hochberger, TU Darmstadt Assembler 18


Byte- und Word Adressierung


Wortadressierung
– Jedes Wort eine eigene Adresse
– Aufeinander folgende Worte → um 1 erhöhte Adresse

Wort Adresse Daten

... ... ...

0000003 40F30788 Wort 3

0000002 01EE2842 Wort 2


Steigende
Adressen 0000001 F2F1AC07 Wort 1

0000000 ABCDEF78 Wort 0


Hexadezimale Zahlen

© Christian Hochberger, TU Darmstadt Assembler 19


MIPS - Speicheradressierung


Speicheradresse immer eine Summe
– Basisadresse → kommt aus Register
– Offset → Wird hinzu addiert, Teil des Befehls
– Wird Register relative Adressierung genannt

Zugriff auf Speicher
– load word Instruktion
# Assembly Code (non MIPS), word addressable memory
lw $s3, 1($0) # Wort 1 aus Speicher lesen
# und in $s3 ablegen
sw $s7, 5($0) # $s7 in Wort 5 abspeichern

– Effektive Adresse beim Lesen: 0 + 1


– Effektive Adresse beim Schreiben: 0 + 5
© Christian Hochberger, TU Darmstadt Assembler 20
Byte- und Word Adressierung (2)


Byteadressierung
– Jedes Byte eine eigene Adresse
– Aufeinander folgende Bytes → um 1 erhöhte Adresse
– Aufeinander folgende Worte → um 4 erhöhte Adresse

Neben load/store word gibt es
dann auch load/store byte (lb, sb) Wortadressen Daten

... ... ...

0000000C 40 F3 07 88 Wort 3

00000008 01 EE 28 42 Wort 2

00000004 F2 F1 AC 07 Wort 1

00000000 AB CD EF 78 Wort 0

© Christian Hochberger, TU Darmstadt Assembler 21


Big- und Little-Endian


Welche Adresse gehört denn zu welchem Byte?
– Zwei mögliche Antworten
– MSB auf Adresse 0, LSB auf Adresse 3
→ Big-Endian
– MSB auf Adresse 3, LSB auf Adresse 0
→ Little Endian Wortadressen Daten

... ... ...

0000000C 40 F3 07 88 Wort 3

00000008 01 EE 28 42 Wort 2

00000004 F2 F1 AC 07 Wort 1
0 1 2 3
00000000 AB CD EF 78 Wort 0
3 2 1 0
© Christian Hochberger, TU Darmstadt Assembler 22
Big- und Little-Endian (2)
0x.... übliche Schreibweise
für Hexadezimalzahlen

Beispiel:
– $s0 enthält 0x23456789
# Assembly Code, byte addressable memory
sw $s0, 0($0)
lb $s0, 1($0)


store word schreibt in Wort 0 (egal ob Big- oder Little)

Big-Endian Byte Adresse 0 1 2 3
Datum 23 45 67 89
– $s0 enthält 0x00000045
MSB LSB

Little-Endian Byte Adresse 3 2 1 0
– $s0 enthält 0x00000067 Datum 23 45 67 89
MSB LSB
© Christian Hochberger, TU Darmstadt Assembler 23
Ausrichtung


Auf welchen Adressen dürfen Worte liegen?
– Nur auf Adressen, die durch 4 teilbar sind
→ Ausrichtung auf Worte (word allignment)
– Auf allen Adressen
→ keine Ausrichtung (unaligned)

Von Prozessorarchitektur abhängig
– MIPS: Nur ausgerichtete Zugriffe möglich

Vereinfacht Bus-Logik
– IA32: Unausgerichtete Zugriffe möglich

Vereinfacht Programmierung

lb und sb müssen nicht ausgerichtet werden
© Christian Hochberger, TU Darmstadt Assembler 24
Konstanten


load word und store word enthalten Konstanten
– Offset, der zur Basis-Adresse addiert wird
– Teil des Befehlswortes

Weitere Instruktionen mit Konstante
– add immediate, addi
High-Level Code Assembly Code
a = a + 4; addi $s0, $s0, 4
b = a – 12; addi $s1, $s0, -12

– MIPS: Konstante ist 16 Bit Zweierkomplement Zahl


– Wertebereich [-32768, 32767]

© Christian Hochberger, TU Darmstadt Assembler 25


Design Principle 4


„Good design demands good compromises“

add und sub: 3 Register-Operanden

lw, sw und addi: 2 Register-Operanden, 1 Konstante

Design Principle 1 (Simplicity favors Regularity)
– Alle Befehle müssten gleiches Format haben
– Wäre starke Einschränkung (Konstanten wären kleiner)
– Prinzip wird bewusst verletzt

Verschiedene Befehlsformate verbessern die Effizienz des Befehlssatzes

MIPS: Insgesamt drei verschiedene Befehlsformate

© Christian Hochberger, TU Darmstadt Assembler 26


Maschinensprache


Hardware kann nur Bitmuster verarbeiten
– Assembler muss in Maschinensprache übersetzt werden

MIPS:
– Alle Instruktionen 32 Bit breit
– Manche Instruktionen könnte man mit weniger Bit codieren
– Einheitliche Länge hat viele Vorteile
– Drei Befehlstypen (Befehlsformate)

Unterscheidung bzgl. der Operanden

R-Typ: 3 Register

I-Typ: 2 Register und Konstante

J-Typ: 1 Konstante mit 26 Bit

© Christian Hochberger, TU Darmstadt Maschinensprache 27


R-Typ


R-Typ → Register-Typ: 3 Register als Operanden
– 2 Register Quelle (rs, rt)
– 1 Register Ziel (rd)

Befehl besteht aus 6 Bit-Gruppen: op, rs, rt, rd, shamt, funct

op und funct definieren zusammen die Bedeutung
– op immer 0 (bei R-Typ) R-Typ
– funct: add → 32, sub → 34 op rs rt rd shamt funct

shamt 6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit
– Nur bei Schiebe-Operationen (sonst immer 0)
– Bestimmt um wie viele Bit geschoben wird

© Christian Hochberger, TU Darmstadt Maschinensprache 28


R-Typ Beispiele


Reihenfolge der Register unterschiedlich in Maschinen- und
Assemblersprache

Code-Beispiel # MIPS Assembly Code
add $t0, $s1, $s2 # t=b+c
sub $s0, $t0, $s3 # a=t-d
Assembler Code Bit-Felder

add $t0,$s1,$s2 0 17 18 8 0 32

sub $s0,$t0,$s3 0 8 19 16 0 34

6 Bit 5 Bit 5 Bit 5 Bit 5 Bit 6 Bit


op rs rt rd shamt func
000000 10001 10010 10000 00000 100000 0x02328020

000000 01000 10011 10000 00000 100010 0x01738022

Maschinen-Code Speicherwort
© Christian Hochberger, TU Darmstadt Maschinensprache 29
I-Typ


I-Typ → Immediate Typ, Konstante im Befehl
– 1 Register Quelle (rs)
– 1 Register Ziel (rt), evtl. auch zweite Quelle (sw)

Befehl besteht aus 4 Bit-Gruppen: op, rs, rt, imm

op definiert Operation I-Typ

op rs rt imm
– 8: addi, 35: lw, 43: sw
6 Bit 5 Bit 5 Bit 16 Bit

imm 16 Bit breit
– Nicht immer K2-Zahl (logische Operationen)

© Christian Hochberger, TU Darmstadt Maschinensprache 30


I-Typ Beispiel

Assembler Code Bit-Felder

addi $s0,$s1,5 8 17 16 5

addi $t0,$s3,-12 8 19 8 -12

lw $t2,32($0) 35 0 10 32

sw $s1,4($t1) 43 9 17 4

6 Bit 5 Bit 5 Bit 16 Bit


op rs rt imm
001000 10001 10000 0000 0000 0000 0101 0x22300005

rt bei sw auch 001000 10011 01000 1111 1111 1111 0100 0x2268FFF4
Quelle für 100011 00000 01010 0000 0000 0010 0000 0x8C0A0020
Operanden
101011 01001 10001 0000 0000 0000 0100 0xAD310004

Maschinen-Code Speicherwort
© Christian Hochberger, TU Darmstadt Maschinensprache 31
J-Typ


J-Typ → Jump Typ, speziell für Sprungbefehle

Nur ein Operand
J-Typ
– 26 Bit Adresse
op addr
– Genauere Erklärung später
6 Bit 26 Bit

op
– Verschiedene Arten von Sprüngen möglich
– Alle Sprünge sind unbedingt

© Christian Hochberger, TU Darmstadt Maschinensprache 32


Maschinenprogramme interpretieren


Zunächst: Entschlüsseln der Felder des Befehls
– Verschiedene Formate für verschiedene Befehlstypen
– Befehlstyp durch op festgelegt
– op immer an gleicher Position
→ op zuerst entschlüsseln
– op=0 → R-Typ
– op≠0 → I-Typ oder J-Typ
– Weitere Felder nach Befehlstyp entschlüsseln

© Christian Hochberger, TU Darmstadt Maschinensprache 33


Maschinenprogramme interpretieren (2)


Beispielanweisungen:
– 0x2237FFF1
– 0x02F34022

0010 0010 0011 0111 1111 1111 1111 0001
8 → addi rs = 17 rt = 23 imm = -15

addi $s7,$s1, -15


0000 0010 1111 0011 0100 0000 0010 0010
0 → R-Typ rs = 23 rt = 19 rd = 8 shamt=0 func=34 → sub
sub $t0,$s7,$s3

© Christian Hochberger, TU Darmstadt Maschinensprache 34


Gespeicherte Programme


Jeder Befehl 32 Bit breit
– Programm → Sequenz von 32 Bit Worten
– Können im Speicher abgelegt werden

Basis für Mächtigkeit von Computern
– Programm im Speicher kann ausgetauscht werden
– Neue Anwendung → einfach Speicherinhalt austauschen

Oft als General Purpose Computing bezeichnet

Prozessor:
– Holt Befehle aus dem Speicher
– Führt sie aus
© Christian Hochberger, TU Darmstadt Maschinensprache 35
Gespeicherte Programme (2)


Ausführen eines Programms
– Prozessor holt Befehle nacheinander aus Speicher
– Aufeinander folgende Befehle liegen im Speicher hintereinander
– Adresse des aktuellen Befehls liegt in speziellem Register:
Program Counter, PC

MIPS:
– PC gehört nicht zum Registersatz
– Programme beginnen bei 0x00400000
– PC wird nach jedem Befehl um 4 erhöht
(Ausnahme: bedingte oder unbedingte Sprünge)

© Christian Hochberger, TU Darmstadt Maschinensprache 36


Maschinen Status


Maschinen Status
– Speichert Zustand eines Programms
– MIPS: Registersatz und PC

Konsequenz
– Betriebssystem kann Maschinen Status retten (irgendwo abspeichern)
– Programm wird unterbrochen
– Betriebssystem restauriert Maschinen Status
– Programm kann weiterarbeiten (als ob nie was passiert wäre)

© Christian Hochberger, TU Darmstadt Maschinensprache 37


Programmierung


Typische Elemente von Hochsprachen
– Logische und arithmetische Operationen
– if/else Anweisungen
– for und while Schleifen
– Array-Zugriffe
– Funktionsaufrufe

Wie werden diese Elemente in Assembler realisiert?
– Exemplarische Diskussion
– Prinzipien zeigen

© Christian Hochberger, TU Darmstadt Programmierung 38


Logische Befehle


Unterstützte Operationen:
– Bit-weise Verknüpfung der Quell-Register
– and, or, xor, nor
– R-Typ Befehle Quell-Register

$s1 1111 1111 1111 1111 0000 0000 0000 0000

$s2 0100 0110 1010 0001 1111 0000 1011 0111

Assembler Befehl Ergebnisse

and $s3,$s1,$s2 $s3 0100 0110 1010 0001 0000 0000 0000 0000

or $s4,$s1,$s2 $s4 1111 1111 1111 1111 1111 0000 1011 0111

xor $s5,$s1,$s2 $s5 1011 1001 0101 1110 1111 0000 1011 0111

nor $s6,$s1,$s2 $s6 0000 0000 0000 0000 0000 1111 0100 1000

© Christian Hochberger, TU Darmstadt Programmierung 39


Logische Befehle (2)


and kann zur Maskierung benutzt werden
– Maske enthält 1 Bits an den gewünschten Stellen
– Unerwünschte Bits werden zu 0

or kann zum Kombinieren von Registern benutzt werden
– Bit-Gruppen in einem Register erzeugen
– Zu anderem Register hinzufügen
– Häufig zusammen mit Maskierung

MIPS hat kein not
– Kann durch nor mit $0 ersetzt werden
– nor $s1, $0, $s0 → $s1 = (0 or $s0) = $s0

© Christian Hochberger, TU Darmstadt Programmierung 40


Logische Befehle (3)


and, or und xor auch mit Konstante möglich
→ andi, ori, xori (and immediate, or immediate, …)

Befehle dann I-Typ
– Konstante Teil des Befehlswortes
– Konstante nur 16 Bit breit (Keine Vorzeichenerweiterung → mit 0 auffüllen)
Quell-Register

$s1 0000 0000 0000 0000 0000 0000 1111 1111

imm 0000 0000 0000 0000 1111 1010 0011 0100

Assembler Befehl Ergebnisse

andi $s2,$s1,0xFA34 $s2 0000 0000 0000 0000 0000 0000 0011 0100

ori $s3,$s1,0xFA34 $s3 0000 0000 0000 0000 1111 1010 1111 1111

xori $s4,$s1,0xFA34 $s4 0000 0000 0000 0000 1111 1010 1100 1011

© Christian Hochberger, TU Darmstadt Programmierung 41


Schiebebefehle


Drei Typen von Schiebe-Operationen
– sll (shift left logical) , srl (shift right logical), sra (shift right arithmetic)
– R-Typ Befehl, aber rs wird ignoriert
– Schiebeweite steht in shamt
Quell-Register

$s1 1111 0011 0000 0000 0000 0010 1010 1000

shamt 0 0100

Assembler Befehl Ergebnisse

sll $t0, $s1, 4 $s2 0011 0000 0000 0000 0010 1010 1000 0000

srl $t0, $s1, 4 $s3 0000 1111 0011 0000 0000 0000 0010 1010

sra $t0, $s1, 4 $s4 1111 1111 0011 0000 0000 0000 0010 1010

© Christian Hochberger, TU Darmstadt Programmierung 42


Schiebebefehle (2)


Schieben mit variabler Bit-Anzahl möglich
– sllv, srlv, srav
– R-Typ Befehle
– rs legt Register fest, in dem die Schiebeweite steht
– shamt wird ignoriert Quell-Register

$s1 1111 0011 0000 0100 0000 0010 1010 1000

$s2 0000 0000 0000 0000 0000 0000 0000 1000

Assembler Befehl Ergebnisse

sllv $s3,$s1,$s2 $s3 0000 0100 0000 0010 1010 1000 0000 0000

srlv $s4,$s1,$s2 $s4 0000 0000 1111 0011 0000 0100 0000 0010

srav $s5,$s1,$s2 $s5 1111 1111 1111 0011 0000 0100 0000 0010

© Christian Hochberger, TU Darmstadt Programmierung 43


Konstante Laden


16 Bit K2 Konstante mithilfe des addi Befehls
High-Level Code Assembly Code
a = 0x4397; # a = $s0
addi $s0, $0, 0x4397


32 Bit Konstante mithilfe zweier Befehle
– lui → lädt obere 16 Bit des Zielregisters
– ori → fügt untere 16 hinzu
High-Level Code Assembly Code
a = 0xDEADBEEF; # a = $s0
lui $s0, 0xDEAD
ori $s0, $s0, 0xBEEF

© Christian Hochberger, TU Darmstadt Programmierung 44


Multiplikation und Division


Multiplikation von 32 Bit Zahlen kann 64 Bit Ergebnis liefern

Zwei Multiplikationsbefehle
– mult → op1 * op2, Ergebnis in Spezialregistern hi und lo
– hi und lo nicht Teil des Registersatzes
– mul → op1 * op2, untere 32 Bit des Ergebnisses in dest

Division
– Quotient und Rest interessant
– div → Berechnet op1/op2, Quotient nach lo, Rest nach hi

Zugriff auf hi und lo
– mflo, mfhi (move from hi/lo) → Transportiert hi/lo in Zielregister
© Christian Hochberger, TU Darmstadt Programmierung 45
Verzweigungen


Englisch: Branch
– Bedingt/Unbedingt

PC Behandlung
– Normalerweise: PC = PC + 4 nach jeder Anweisung
– Bei ausgeführtem Sprung: PC wird manipuliert

Programmstücke auslassen (überspringen)

Programmstücke wiederholen (Schleifen)

Bedingte Sprünge
– Werten Bedingung aus
– Bedingung erfüllt → Sprung ausführen
– Bedingung nicht erfüllt → PC = PC + 4
© Christian Hochberger, TU Darmstadt Programmierung 46
Bedingte Sprünge


Zwei Formen, beide I-Typ
– beq (branch equal) → Springt wenn Register gleich sind
– bne (branch not equal)→ Springt wenn Register ungleich sind
# MIPS Assembly Code
Sprungziel
addi $s0, $0, 4 # $s0 = 0 + 4 symbolisch angegeben
addi $s1, $0, 1 # $s1 = 0 + 1
sll $s1, $s1, 2 # $s1 = 1 << 2 = 4
beq $s0, $s1, target # $s0==$s1 → SprungCode
# MIPS Assembly durchführen
addi $s1, $s1, 1 # nicht ausgeführt
addi $s0, $0, 4 # $s0 = 0 + 4
sub $s1, $s1, $s0 # nicht ausgeführt
addi $s1, $0, 1 # $s1 = 0 + 1
sll $s1, $s1, 2 # $s1 = 1 << 2 = 4
target: bne $s0, $s1, target # $s0==$s1 → nicht springen
add $s1, $s1, $s0 # $s1 addi
= $s1$s1,
+ $s0
$s1, 1 # $s1 = $s1 + 1
Definition eines Labels, sub $s1, $s1, $s0 # $s1 = $s1 - $s0
kann als Sprungziel benutzt werden
target:
add $s1, $s1, $s0 # $s1 = $s1 + $s0
© Christian Hochberger, TU Darmstadt Programmierung 47
Bedingte Sprünge (2)


Labels
– Symbolische Marken im Assembler-Quelltext
– Werden beim Übersetzen mit einer Adresse belegt
(ergibt sich aus dem PC an dieser Stelle)
– Dürfen keine reservierten Worte sein

Konvention
– Code einrücken, Label nicht
– Label kann auch auf gleicher Zeile mit Befehl stehen

© Christian Hochberger, TU Darmstadt Programmierung 48


Sprünge (Jumps)


Unbedingte Sprünge
– Unterschied zum Branch → Absolute Adresse

Drei Typen
– j → Setze PC auf Adresse aus Befehl
– jal (jump and link)→ Setze PC auf Adresse und speichere Folgeadresse in R31
– jr → Setze PC auf Adresse aus Register
– j und jal nutzen J-Typ
– jr nutzt R-Typ (auch wenn nur ein Register gebraucht wird)

© Christian Hochberger, TU Darmstadt Programmierung 49


Bedingte Anweisungen


If-Anweisung
– Block von Anweisungen wird nur ausgeführt, wenn Bedingung erfüllt

Assembler
– Umgekehrte Bedingung prüfen
– Erfüllt: Über den Anweisungsblock hinweg springen

High-Level Code Assembly Code


if (i==j) # $s0=f, $s1=g, $s2=h, $s3=i,$s4=j
f=g+h; bne $s3,$s4,L1
add $s0,$s1,$s2
f=f-i; L1:
sub $s0,$s0,$s3

© Christian Hochberger, TU Darmstadt Programmierung 50


Bedingte Anweisungen (2)


If/else Anweisung
– Nur einer der beiden Blöcke wird ausgeführt

Assembler
– Am Ende des then-Blocks hinter den else-Block springen

High-Level Code Assembly Code


if (i==j) # $s0=f, $s1=g, $s2=h, $s3=i,$s4=j
f=g+h; bne $s3,$s4,L1
else add $s0,$s1,$s2
f=f-i; j L2
L1:
sub $s0,$s0,$s3
L2:

© Christian Hochberger, TU Darmstadt Programmierung 51


while Schleifen


Wiederhole Schleifenkörper bis Bedingung nicht mehr erfüllt ist

Assembler
– Umgekehrte Bedingung prüfen, hinter Schleife springen
– Am Ende des Körpers → Zur Prüfung springen
High-Level Code Assembly Code
int pow=1; # $s0=pow, $s1=x
int x=0; addi $s0,$0,1
while (pow!=128) { addi $s1,$0,0
pow=pow*2; addi $t0,$0,128
x++; while:
} beq $s0,$t0,done
sll $s0,$s0,1
addi $s1,$s1,1
j while
done:

© Christian Hochberger, TU Darmstadt Programmierung 52


for Schleifen


Ähnlich wie while Schleife
– Schleifenkörper wiederholen, bis Bedingung nicht mehr erfüllt

Allgemeine Struktur:
for (Initialisierung; Bedingung; Weiterschaltung) Anweisung

Zusätzlich
– Initialisierung → Einmal vor Betreten der Schleife
– Weiterschaltung → Am Ende des Körpers

© Christian Hochberger, TU Darmstadt Programmierung 53


for Schleifen (2)


Addiere die Zahlen von 0 - 9
High-Level Code Assembly Code
int sum=0; # $s0=i, $s1=sum
int i; addi $s1,$0,0
addi $t0,$0,10 # Für den Vergleich

for (i=0; i!=10; i++) { addi $s0,$0,0 # Initialisierung


sum=sum+i; for:
} beq $s0,$t0,done
add $s1,$s1,$s0

addi $s0,$s0,1 # Weiterschaltung


j for
done:

© Christian Hochberger, TU Darmstadt Programmierung 54


Größenvergleiche


beq und bne erlauben nur Prüfung auf Identität

In realen Programmen:
– Richtige Vergleiche erforderlich: <, ≤, >, ≥
– Neue Befehle erforderlich

slt (set less then)
– Setzt Zielregister auf 1, wenn op1 < op2
– Ansonsten Zielregister = 0

Andere Vergleiche nicht verfügbar
– > → Operanden vertauschen
– ≥ → Negation von < (auf Ergebnis 0 prüfen)
© Christian Hochberger, TU Darmstadt Programmierung 55
Größenvergleiche (2)


Beispiel:
– Summe aller Zweierpotenzen < 101 berechnen
High-Level Code Assembly Code
int sum=0; # $s0=i, $s1=sum
int i; addi $s1,$0,0
addi $t0,$0,101 # Für den Vergleich

for (i=1; i<101; i=i*2) { addi $s0,$0,1 # Initialisierung


sum=sum+i; for:
} slt $t1,$s0,$t0
beq $t1,$0,done
add $s1,$s1,$s0

sll $s0,$s0,1 # Weiterschaltung


j for
done:

© Christian Hochberger, TU Darmstadt Programmierung 56


Arrays


Häufig benutzte Datenstruktur in Hochsprachen
– Index bestimmt, welches Element benutzt wird
– Anzahl der Elemente definiert Größe des Arrays Adresse Daten
0x10007010 array[4]
0x1000700C array[3]

High-Level Code Assembly Code 0x10007008 array[2]


int array[5]; # $s0=Basisadresse von array 0x10007004 array[1]
lui $s0,0x1000
ori $s0,0x7000 0x10007000 array[0]

array[0]=array[0]*8; lw $t0,0($s0)
sll $t0,$t0,3
sw $t0,0($s0)
array[1]=array[1]*8; lw $t0,4($s0)
sll $t0,$t0,3
sw $t0,4($s1)
© Christian Hochberger, TU Darmstadt Programmierung 57
Arrays (2)


Beispiel verwendet konstanten Index

In realen Anwendungen: Index aus Variable
High-Level Code Assembly Code
int i; # $s0=Basisadresse von array, $s1=i
int array[1000]; lui $s0,0x23BB
ori $s0,0xF000
addi $t2,$0,1000 # Für Vergleich
addi $s1,$0,0 # Initialisierung
for (i=0; i<1000; i++) { for:
array[i]=array[i]*8; slt $t0,$s1,$t2 Index skalieren
} beq $t0,$0,done (mit 4 multiplizieren)
sll $t0,$s1,2
add $t0,$s0,$t0 Effektive Adresse
lw $t1,0($t0) berechnen
sll $t1,$t1,3 Basis + Index(skaliert)
sw $t1,0($t0)
addi $s1,$s1,1 # Weiterschaltung
j for
done:
© Christian Hochberger, TU Darmstadt Programmierung 58
Byte-Arrays


Zugriff auf Arrays von Bytes
– lb (load byte) → Ein Byte aus Speicher holen, Vorzeichenerweiterung vornehmen
– lbu (load byte unsigned) → Ein Byte holen, mit 0 erweitern
– sb (store byte) → Ein Byte speichern
(Keine Unterscheidung von signed/unsigned nötig)

Byte häufig für Zeichen benutzt
– Kodierung: ASCII (veraltet), ISO-8859-1
– Manchmal auch Mehr-Byte Codes: UTF-8

© Christian Hochberger, TU Darmstadt Programmierung 59


Zeichenketten


Beispiel: Stringlänge berechnen
– In C: Letztes Zeichen eines String 0-Byte

High-Level Code Assembly Code


int i=0; # $s0=Basisadresse von string, $s1=i
char string[100]; lui $s0,0x1000
ori $s0,0xF000
addi $s1,$0,0

while (string[i]!=0) while:


i++; add $t0,$s0,$s1
lb $t0,0($t0)
beq $t0,$0,done
addi $s1,$s1,1
j while
done:

© Christian Hochberger, TU Darmstadt Programmierung 60


Unterprogramme


Typische SW-Struktur, um Programmteile wieder zu verwenden

Meist in Form von Funktionen
– Übergabe von Parametern/Argumenten
– Rückgabe eines Ergebnisses

Hierarchien von Funktionen
– Aus einer Funktion f1 wird f2 aufgerufen
– Aus f2 wird f3 aufgerufen
– …

Nomenklatur:
– Aufrufer, Aufgerufener
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 61
MIPS: Aufrufkonvention


Übergabe von Parametern/Argumenten
– Aufrufer platziert bis zu 4 Parameter in $a0 - $a3

Rückgabe von Ergebnissen
– Aufgerufener platziert Ergebnis in $v0 und $v1

Konvention erlaubt,
– dass UPs benutzt werden können, ohne sie selbst geschrieben zu haben
– dass UPs in anderen Programmiersprachen geschrieben werden

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 62


MIPS: Aufrufkonvention (2)


Aufgerufener darf Aufrufer nicht stören
– Programm muss nach Ende von Aufgerufenem korrekt fortgesetzt werden
– Register des Aufrufers müssen erhalten bleiben
– Speicherbereiche des Aufrufers müssen erhalten bleiben

Rückkehr zum Aufrufer
– Aufrufer nutzt jal → Rücksprungadresse in $ra (R31)
– $ra darf von Aufgerufenem nicht zerstört werden

Register des Aufrufers
– $s0 - $s7 dürfen nicht verändert werden

Speicherbereiche
– Stack des Aufrufers muss erhalten bleiben
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 63
UPs: Minimalbeispiel


jal zum Aufruf von UPs
– Springt zum Aufgerufenen
– Rettet Rücksprungadresse (PC+4) in $ra Speichert
0x00400204 in $ra

jr zur Rückkehr zum Aufrufer
High-Level Code Assembly Code
int main() { 0x00400200 main: jal simple
simple(); 0x00400204 …

} Springt an Befehl
nach jal simple

// void → kein Ergebnis


void simple() { 0x00401020 simple: jr $ra
return;
}

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 64


Funktion mit Argumenten und Rückgabe

● Bis zu vier Argumente in Registern $a0-$a3


● Ergebnis in Registern $v0-$v1
High-Level Code Assembly Code
int main() { # y=$s0
int y; main: Eigentlich ein
… addi $a0,$0,2 move
y=diffofsums(2,3,4,5); addi $a1,$0,3
… addi $a2,$0,4
} addi $a3,$0,5
jal diffofsums
add $s0,$0,$v0
… Vorsicht: So nicht korrekt
int diffofsums(int f, int g, diffofsums: Richtige Variante folgt später
int h, int i) { add $t0,$a0,$a1
int result; add $t1,$a2,$a3
result=(f+g)-(h+i); sub $s0,$t0,$t1
return result; add $v0,$0,$s0
} jr $ra Kann durch Optimierung
eingespart werden
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 65
Stack


Spezieller Speicherbereich
– Zum Retten von Registern
– Zur Übergabe von Parametern (wenn mehr als 4)
– Wächst und schrumpft dynamisch

Stack (allgemein)
– Last-in-first-Out Warteschlange
– Etwas zum Stack hinzufügen → push
– Etwas vom Stack wegnehmen → pop
– Funktionen können auf dem Stack Platz reservieren
(muss vor Rückkehr wieder freigegeben werden)

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 66


Stack in MIPS


MIPS: Stack wächst nach unten!
● Spezielles Register $sp
– Stack Pointer
– Zeigt auf niedrigste benutzte Adresse

Zwei Worte auf den Stack legen:
– $sp = $sp-8
– 1. Wort adressieren: lw/sw 4($sp)
– 2. Wort adressieren: lw/sw 0($sp)

Platz wieder freigeben
– $sp = $sp+8
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 67
Stack-Nutzung


Hauptaufgabe
– Retten von Registern beim Betreten einer Funktion
– Restaurieren der Register am Ende der Funktion

Vorgehensweise
– Platz für alle zu rettenden Register auf dem Stack reservieren
– Register auf den Stack legen
– Funktion ausführen
– Register-Inhalte wieder vom Stack lesen
– Reservierten Platz wieder freigeben

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 68


Stack-Nutzung – Beispiel

● diffofsums nutzt $t0, $t1, $s0 Assembly Code


diffofsums:
add $t0,$a0,$a1

Auf dem Stack müssen 3 Worte add $t1,$a2,$a3
reserviert werden sub $s0,$t0,$t1
add $v0,$0,$s0
jr $ra

Adresse Daten Adresse Daten Adresse Daten

0xFC ? ← $sp 0xFC ? 0xFC ? ← $sp


0xF8 0xF8 $s0 0xF8
0xF4 0xF4 $t0 0xF4
0xF0 0xF0 $t1 ← $sp 0xF0
... … ... … ... …
Vor Funktionsaufruf Während diffofsums Nach Funktionsaufruf
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 69
Stack-Nutzung – Beispiel (2)

● Modifizierter Code von diffofsums

Assembly Code Platz auf Stack reservieren


# $s0 = result
diffofsums:
addi $sp,$sp,-12
sw $s0,8($sp) Benutzte Register retten
sw $t0,4($sp)
sw $t1,0($sp)
add $t0,$a0,$a1
add $t1,$a2,$a3 Eigentliche Funktion
sub $s0,$t0,$t1
add $v0,$0,$s0
lw $t1,0($sp) Benutzte Register zurückholen
lw $t0,4($sp)
lw $s0,8($sp)
addi $sp,$sp,12
jr $ra Platz auf Stack freigeben

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 70


Erhaltene Register

● Wenn Aufrufer $t0 und $t1 gar nicht braucht


– Aufgerufener muss sie nicht retten

Konvention: Nicht alle Register werden vom Aufgerufenen gerettet

Assembly Code
# $s0 = result Weniger Platz auf Stack reservieren
diffofsums:
addi $sp,$sp,-4
sw $s0,0($sp) Nur $s0 retten
add $t0,$a0,$a1
add $t1,$a2,$a3
sub $s0,$t0,$t1
add $v0,$0,$s0 $s0 restaurieren
lw $s0,0($sp)
addi $sp,$sp,4
jr $ra

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 71


Erhaltene Register (2)

Erhaltene Register Nicht erhaltene Register


Saved Registers $s0-$s7 Temporary Register $t0-$t9
Return Address $ra Argument Register $a0-$a3
Stack Pointer $sp Return Value Register $v0-$v1
Stack oberhalb von $sp Stack unterhalb von $sp


Wenn Aufrufer ein nicht erhaltenes Register nach Aufruf noch braucht
– Vor Aufruf selber retten
– Nach Aufruf selber restaurieren

Aufteilung willkürlich (aber empirisch optimiert)

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 72


Rekursive Funktionen


Einteilung von Funktionen
– Leaf Funktionen

Rufen keine weiteren Funktionen auf

Einfacher zu programmieren
– Non-Leaf Funktionen

Rufen andere Funktionen auf
● Müssen nicht erhaltene Register selber retten (z.B. $a0-$a3, $t0-$t9)

Rekursive Funktionen
– Non-Leaf Funktion, die sich selbst aufruft
– Beispiel: Rekursive Berechnung der Fakultät

fak(x) = x*fak(x-1)

Kein rekursiver Aufruf, wenn x ==1
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 73
Rekursive Funktionen – Beispiel

$a0 + $ra immer retten


High-Level Code Assembly Code
int fak(int n) { 0x90 fak: addi $sp,$sp,-8
0x94 sw $a0,4($sp)
0x98 sw $ra,0($sp)
Rekursions- 0x9C addi $t0,$0,2
if (n<2) Verankerung 0xA0 slt $t0,$a0,$t0 $a0 + $ra nicht
return 1; 0xA4 beq $t0,$0,else restaurieren
0xA8 addi $v0,$0,1
0xAC addi $sp,$sp,8
0xB0 jr $ra
rekursiver Aufruf
else 0xB4 else: addi $a0,$a0,-1
mit $a0-1
return n*fak(n-1); 0xB8 jal fak
0xBC lw $ra,0($sp)
0xC0 lw $a0,4($sp)
0xC4 mul $v0,$a0,$v0
0xC8 addi $sp,$sp,8
} 0xCC jr $ra
$a0 + $ra restaurieren
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 74
Rekursive Funktionen – Stack-Entwicklung

Adresse Daten Adresse Daten Adresse Daten

0xFC ← $sp 0xFC ← $sp 0xFC ← $sp

0xF8 0xF8 $a0 (3) 0xF8 $a0 (3)

0xF4 0xF4 $ra (?) ← $sp 0xF4 $ra (?) $v0=3*2=6

0xF0 0xF0 $a0 (2) 0xF0 $a0 (2)

0xEC 0xEC $ra (0xBC) ← $sp 0xEC $ra (0xBC) $v0=2*1

0xE8 0xE8 $a0 (1) 0xE8 $a0 (1)

0xE4 0xE4 $ra (0xBC) ← $sp 0xE4 $ra (0xBC) $v0=1

0xE0 0xE0 0xE0

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 75


Funktionen: Mehr Argumente und lokale Variablen


Bisher:
– Maximal 4 Argumente (mit 32 Bit)
– Maximal 8 lokale Variablen (mit 32 Bit)

Mehr als 4 Argumente
– Erste 4 Argumente in $a0-$a3
– Zusätzliche Argumente auf Stack (oberhalb von $sp)
– Vom Aufrufer gemanaged

Vor Aufruf Platz auf Stack reservieren

Nach Aufruf Platz auf Stack wieder freigeben

Mehr als 8 lokale Variable (z.B. lokale Arrays)
– Beim Reservieren des Platzes im Aufgerufenen berücksichtigen
© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 76
Funktionen: Mehr Argumente und lokale Variablen (2)

Zusätzliche Argumente Zusätzliche Argumente


← $sp $a0-$a3
(nur falls gebraucht)

Stack Frame
$ra (nur falls gebraucht)
$s0-$s7
(nur falls gebraucht)
Lokale Variablen
und Arrays
← $sp

© Christian Hochberger, TU Darmstadt Programmierung Funktionsaufrufe 77


Adressierungsarten


Insgesamt 5 Adressierungsarten in MIPS

Drei kennen wir schon
– Register direkt

Registerinhalt wird direkt als Operand benutzt
– Immediate

Konstante im Befehl wird als Operand genutzt
– Register indirekt mit Offset (Base Addressing)

Adressierung von Operanden im Speicher

Lesen oder Schreiben

Berechnet aus Register und Offset (Konstante im Befehl)

© Christian Hochberger, TU Darmstadt Programmierung - Adressierungsarten 78


Adressierung – PC-Relative


Branch Befehle springen relativ zum PC
– Offset im Befehl wird vorzeichenerweitert
– Vorwärts- und Rückwärtssprünge möglich

Welcher Wert des PC wird zum Rechnen benutzt
– Intuitiv: PC des aktuellen Befehls
– Aus Mikroarchitektur-Gründen: PC+4

Sprungdistanz muss immer durch 4 teilbar sein
– Offset kann mit Faktor 4 skaliert werden
– Erhöht maximale Sprungdistanz
– (Nicht in allen RISC-Prozessoren so)

© Christian Hochberger, TU Darmstadt Programmierung - Adressierungsarten 79


Adressierung – PC-Relative Beispiel


Kodierung des beq Befehls Assembly Code
0xA4 beq $t0,$0,else
– Adresse des Sprungziels: 0xB4 0xA8 addi $v0,$0,1
0xAC addi $sp,$sp,8
– PC des Befehls: 0xA4 0xB0 jr $ra
0xB4 else: addi $a0,$a0,-1
– PC+4: 0xA8 0xB8 jal fak
– Differenz: 0xB4-0xA8 = 0x0C
– Skalieren (durch 4 teilen)

Offset im Befehl = 0x0C/4 = 3

I-Typ
beq $t0,$0,else 4 8 0 3

6 Bit 5 Bit 5 Bit 16 Bit

© Christian Hochberger, TU Darmstadt Programmierung - Adressierungsarten 80


Adressierung – Pseudo-Direct


Direkte Adressierung (absolute Adressierung)
– Vollständige Adresse Teil des Befehls
– j und jal könnten das nutzen
– Bei 32 Bit Adressen nicht möglich

Pseudo-Direct
– Befehl enthält 26 Adressbits
– Unterste zwei Adressbits nicht spezifiziert (weil immer 0)
– Fehlen immer noch Adressbits 31-28
– Werden aus dem aktuellen PC genommen
(Wieder: Aus Mikroarchitektur-Gründen PC+4)

© Christian Hochberger, TU Darmstadt Programmierung - Adressierungsarten 81


Arbeit mit „ echten“ Programmen


Bisher nur kurze Programmsequenzen

Echte Programme
– Bestehen aus mehreren Quelldateien/Bibliotheken
– Müssen nach dem Übersetzen richtig in den Speicher geladen werden

Aufgaben
– Compilieren
– Assemblieren
– Linken
– Laden

© Christian Hochberger, TU Darmstadt Programmierung 82


Speicheraufbau


Memory Map von MIPS Adresse Segment
– Fünf Bereiche 0xFFFFFFFC
– 2 Reservierte Bereiche Reserviert
0x80000000
– Text Segment (Programm)
0x7FFFFFFC Stack ← $sp=0x7FFFFFFC
– Global Data
Dynamic Data
– Dynamic Data Heap
0x10010000

Stack (wächst nach unten)
0x1000FFFC

Heap (wächst nach oben)
0x10000000
Global Data ← $gp=0x10008000
0x0FFFFFFC
Text
0x00400000 ← PC = 0x00400000
0x003FFFFC
Reserviert
0x00000000
© Christian Hochberger, TU Darmstadt Programmierung 83
Stadien eines Programms


Verschiedene Abstraktionsebenen des High-Level Code

Programms
Compiler
– High-Level Code
Assembly Code
C, C++, Java, …
Assembler
– Assembly Code
Object Files
symbolische Prozessoranweisungen Object File Library Files
– Object File Linker
Binär kodierte Anweisungen,
Executable
kein vollständiges Programm
Loader
– Executable
Vollständiges Programm Speicher

© Christian Hochberger, TU Darmstadt Programmierung 84


Compilieren


z.B. C → MIPS Assembler Assembly Code
.data
– Zusätzlich Assembler Direktiven f:

.data → Folgende Anweisungen betreffen globales Segment g:
y:

.text → Folgende Anweisungen betreffen Text-Segment
.text
main: addi $sp,$sp,-4
High-Level Code
sw $ra,0($sp)
int f,g,y;
addi $a0,$0,2
sw $a0,f
int main(void) {
addi $a1,$0,3
f=2;
sw $a1,g
g=3;
y=sum(f,g); jal sum
sw $v0,y
return y;
} lw $ra,0($sp)
addi $sp,$sp,4
int sum(int a, int b){ jr $ra
sum: add $v0,$a0,$a1
return (a+b);
jr $ra
}
© Christian Hochberger, TU Darmstadt Programmierung 85
Assemblieren


Verwandelt Assembler in Maschinencode
→ Object-File

Typischerweise in 2 Passes
– 1. Pass: Festlegen der Adressen (Befehle/Daten)

Beginn Code-Segment: 0x00400000

Tabelle mit Labels aufbauen

Bekannte Adressen eintragen
– 2. Pass: Erzeugen der Maschinenbefehle

Bekannte Sprungadressen eintragen

Unbekannte Adressen offen lassen (z.B. globale Daten)

Zugriff auf globale Daten
– lw/sw Befehl eintragen

Offset und Basisregister bleiben offen
© Christian Hochberger, TU Darmstadt Programmierung 86
Assemblieren (2)


Object-File
– Enthält auch Verwaltungsinformationen
Maschinen-Code
– Code-Größe, Daten-Größe 0x00400000 main: addi $sp,$sp,-4
– Symbol-Informationen 0x00400004 sw $ra,0($sp)
0x00400008 addi $a0,$0,2
0x0040000C sw $a0,f
Symbol Adresse 0x00400010 addi $a1,$0,3
0x00400014 sw $a1,g
f 0x10000000 0x00400018 jal sum
0x0040001C sw $v0,y
g 0x10000004 0x00400020 lw $ra,0($sp)
0x00400024 addi $sp,$sp,4
y 0x10000008
0x00400028 jr $ra
main 0x00400000 0x0040002C sum: add $v0,$a0,$a1
0x00400030 jr $ra
sum 0x0040002C

© Christian Hochberger, TU Darmstadt Programmierung 87


Linken


Zusammenfügen mehrerer Object-Files
– Aus Quell-Programmen
– Aus Bibliotheken

Relokation
– Assembler nimmt für alle Code-Segmente gleiche Startadresse an
– Code-Segmente müssen verschoben werden

Branch-Befehle bleiben unverändert!

Jump-Befehle müssen korrigiert werden (Adress-Verschiebung hinzu addieren)

Globale Daten anordnen
– Relativ zu $gp (liegt in der Mitte des reservierten Bereichs)
– Zugriffsbefehle patchen
© Christian Hochberger, TU Darmstadt Programmierung 88
Konstante 0x8000 → negativ!
Linken (2)


auf 32 Bit erweitern→ 0xFFFF8000
● + $gp=0x10008000

Effektive Adresse: 0x10000000
Datei-Header

Fertiges Programm Code-Größe: 52 Bytes
Daten-Größe: 12 Bytes
Code-Segment
0x00400000 0x23BDFFFC main: addi $sp,$sp,-4
0x00400004 0xAFBF0000 sw $ra,0($sp)
0x00400008 0x20040002 addi $a0,$0,2
0x0040000C 0xAF848000 sw $a0,0x8000($gp)
0x00400010 0x20050003 addi $a1,$0,3
0x00400014 0xAF858004 sw $a1,0x8004($gp)
0x00400018 0x0C10000B jal sum
0x0040001C 0xAF828008 sw $v0,0x8008($gp)
0x00400020 0x8FBF0000 lw $ra,0($sp)
0x00400024 0x23BD0004 addi $sp,$sp,4
0x00400028 0x03E00008 jr $ra
0x0040002C 0x00851020 sum: add $v0,$a0,$a1
0x00400030 0x03E00008 jr $ra
Daten-Segment
0x10000000 0 f
0x10000004 0 g
© Christian Hochberger, TU Darmstadt 0x10000008 0 Programmierung y 89
Laden


Mehrere Schritte
– Einlesen des Code-Segments in den Speicher ab Adresse 0x00400000
– $gp auf 0x10008000 setzen
– $sp auf 0x7FFFFFFC setzen
– jal an Startadresse (0x00400000)

In Wirklichkeit komplizierter
– Argumente an Programm übergeben?
– Datenbereiche vorinitialisieren?
– Debugging?

© Christian Hochberger, TU Darmstadt Programmierung 90


Pseudoinstruktionen


Abkürzungen für häufig auftretende Aufgaben
– Lange Konstante laden
li $s0,0x1234AA77 → lui $s0,0x1234
ori $s0,0xAA77
– Register löschen
clear $t0 → add $t0,$0,$0
– Register verschieben
move $s2,$s1 → add $s2,$0,$s1
– Nichts tun (No Operation)
nop → xor $0,$0,$0
– Verzweigung mit konstantem Vergleichswert
beq $t2,imm15:0,label → addi $at,$0,imm15:0
beq $t2,$at,label

© Christian Hochberger, TU Darmstadt Programmierung 91
Exceptions


Besondere Situationen, die Behandlung durch Prozessor erfordern
– Wie ein unaufgeforderter Funktionsaufruf
– Können durch HW oder SW ausgelöst werden

HW Exceptions
– Peripherie des Computers muss bedient werden
– Werden Interrupts genannt

SW Exceptions
– Durch Fehler im Programmablauf
(z.B. Division durch 0, unausgerichtete Adresse, …)
– Mit Absicht durch das Programm (Betriebssystem-Aufrufe)
– Werden Traps genannt
© Christian Hochberger, TU Darmstadt Programmierung 92
Exceptions in MIPS


Prozessor merkt sich
– PC bei dem die Exception auftrat
● Register EPC
– Ursache der Exception (Cause)
● Register Cause

Sprung zum Exception Handler
– Liegt an Adresse 0x80000180
– Wird durch das Betriebssystem definiert
– Handler liest Ursache aus
– Verzweigung je nach Behandlung

© Christian Hochberger, TU Darmstadt Programmierung 93


Exceptions in MIPS (2)

● EPC und Cause nicht Teil des normalen Registersatzes


– Werden als Teil des Coprozessor 0 gesehen
– Coprozessor 0 → Processor Control
– Lesen von Registern

mfc0 (move from coprocessor 0)
mfc0 $t0,Cause
mfc0 $t1,EPC

syscall und break als spezielle Instruktionen
– syscall → Aufruf von Betriebssystemfunktionen
– break → Realisierung von Breakpoints beim Debuggen
– Argumente müssen vom Exception-Handler aus der Instruktion geholt werden
– Zugriff auf Instruktion über EPC
© Christian Hochberger, TU Darmstadt Programmierung 94
Eine alternative Architektur: IA32


Basiert auf 8086 Prozessor von Intel aus 1978!
– Damals 16 Bit Prozessor
– Spätere Varianten 80286, 80386 (erstmals richtig 32 Bit)
– Pentium und Athlon

CISC Prozessor
– Primäres Ziel der Befehlssatzauswahl: Kompakte Programme
→ Viele verschiedene Befehle
→ Viele Adressierungsarten
→ Viele Datentypen
→ Viele Befehlsformate

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 95


IA32 - Register


Prinzipiell 8 Register zu 32 Bit:
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI

Teilweise als 16 Bit oder 8 Bit Register ansprechbar
AX, CX, DX, BX, AH, AL, CH, CL, DH, DL, BH, BL

Beinahe alle Register universell
– Nicht alle Befehle können alle Register nutzen
– Bestimmte Befehle nutzen festgelegte Register

ESP immer Stack Pointer

Loop-Befehl nutzt immer ECX
– EIP → PC, nur indirekt manipulierbar

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 96


IA32 - Operanden


MIPS:
– Zwei Arten von Operanden: Register oder Immediate
– Jeder Befehl spezifiziert 3 Operanden
– Ausnahme Load/Store

IA32:
– Drei Arten von Operanden: Register, Immediate, Memory
– Jeder Befehl spezifiziert 2 Operanden!
– Erster Operand immer auch Ziel der Operation
→ Komplizierter zu programmieren
– Einzig Kombination Memory, Memory nicht erlaubt

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 97


IA32 – Operanden (2)


Beispiele für Operanden-Kombinationen
Source/ Source Befehl Bedeutung
Destination

Register Register add EAX,EBX EAX ← EAX+EBX

Register Immediate add EAX,42 EAX ← EAX+42

Register Memory add EAX,[20] EAX ← EAX+MEM[20]

Memory Register add [20],EAX MEM[20] ← MEM[20]+EAX

Memory Immediate add [20],42 MEM[20] ← MEM[20]+42


Memory als Operand
– Lange Zugriffszeit auf Operand!
– Evtl. sogar zwei Zugriffe auf Speicher in einem Befehl
© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 98
IA32 – Operanden (3)


Befehle können mit 8, 16 oder 32 Bit arbeiten
(neuere Varianten auch mit 64 Bit)

Größe je nach Register-Name

Beispiele
– add AH,BL AH ← AH+BL 8 Bit
– add AX,-1 AX ← AX-1 16 Bit
– add EAX,EDX EAX ← EAX+EDX 32 Bit

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 99


IA32 - Adressierungsarten


Viel mehr Auswahl als bei MIPS

Beispiele (nicht vollständig)
8, 16 oder 32 Bit-Wert
– Displacement
add EAX,[20] EAX ← EAX+MEM[20]
– Base Addressing
add EAX,[ESP] EAX ← EAX+MEM[ESP]
– Base + Displacement
add EAX,[EDX+40] EAX ← EAX+MEM[EDX+40]
Skalierung um 1, 2, 4 oder 8
– Displacement + Scaled Index
add EAX,[60+EDI*4] EAX ← EAX+MEM[60+EDI*4]
– Base + Displacement + Scaled Index
add EAX,[EDX+80+EDI*2] EAX ← EAX+MEM[EDX+80+EDI*2]
© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 100
IA32 – Status Flags


Bedingungen werden in IA32 besonders behandelt
– Speicherung in Flags
– Beispiele für Flags

CF → Carry Flag (Carry Out der letzten Rechnung, kann mit addiert werden)

ZF → Zero Flag (Letztes Ergebnis war 0)

SF → Sign Flag (Letztes Ergebnis war negativ)

OF → Overflow Flag (K2-Zahl übergelaufen)
– Flags werden von Branches ausgewertet

Flags gehören zum Maschinen-Status

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 101


IA32 – Beispielbefehle


ADD,SUB → Normale Addition/Subtraktion

ADDC → Addiert CF mit hinzu

INC/DEC → ± 1

BT → Bit Test, CF=D[S] (Bit s von D)

BTR/BTS → Bit Test + Set/Reset

MOV → D=S

Loop → Dekrementiert ECX
ECX ≠ 0 → Sprung

PUSH/POP→ Benutzt automatisch ESP

CALL → ESP=ESP-4, MEM[ESP]=EIP, EIP=S

RET → EIP=MEM[ESP], ESP=ESP+4
© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 102
IA32 – Befehlskodierung


Befehle können zwischen 1 und 15 Byte lang sein

Allgemeines Schema
Prefixe Opcode ModR/M SIB Displacement Immediate
Bis zu 4 Prefixe 1,2 oder 3 Byte 1,2 oder 4 Byte 1,2 oder 4 Byte
Jeweils 1 Byte

Reg/
Mod R/M Scale Index Base
Opcode
2 Bits 3 Bits 3 Bits 2 Bits 3 Bits 3 Bits

Im Prinzip 17 Byte möglich, aber nicht zulässig

Prefix: Operanden-Größe, Adress-Größe, Wiederholung, Speicher-Lock

© Christian Hochberger, TU Darmstadt IA32 - Das wahre Leben 103

Das könnte Ihnen auch gefallen