Der Assembler - Universität zu Lübeck
Der Assembler - Universität zu Lübeck
Der Assembler - Universität zu Lübeck
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Institut für Telematik | <strong>Universität</strong> <strong>zu</strong> <strong>Lübeck</strong><br />
Informatik III<br />
Kapitel 3: <strong>Assembler</strong><br />
Prof. Dr. Stefan Fischer<br />
Wintersemester 2005/2006
3-2<br />
Überblick<br />
• Was ist <strong>Assembler</strong> Programmierung?<br />
• Materialien<br />
• Erstes <strong>Assembler</strong> Beispiel<br />
• Speicher<br />
• Prozessor<br />
• Register<br />
• Aufbau eines <strong>Assembler</strong> Programms<br />
• Einfache Instruktionen<br />
• <strong>Der</strong> Stack<br />
• Funktionen<br />
• Von C <strong>zu</strong> <strong>Assembler</strong>: der Compiler<br />
• gdb – ein einfacher Debugger<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0<br />
pusha<br />
mov ebx, 1<br />
dump_regs 1<br />
popa<br />
mov eax, 0<br />
leave<br />
ret<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-3<br />
Was ist <strong>Assembler</strong>-Programmierung?<br />
• Prozessoren stellen einen sogenannten Instruktionssatz<br />
(ISA) <strong>zu</strong>r Verfügung<br />
• das ist die Menge aller Instruktionen, die direkt vom Prozessor<br />
ausgeführt werden können<br />
• Beispiele:<br />
- Addieren/Multiplizieren/Dividieren von zwei Zahlen<br />
- Zugriff auf den Speicher<br />
- Sprünge und Verzweigungen<br />
• <strong>Der</strong> Instruktionssatz ist unabhängig vom Betriebssystem<br />
• Die Instruktionen des Instruktionssatzes sind Binärzahlen:<br />
• Beispiel: 03 C3<br />
- IA-32 bzw. x86 (= 80x86, beinhaltet auch Pentium) Befehl<br />
- addiert und speichert zwei Zahlen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-4<br />
Kompilieren von Hochsprachen<br />
• Beim Kompilieren von Hochsprachen (C, C++, Pascal,<br />
etc.):<br />
• die Konstrukte der Hochsprache werden in den Instruktionssatz des<br />
Prozessors übersetzt<br />
• Besonderheiten des Betriebssystems werden berücksichtigt<br />
• daher abhängig von Prozessor und Betriebssystem<br />
• Manchmal möchte man jedoch direkt auf dem<br />
Instruktionssatz des Prozessors arbeiten<br />
• Das ist auf Basis von Binärzahlen jedoch sehr aufwendig<br />
und fehleranfällig<br />
• Daher: <strong>Assembler</strong> Programmierung<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-5<br />
Was ist <strong>Assembler</strong> Programmierung?<br />
• Symbolische Schreibweise:<br />
• add eax, ebx<br />
• <br />
• semantisch äquivalent <strong>zu</strong> 03C3<br />
• Ein <strong>Assembler</strong> ist ein Programm mit folgende Aufgaben:<br />
• Übersetzen der symbolischen Schreibweise in binäre Instruktionen<br />
(assemblieren, assembly)<br />
- jede Instruktion in symbolischer Schreibweise = höchstens<br />
eine Instruktion in binärer Schreibweise (mit wenigen Ausnahmen)<br />
- Ergebnis des Übersetzens ist eine Objektdatei (.o), genau wie beim<br />
Übersetzen eines C Programms<br />
- die Objektdatei enthält Objektcode<br />
– Format ist betriebssystemspezifisch<br />
• Zusammenführen mehrerer Objektdateien <strong>zu</strong> einem ausführbaren<br />
Programm (linken, linking)<br />
- <strong>zu</strong>m Teil betriebssystemspezifisch<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-6<br />
<strong>Der</strong> <strong>Assembler</strong><br />
• Es gibt viele verschiedene <strong>Assembler</strong><br />
• Selbst für einen Prozessor unterscheidet sich die Syntax<br />
der symbolischen Befehle von <strong>Assembler</strong> <strong>zu</strong> <strong>Assembler</strong><br />
• meist ist die Syntax jedoch <strong>zu</strong>mindest ähnlich<br />
• Auch in Be<strong>zu</strong>g auf die Unterstüt<strong>zu</strong>ng durch einen<br />
Präprozessor (z.B. für Makros) gibt es große Unterschiede<br />
• Im Rahmen der Vorlesung empfehlen und verwenden wir<br />
den NASM<br />
(Netwide <strong>Assembler</strong>)<br />
• open source<br />
• für DOS/Windows und Linux<br />
• http://sourceforge.net/projects/nasm<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-7<br />
Unterschied von Assemblieren und Kompilieren<br />
• In höheren Programmiersprachen (C/C++/etc.):<br />
• Kompilieren, um aus dem Quelltext eine Objektdatei mit<br />
Objektcode <strong>zu</strong> erzeugen<br />
- ähnlich wie Assemblieren<br />
• Aber: hier werden die Instruktionen der Programmiersprache vom<br />
Compiler in viele Instruktionen des Befehlssatzes übersetzt<br />
- der Optimierungsgrad kann beim Übersetzen durch Parameter<br />
gesteuert werden<br />
- ebenso kann man durch Parameter bestimmen, ob die Besonderheiten<br />
eines Prozessors (MMX/ISSE) verwendet werden sollen<br />
- man hat keine vollständige Kontrolle darüber, welche Instruktionen des<br />
Befehlssatzes erzeugt werden<br />
• Bei der <strong>Assembler</strong> Programmierung:<br />
• Programmierer hat genaue Kontrolle darüber, welche Instruktion<br />
erzeugt wird<br />
• sehr viel direktere und einfachere Überset<strong>zu</strong>ng als beim<br />
Kompilieren<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-8<br />
Einbetten in C<br />
• Meist werden Programme nicht komplett in <strong>Assembler</strong><br />
geschrieben:<br />
• sehr aufwändig<br />
• sehr fehleranfällig<br />
• Statt dessen:<br />
• einzelne Funktionen werden in <strong>Assembler</strong> geschrieben<br />
• die Funktionen werden dann von einer höheren<br />
Programmiersprache aus aufgerufen<br />
• Vorgehen bei C:<br />
• C Programm mit Funktionsaufruf schreiben und kompilieren<br />
• <strong>Assembler</strong> Programm für diese Funktion schreiben und<br />
assemblieren<br />
• Linken der Objektdateien<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-9<br />
Warum <strong>Assembler</strong> Programmierung?<br />
• Drei zentrale Gründe:<br />
• <strong>zu</strong>r Optimierung von besonders kritischen und wichtigen<br />
Stellen eines Programms<br />
- genaue Kontrolle über die verwendeten Instruktionen<br />
- Nutzen hierfür nimmt ab: Compiler werden immer besser!<br />
• <strong>zu</strong>m Zugriff auf Funktionalität die durch höhere<br />
Programmiersprachen nicht direkt angesprochen<br />
werden kann<br />
- Beispiele: MMX, 3DNow!, ISSE2<br />
- werden jedoch auch <strong>zu</strong>nehmend gut von Compilern unterstützt<br />
• der wichtigste: Verstehen wie ein Computer arbeitet!<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-10<br />
Materialien<br />
• <strong>Assembler</strong> Programmierung in 3 Schritten:<br />
• Kurzeinführung in der Vorlesung (x86/IA-32 <strong>Assembler</strong>)<br />
• Paul A Carter, „PC Assembly Language“, 2005<br />
- verfügbar unter http://www.drpaulcarter.com/pcasm/<br />
• Verwendete Tools:<br />
• NASM (assemblieren)<br />
http://sourceforge.net/projects/nasm<br />
• Handbuch <strong>zu</strong> NASM (Link auf der Webseite <strong>zu</strong>r<br />
Vorlesung)<br />
• gcc (compilieren und linken)<br />
- für DOS/Windows: DJGPP (http://www.delorie.com/djgpp/)<br />
• sind im Pool installiert<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-11<br />
Erstes <strong>Assembler</strong> Beispiel<br />
• Das C Programm für das erste <strong>Assembler</strong> Beispiel<br />
• cdecl.h enthält die Definitionen von PRE_CDECL und<br />
POST_CDECL<br />
• regelt wie C <strong>Assembler</strong> Funktionen aufruft<br />
• Alles andere: wie immer<br />
• inkl. Deklaration einer Funktion int asm_main(void);<br />
#include "cdecl.h"<br />
int PRE_CDECL asm_main( void ) POST_CDECL;<br />
int main()<br />
{<br />
int ret_status;<br />
ret_status = asm_main();<br />
return ret_status;<br />
}<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-12<br />
Erstes <strong>Assembler</strong> Beispiel<br />
• Zeilen die mit % beginnen sind Anweisungen an den NASM<br />
Präprozessor (analog <strong>zu</strong> # in C)<br />
• In asm_io.inc werden einige Hilfsmakros definiert, z.B. eines <strong>zu</strong>r<br />
Ausgabe aller Registerinhalte (dump_regs 1)<br />
• Unter DOS/Windows: _asm_main statt asm_main<br />
%include "asm_io.inc"<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0 ; Funktionseintritt<br />
pusha<br />
Prof. Dr. Stefan Fischer<br />
mov ebx, 1 ; lade eine 1 in das Register ebx<br />
dump_regs 1 ; gib Register aus<br />
popa ; nach C <strong>zu</strong>rückkehren<br />
mov eax, 0<br />
; Rückgabeparameter setzen<br />
leave<br />
ret<br />
Informatik III: <strong>Assembler</strong>
3-13<br />
Assemblieren, Kompilieren, Linken<br />
• Assemblieren:<br />
• nasm -f elf Program1.asm (linux)<br />
• nasm -f coff Program1.asm (dos)<br />
• erzeugt eine Objektdatei: Program1.o<br />
• Kompilieren:<br />
• gcc -c driver.c<br />
• Linken:<br />
• gcc -o first driver.o Program1.o asm_io.o<br />
• asm_io beinhaltet den Objektcode für die Ausgaberoutinen, die in<br />
asm_io.inc deklariert wurden<br />
• Ergebnis: first.exe (dos) oder first (linux)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-14<br />
Ausgabe<br />
• In das Register EBX wurde eine 1 geladen<br />
Register Dump # 1<br />
EAX = 00000000 EBX = 00000001 ECX = 00000001 EDX = 401570C0<br />
ESI = 40014020 EDI = BFFFDCB4 EBP = BFFFDC58 ESP = BFFFDC38<br />
EIP = 0804841A FLAGS = 0286 SF PF<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-15<br />
Speicher<br />
• <strong>Der</strong> Speicher ist üblicherweise in Bytes aufgeteilt<br />
• Jedes Byte umfasst 8 Bit<br />
• Instruktionen arbeiten auf einem oder mehreren Bytes<br />
• Je nach Anzahl der Bytes verwendet man bei x86<br />
Prozessoren die folgenden Begriffe:<br />
• word = 2 Byte<br />
• double word = 4 byte<br />
• quad word = 8 byte<br />
• paragraph = 16 byte<br />
• Die Bytes im Speicher sind durchnummeriert, die Nummer<br />
eines Bytes bezeichnet man als seine Adresse<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-16<br />
Endianess<br />
• Wie speichert man einen Wert, der aus mehreren Bytes besteht (z.B. 32 Bit<br />
unsigned Integer)?<br />
• Zwei Möglichkeiten:<br />
• Big Endian:<br />
- Das höchstwertige Byte wird in der kleinsten Adresse gespeichert<br />
- Beispiel 0xA0B70708 wird wie folgt an der Adresse 800 gespeichert<br />
– A0 in der Speicherzelle mit der Adresse 800<br />
– B7 in 801, 07 in 802, 08 in 803<br />
- Beispiele: Motorola 68000, SPARC, IBM 370<br />
• Little Endian:<br />
- Das höchstwertige Byte wird in der größten Adresse gespeichert<br />
- Beispiel 0xA0B70708 wird wie folgt an der Adresse 800 gespeichert<br />
– A0 in der Speicherzelle mit der Adresse 803<br />
– B7 in 802, 07 in 801, 08 in 800<br />
- Beispiele: MOS Technologies 6502, Intel x86, DEC VAX<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-17<br />
Wann ist Endianess wichtig?<br />
• Im normalen Betrieb merkt man nicht ob ein<br />
Prozessor Big oder Little Endian verwendet<br />
• sowohl lesender als auch schreibender Zugriff<br />
verwendet immer die gleiche Endianess<br />
• Problematisch wird es, wenn:<br />
• man zwischen zwei Rechnern mit verschiedener<br />
Endianess Daten austauscht<br />
• man dieselben Daten in unterschiedlichen Einheiten<br />
manipuliert<br />
- also z.B. auf ein 32-bit Unsigned Integer Wert byteweise <strong>zu</strong>greift<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-18<br />
Prozessor<br />
• <strong>Der</strong> Prozessor stellt den Instruktionssatz <strong>zu</strong>r<br />
Verfügung<br />
• Dieser Instruktionssatz unterscheidet sich i.d.R.<br />
von Prozessor <strong>zu</strong> Prozessor<br />
• Wir verwenden den Instruktionssatz der Intel x86<br />
Familie<br />
• wird auch IA-32 (Intel Architecture 32) genannt<br />
• ab 80386, bis <strong>zu</strong>m aktuellen Pentium, aktuelle AMD<br />
Prozessoren<br />
• Erweiterungen MMX, ISSE<br />
• 32-bit ist die natürliche Größe für Operanden und<br />
Adressen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-19<br />
Register<br />
• Im Prozessor gibt es die schon genannten<br />
Register:<br />
• dies sind Speicherzellen<br />
• auf die besonders schnell <strong>zu</strong>gegriffen werden kann<br />
• die teilweise besondere Bedeutung bei verschiedenen<br />
Instruktionen haben<br />
• Viele Operationen verwenden Register als<br />
Operanden oder <strong>zu</strong>m Speichern des Ergebnisses<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-20<br />
Speichermodelle<br />
• Real Mode, Flat Model: ab Intel 8080<br />
• 64K für alles (Programm und Daten)<br />
• Betriebssysteme: CP/M-80, später DOS<br />
• Real Mode, Segmented Model: ab Intel 8086<br />
• für die Kompatibilität mit 8080: Einteilung des Speichers in 64k<br />
Blöcke<br />
• man muss manuell festlegen welchen Block man gerade verwendet<br />
• sehr aufwändig und fehleranfällig<br />
• Betriebssysteme: DOS<br />
• Protected Mode: ab Intel 80386<br />
• 4GB virtueller Speicher für alles (Programm und Daten)<br />
• Betriebssysteme: Windows, Linux<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-21<br />
Register des Pentium<br />
• Entwicklungsgeschichte (8086 von<br />
1978!) kann aus dem Registersatz<br />
abgelesen werden<br />
• E = Extended = 32 bit<br />
• EAX, EBX, ECX, EDX<br />
• Allgemeine 32 bit Register, aber:<br />
• EAX: Berechnungen<br />
• EBX: Zeiger (Pointer)<br />
• ECX: Schleifen<br />
• EDX: Mult/Div, 64 bit mit EAX<br />
• 16 and 8 bit Teile (286, 8088)<br />
• ESI, EDI: String Operationen<br />
• EBP, ESP: Base/Stack Pointer<br />
• CS-GS: Speicher Segment Zugriff<br />
• EIP: Instruction Counter (=PC)<br />
• EFLAGS: Prozessorstatuswort<br />
Für den Anwendungsprogrammierer<br />
nur<br />
unter Real Mode,<br />
Segmented Model<br />
sichtbar!<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-22<br />
EFLAGS-Register<br />
• Das EFLAGS-Register hat eine besondere Bedeutung:<br />
• es gibt den Status des Prozessors an<br />
• es erteilt Informationen über die letzte Berechnung<br />
• jedes Bit in diesem Register hat eine eigene Bedeutung<br />
• Beispiele:<br />
- Sign Flag (S):<br />
– im Ergebnis der letzten Operation war das höchstwertige Bit gesetzt<br />
- Zero Flag (Z):<br />
– das Ergebnis der letzten Operation war 0<br />
- Carry Flag (C):<br />
– bei der letzten Operation gab es einen Übertrag<br />
- Overflow Flag (O)<br />
– bei der letzten Operation gab es einen Überlauf<br />
• die Flags des EFLAGS-Registers können mit speziellen<br />
Instruktionen abgefragt werden<br />
- Realisieren bedingter Sprünge<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-23<br />
Aufbau eines <strong>Assembler</strong> Programms (NASM)<br />
• Ein Programm kann aus mehreren Überset<strong>zu</strong>ngseinheiten<br />
bestehen<br />
• Eine Überset<strong>zu</strong>ngseinheit wird Modul genannt<br />
• Ein Modul kann die folgenden Elemente beinhalten:<br />
• Segmentidentifikation<br />
• <strong>Assembler</strong> Instruktionen<br />
• Pseudo Instruktionen<br />
• Preprozessor Anweisungen<br />
• Direktiven an den <strong>Assembler</strong> (beinhaltet Segmentidentifikation)<br />
• Dies ist <strong>Assembler</strong> spezifisch (also hier für NASM), von<br />
den Grundzügen her aber typisch für x86 <strong>Assembler</strong><br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-24<br />
Segmentidentifikation<br />
• Eine Überset<strong>zu</strong>ngseinheit kann aus mehreren<br />
(Speicher)Bereichen bestehen<br />
• Beispiele:<br />
• .text: in diesem Bereich befinden sich die ausführbaren<br />
Instruktionen<br />
• .data: in diesem Bereich befinden sich „Variablen“ mit<br />
vordefinierten Werten<br />
• .bss: (block start symbol) in diesem Bereich befinden sich<br />
„Variablen“ die keinen vordefinierten Wert besitzen<br />
• Diese Bereiche nennt man Segmente oder Sektionen<br />
• <strong>Der</strong> Beginn eines Segmentes wird mit dem <strong>Assembler</strong> Direktiv<br />
SEGMENT (oder wahlweise SECTION) gekennzeichnet<br />
• Beispiel: %include "asm_io.inc"<br />
Prof. Dr. Stefan Fischer<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0 ; Funktionseintritt<br />
... Informatik III: <strong>Assembler</strong>
3-25<br />
<strong>Assembler</strong> Instruktion<br />
• <strong>Assembler</strong> Instruktionen werden vom <strong>Assembler</strong> in Instruktionen des<br />
Befehlssatzes des Prozessors übersetzt<br />
• In NASM haben <strong>Assembler</strong> Instruktionen folgendes Format:<br />
: ; <br />
• Beispiel:<br />
loop1: mov ebx, 1 ; Start of Loop, initialize ebx<br />
• label<br />
• Damit kann diese Zeile identifiziert werden, ohne dass man mühsam die<br />
Speicheradresse dieser Zeile bestimmen muss<br />
- Das Bestimmen der Speicheradresse übernimmt der <strong>Assembler</strong> für uns<br />
• Ein definierter Label kann anstelle einer Adresse geschrieben werden, z.B.<br />
- um den Ort <strong>zu</strong> identifizieren an dem Daten abgelegt sind<br />
- um Ziele von Verzweigungen oder Sprüngen <strong>zu</strong> identifizieren<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-26<br />
<strong>Assembler</strong> Instruktion<br />
• instruction<br />
• die eigentliche <strong>Assembler</strong> Instruktion<br />
• operands<br />
• je nach Instruktion können Operanden folgen<br />
• Operanden können<br />
- direkt angegeben werden (als Konstante)<br />
- in einem Register stehen<br />
- im Speicher stehen<br />
• comment<br />
• alles nach dem ; wird ignoriert<br />
• Zeilenverlängerung: ein <strong>Assembler</strong> Instruktion muss in<br />
einer Zeile stehen<br />
• Verlängerung einer Zeile durch \ als abschließendes Zeichen<br />
möglich<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-27<br />
Spezifikation von Instruktionen<br />
• Aus<strong>zu</strong>g aus dem NASM Handbuch:<br />
MOV r/m8,reg8 ; 88 /r [8086]<br />
MOV r/m16,reg16 ; o16 89 /r [8086]<br />
MOV r/m32,reg32 ; o32 89 /r [386]<br />
MOV reg8,r/m8 ; 8A /r [8086]<br />
MOV reg16,r/m16 ; o16 8B /r [8086]<br />
MOV reg32,r/m32 ; o32 8B /r [386]<br />
...<br />
• Dies gibt an welche Operanden erlaubt sind:<br />
• regX=Register der Größe X<br />
• mX=Speicher der Größe X<br />
• r/mX=Register oder Speicher der Größe X<br />
• immX=direkte Angabe des Operanden der Größe X<br />
• ...<br />
• Dann folgt die Beschreibung welche Instruktion des Befehlssatzes des<br />
Prozessors generiert wird<br />
• Dann der Prozessor ab dem die Instruktion vorhanden ist<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-28<br />
Erlaubte Adressierung von Operanden<br />
• Immediate: Operand als Konstante angeben<br />
• nur für Operanden die kein Ziel für eine Operation sind<br />
• mov eax, 0<br />
• Register: Register angeben<br />
• für Operanden die Ziel oder Quelle für eine Operation sind<br />
• mov eax, ebx<br />
• Speicher: Adresse der Speicherzelle in [] angeben<br />
• nur ein Operand darf direkt auf diese Art adressiert werden<br />
• mov eax, [esp]<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-29<br />
Typische Addressierungsfehler<br />
• mov 17, 1<br />
• nur ein Operand darf Immediate adressiert werden<br />
• mov 17, bx<br />
• Ziel darf nicht Immediate adressiert werden<br />
• mov cx, dh<br />
• beide Operanden müssen die gleiche Größe haben<br />
• mov [ax],[bx]<br />
• nur ein Operand darf direkt im Speicher adressiert<br />
werden<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-30<br />
Speicher<strong>zu</strong>griff<br />
• Wenn ein Operand im Speicher steht wird die Adresse des<br />
Operanden so angegeben: [Adresse]<br />
• Beispiele ohne Speicher<strong>zu</strong>griff:<br />
• mov eax, 1 ; lädt eine 1 in das Register eax<br />
• Sei loop1 ein label, dann<br />
mov eax, loop1 ; lädt die Adresse von loop1 in eax<br />
• Beispiele mit Speicher<strong>zu</strong>griff:<br />
• Sei buffer ein label, dann<br />
mov eax, [buffer] ; lädt 4 Bytes aus dem Speicher beginnend \<br />
mit dem Byte an der Speicherstelle buffer<br />
• mov eax, [ecx+ebx*4+0x800] ; lädt 4 Bytes aus dem Speicher \<br />
beginnend mit dem Byte an der \<br />
Speicherstelle ecx+ebx*4+0x800<br />
- dieses Konstrukt benötigt man z.B. um effizient über ein Array iterieren<br />
<strong>zu</strong> können<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-31<br />
Speicheradressierung<br />
• Erlaubte Adressierung: [BASE+(INDEX*SCALE)+DISP]<br />
• BASE: EAX, EBX, ECX, EDX + deren verkürzte Varianten<br />
- z.B.: Adresse des ersten Wertes in einem Array<br />
• INDEX: EAX, EBX, ECX, EDX + deren verkürzte Varianten<br />
- z.B.: Index eines Array Elementes<br />
• SCALE: 1, 2, 4 oder 8<br />
- z.B.: Größe eines Array Elementes<br />
• DISP: 32-Bit Konstante<br />
- z.B. um einen konstanten Offset in eine Tabelle <strong>zu</strong> addieren<br />
• Alle Elemente sind optional<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-32<br />
Datentypen<br />
• In <strong>Assembler</strong> ist der Datentyp eines Operanden seine<br />
Länge in Bytes<br />
• Hat eine Instruktion mehr als einen Operanden:<br />
• dann muss die Länge der Operanden meist identisch sein:<br />
- mov eax, ebx ist korrekt<br />
- mov eax, bx ist nicht korrekt<br />
• Die Länge eines Operanden kann implizit angegeben sein:<br />
• z.B. bei mov eax, 0x10 wird 0x10 als 32-Bit Zahl interpretiert<br />
• Explizite Angabe der Länge eines Operanden ist<br />
erforderlich, wenn sie implizit nicht bestimmt werden kann:<br />
• z.B. bei neg byte [wert]<br />
• erlaubte Type Specifiers: byte, word, dword<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-33<br />
Pseudoinstruktionen<br />
• Pseudoinstruktionen werden nicht direkt in Instruktionen<br />
des Befehlssatzes übersetzt<br />
• Sie haben aber das gleiche Format wie <strong>Assembler</strong><br />
Instruktionen<br />
• Man verwendet Pseudo Instruktionen <strong>zu</strong>m Beispiel für<br />
• das Bereitstellen von initialisiertem Speicherplatz (meist im<br />
.data Segment):<br />
- db 0x55 ; Speicherplatz der Größe 1 Byte belegt mit 0x55<br />
- db 0x55, 0x56, 0x57 ; drei aufeinander folgende Bytes<br />
- db 'hello',13,10,'$‘ ; 8 aufeinander folgende Bytes<br />
- dw 0x1234 ; 0x34 0x12 (little endian)<br />
- dw 'abc‘ ; 0x61 0x62 0x63 0x00 (Auffüllen auf Wort Grenzen)<br />
- dd 0x12345678 ; 0x78 0x56 0x34 0x12 (little endian)<br />
• das Bereitstellen von uninitialisiertem Speicherplatz (meist im<br />
.bss Segment):<br />
- buffer: resb 64 ; 64 * 1 Byte reserviert<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-34<br />
Konstanten<br />
• In NASM gibt es 4 verschiedene Arten von Konstanten:<br />
• numeric, character, string, (floating-point)<br />
• numeric (überall wo die direkte Angabe eines Operanden erlaubt ist):<br />
• standard: Dezimal<br />
- mov ax, 100<br />
• Hexadezimal durch<br />
- den Präfix 0x (Beispiel: mov ax, 0xa0)<br />
- den Suffix h (Beispiel: mov ax, 0a0h)<br />
– Achtung! die Zahl muss mit einer Ziffer beginnen, daher die '0'<br />
- den Präfix $ (Beispiel: mov ax, $0a0)<br />
– Achtung! die Zahl muss mit einer Ziffer beginnen, daher die '0'<br />
• Oktal durch q oder o als Suffix<br />
- mov ax, 777q<br />
- mov ax, 777o<br />
• Binär durch b als Suffix<br />
- mov ax, 10010011b<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-35<br />
Konstanten<br />
• character (überall wo die direkte Angabe eines Operanden<br />
erlaubt ist):<br />
• bis <strong>zu</strong> 4 Zeichen in einfachen oder doppelten Anführungszeichen<br />
• Little Endian wird berücksichtigt:<br />
- mov eax, 'abcd' ; danach steht 0x64636261 in eax<br />
• string (nur bei den Pseudoinstruktionen DB/DW/DD und<br />
INCBIN):<br />
• beliebig lange Kette von Zeichen in einfachen oder doppelten<br />
Anführungszeichen<br />
• es wird immer auf die „richtige“ Größe aufgefüllt<br />
- DB=ein Byte, DW=zwei Byte, DD=vier Byte<br />
• die Reihenfolge im Speicher ist so wie angegeben<br />
- db 'hello' ; ist äquivalent <strong>zu</strong><br />
- db 'h','e','l','l','o'<br />
- dd 'ninechars' ; ist äquivalent <strong>zu</strong><br />
- dd 'ninechars',0,0,0<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-36<br />
Rückblick<br />
• Speicher (Endianess), Prozessor, Register<br />
• Aufbau eines <strong>Assembler</strong> Programms<br />
• Segmentidentifikation (.TEXT .DATA .BSS)<br />
• Instruktionen: : ;<br />
<br />
- Adressierung von Operanden: immediate, Register, Speicher<br />
- Speicheradressierung: [BASE+(INDEX*SCALE)+DISP]<br />
• Pseudoinstruktionen: <strong>zu</strong>r Reservierung von Speicher<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-37<br />
Beispiel: Addieren von zwei Zahlen<br />
%include "asm_io.inc"<br />
segment .data<br />
wert1:<br />
wert2:<br />
dd 0x20<br />
dd 0x40<br />
segment .bss<br />
resultat: resd 1<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0<br />
pusha<br />
mov eax, [wert1]<br />
add eax, [wert2]<br />
mov [resultat], eax<br />
dump_regs 1<br />
; Funktion initialisieren<br />
; Ersten Operanden laden<br />
; Zweiten Operanden hin<strong>zu</strong>addieren<br />
; Ergebnis speichern<br />
; Ausgabe der Registerwerte<br />
Prof. Dr. Stefan Fischer<br />
popa<br />
mov eax, 0<br />
leave<br />
ret<br />
Informatik III: <strong>Assembler</strong><br />
; Zu C <strong>zu</strong>rückkehren
3-38<br />
Addieren von zwei Zahlen - Resultat<br />
fischer@picard:~/cvs/lehre/info3/vorlesung/assembler$ ./first<br />
Register Dump # 1<br />
EAX = 00000060 EBX = 40155B90 ECX = 00000001 EDX = 401570C0<br />
ESI = 40014020 EDI = BFFFEBB4 EBP = BFFFEB58 ESP = BFFFEB38<br />
EIP = 08048425 FLAGS = 0206<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-39<br />
<strong>Der</strong> Präprozessor<br />
• Analog <strong>zu</strong> C unterstützt auch NASM einen Präprozessor<br />
• Dieser wird vor dem eigentlichen Übersetzen ausgeführt<br />
• Anweisungen an den Präprozessor sind mit %<br />
gekennzeichnet<br />
• Beispiel: %include“asm_io.inc“<br />
• fügt den Inhalt der datei asm_io.inc an diese Stelle ein<br />
• Sehr mächtig:<br />
• genaueres im NASM Handbuch (Kapitel 4)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-40<br />
Einfache Instruktionen<br />
• Kopieren von Daten (mov, bekannt!)<br />
• Arithmetische Integerinstruktionen<br />
• Logische Instruktionen<br />
• Verschiebe Instruktionen<br />
• Rotations Instruktionen<br />
• Unbedingte und bedingte Sprünge<br />
• Vergleiche<br />
• Schleifen<br />
• Setzen/Löschen von Flags<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-41<br />
Arithmetische Integer Instruktionen<br />
• Addieren von ganzen Zahlen:<br />
• add op1, op2 (ohne Berücksichtigung des Carry<br />
(Übertrag) Flags)<br />
- op1=op1+op2<br />
• adc op1, op2 (mit Berücksichtigung des Carry Flags)<br />
- op1=op1+op2+C<br />
• Subtrahieren von ganzen Zahlen:<br />
• sub op1, op2 (ohne Berücksichtigung des Carry Flags)<br />
- op1=op1-op2<br />
• sbb op1, op2 (mit Berücksichtigung des Carry/Borrow<br />
Flags)<br />
- op1=op1-op2-C<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-42<br />
Beispiel<br />
segment .data<br />
wert1:<br />
wert2:<br />
dd 0x00000000, 0xFFFFFFFF<br />
dd 0x00000000, 0x00000001<br />
segment .bss<br />
resultat: resd 2<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
...<br />
mov eax, [wert1+4] ; Operanden laden<br />
mov ebx, [wert1]<br />
mov ecx, [wert2+4]<br />
mov edx, [wert2]<br />
dump_regs 1 ; Ausgabe der Register<br />
add eax, ecx ; Addition der unteren 32 Bit<br />
dump_regs 2 ; Ausgabe der Register<br />
adc ebx, edx ; Addition der oberen 32 Bit<br />
dump_regs 3 ; Ausgabe der Register<br />
mov [resultat], eax ; Ergebnis speichern<br />
mov [resultat+4], ebx<br />
...<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-43<br />
Beispiel<br />
...<br />
mov eax, [wert1+4] ; Operanden laden<br />
mov ebx, [wert1]<br />
mov ecx, [wert2+4]<br />
mov edx, [wert2]<br />
dump_regs 1 ; Ausgabe der Register<br />
add eax, ecx ; Addition der unteren 32 Bit<br />
dump_regs 2 ; Ausgabe der Register<br />
adc ebx, edx ; Addition der oberen 32 Bit<br />
dump_regs 3 ; Ausgabe der Register<br />
mov [resultat], eax ; Ergebnis speichern<br />
mov [resultat+4], ebx<br />
...<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = FFFFFFFF EBX = 00000000 ECX = 00000001 EDX = 00000000<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 0804844C FLAGS = 200286 SF PF<br />
Register Dump # 2<br />
EAX = 00000000 EBX = 00000000 ECX = 00000001 EDX = 00000000<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 08048458 FLAGS = 200257<br />
ZF AF PF CF<br />
Register Dump # 3<br />
EAX = 00000000 EBX = 00000001 ECX = 00000001 EDX = 00000000<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
Informatik III: <strong>Assembler</strong><br />
EIP = 08048464 FLAGS = 200202<br />
Prof. Dr. Stefan Fischer
3-44<br />
Arithmetische Integer Instruktionen<br />
• Multiplikation von ganzen Zahlen<br />
• mul op1 (Multiplikation von vorzeichenlosen Zahlen)<br />
- ax=al*op1 (bei 8 Bit op1)<br />
- dx:ax=ax*op1 (bei 16 Bit op1)<br />
- edx:eax=eax*op1 (bei 32 Bit op1)<br />
• imul op1 (Multiplikation von vorzeichenbehafteten Zahlen)<br />
- analog <strong>zu</strong> mul<br />
- weitere Formate (hier nicht besprochen)<br />
• Division von ganzen Zahlen<br />
• div op1 (Division von vorzeichenlosen Zahlen)<br />
- al=ax div op1 und ah=ax mod op1 (bei 8 Bit op1)<br />
- ax=dx:ax div op1 und dx=dx:ax mod op1 (bei 16 Bit op1)<br />
- eax=edx:eax div op1 und edx=edx:eax mod op1 (bei 32 Bit op1)<br />
• idiv op1 (Division von vorzeichenbehafteten Zahlen)<br />
- analog <strong>zu</strong> div<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-45<br />
Beispiel für Multiplikation<br />
mov eax, 0xFFFFFFFF ; Operanden laden<br />
mov ecx, 0x00000010<br />
dump_regs 1 ; Registerwerte ausgeben<br />
mul ecx ; Multiplizieren<br />
dump_regs 2 ; Registerwerte ausgeben<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = FFFFFFFF EBX = 401579A8 ECX = 00000010 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 0804843F FLAGS = 200286 SF PF<br />
Register Dump # 2<br />
EAX = FFFFFFF0 EBX = 401579A8 ECX = 00000010 EDX = 0000000F<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 0804844B FLAGS = 200A87 OF SF PF CF<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-46<br />
Logische Instruktionen<br />
• and op1, op2<br />
• op1 = op1 AND op2<br />
• or op1, op2<br />
• op1 = op1 OR op2<br />
• xor op1, op2<br />
• op1 = op1 XOR op2<br />
• not op1<br />
• op1 = Einerkomplement von op1 (=alle Bits invertieren)<br />
• neg op1<br />
• op1 = Zweierkomplement von op1 (=(not op1)+1)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-47<br />
Verschiebe Instruktionen<br />
• shr op1, op2 (Shift Right)<br />
• op1 wird um op2 Stellen nach rechts verschoben<br />
• von links werden 0en nachgeschoben<br />
• shl op1, op2 (Shift Left)<br />
• op1 wird um op2 Stellen nach links verschoben<br />
• von rechts werden 0en nachgeschoben<br />
• sar op1, op2 (Shift Arithmetic Right)<br />
• op1 wird um op2 Stellen nach recht verschoben<br />
• von links wird die Ziffer nachgeschoben, die vorher im<br />
höchstwertigen Bit stand<br />
• Sign Extension!<br />
• sal op1, op2 (Shift Artithmetic Left) Synonym für shl<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-48<br />
Rotations Instruktionen<br />
• ror op1, op2 (Rotate Right)<br />
• op1 wird um op2 Stellen nach rechts rotiert<br />
• von links wird das Bit übernommen, welches rechts herausrotiert<br />
wurde<br />
• rol op1, op2 (Rotate Left)<br />
• op1 wird um op2 Stellen nach links rotiert (analog <strong>zu</strong> ror)<br />
• rcr op1, op2 (Rotate Carry Rigth)<br />
• C:op1 wird um op2 Stellen nach rechts rotiert<br />
• von links wird das Bit übernommen, welches im Carry Flag stand<br />
• rechts wird in das Carry Bit hineinrotiert<br />
• rcl op1, op2 (Rotate Carry Left)<br />
• C:op1 wird um op2 Stellen nach links rotiert (analog <strong>zu</strong> rcr)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-49<br />
Bedingte Sprünge<br />
• Bisher lineare Ausführung von Instruktionen<br />
• jmp ende<br />
• unbedingter Sprung <strong>zu</strong>r Instruktion mit dem Label ende<br />
• Bedingte Sprünge:<br />
• verzweigen, wenn Flags in EFLAGS Register gesetzt oder nicht<br />
gesetzt sind<br />
• Beispiel für einen bedingten Sprung: jo fehler<br />
• falls das Overflow (o) Flag gesetzt ist wird gesprungen<br />
• wenn nicht wird die nächste Instruktion ausgeführt<br />
• Sprungbefehle (Aus<strong>zu</strong>g):<br />
• jo, jno, jz, jnz, jc, jnc<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-50<br />
Beispiel für bedingte Sprünge<br />
mov al, 01111111b ; Operanden laden, 2er Komplement<br />
mov bl, 00000001b<br />
add al, bl ; Addieren<br />
dump_regs 1 ; Registerwerte ausgeben<br />
jno ende ; Überlauf abfangen<br />
mov al, 0x0 ; Bei Überlauf al auf 0 setzen<br />
ende: dump_regs 2 ; Registerwerte ausgeben<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = 00000080 EBX = 40157901 ECX = 401579A8 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 0804843B FLAGS = 200A92 OF SF AF<br />
Register Dump # 2<br />
EAX = 00000000 EBX = 40157901 ECX = 401579A8 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 08048449 FLAGS = 200A92 OF SF AF<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-51<br />
Vergleiche<br />
• Springen auf Grund von Vergleichen<br />
• cmp op1, op2<br />
• berechnet op1-op2<br />
• speichert kein Ergebnis<br />
• setzt aber die entsprechenden Flags im EFLAGS Register<br />
• bei vorzeichenlosen Zahlen:<br />
- op1=op2 wenn Z Flag gesetzt ist<br />
- op1op2 wenn Z und C Flag nicht gesetzt sind<br />
• bei vorzeichenbehafteten Zahlen:<br />
- ähnlich aber etwas komplizierter<br />
• Prinzipiell reicht das!<br />
• es ist aber nicht besonders praktisch, da mehrere Instruktionen für<br />
eine Auswahl benötigt werden<br />
• daher: spezielle bedingte Sprünge für die wichtigsten Fälle<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-52<br />
Vergleiche<br />
• Beim Vergleich vorzeichenbehafteter Zahlen:<br />
• JE (op1==op2), JNE (op1!=op2)<br />
• JL und JNGE (op1=op2)<br />
• Beim Vergleich vorzeichenloser Zahlen<br />
• JE (op1==op2), JNE (op1!=op2) (wie oben!)<br />
• JB und JNAE (op1=op2)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-53<br />
Beispiel für Vergleiche<br />
mov eax, 0x10 ; Die größere der beiden Zahlen<br />
mov ebx, 0x20 ; soll in ecx gespeichert werden<br />
cmp eax, ebx ; <strong>Der</strong> Vergleich<br />
dump_regs 1 ; Registerwerte ausgeben<br />
jl bgr<br />
mov ecx, eax<br />
jmp ende<br />
bgr: mov ecx, ebx<br />
ende: dump_regs 2 ; Registerwerte ausgeben<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = 00000010 EBX = 00000020 ECX = 401579A8 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 08048441 FLAGS = 200287 SF PF CF<br />
Register Dump # 2<br />
EAX = 00000010 EBX = 00000020 ECX = 00000020 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 08048456 FLAGS = 200287 SF PF CF<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-54<br />
Schleifen<br />
• Für die “elegante” Unterstüt<strong>zu</strong>ng von for Schleifen<br />
gibt es folgende Instruktionen<br />
• loop marke<br />
- dekrementiert ecx<br />
- springt <strong>zu</strong>m Label marke wenn danach ecx != 0<br />
• loope marke (loopz marke)<br />
- dekrementiert ecx (ohne EFLAGS <strong>zu</strong> modifizieren)<br />
- springt <strong>zu</strong>m Label marke, wenn danach ecx != 0 und das Z Flag<br />
gesetzt ist<br />
• loopne marke (loopnz marke)<br />
- dekrementiert ecx (ohne EFLAGS <strong>zu</strong> modifizieren)<br />
- springt <strong>zu</strong>m Label marke, wenn danach ecx != 0 und das Z Flag<br />
nicht gesetzt ist<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-55<br />
Beispiel<br />
mov eax, 0<br />
mov ecx, 10<br />
start: add eax, ecx<br />
loop start<br />
dump_regs 1<br />
; eax enthält die Summe<br />
; ecx enthält die Obere Grenze<br />
; Aufsummieren<br />
; ecx dekrementieren und <strong>zu</strong>rückspringen<br />
; Registerinhalte ausgeben<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = 00000037 EBX = 40155B90 ECX = 00000000 EDX = 401570C0<br />
ESI = 40014020 EDI = BFFFF2B4 EBP = BFFFF258 ESP = BFFFF234<br />
EIP = 08048403 FLAGS = 0202<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-56<br />
Setzen und Löschen von Flags<br />
• Das Ausführen von Instruktionen kann den Status<br />
der Flags im EFLAGS Register verändern<br />
• Man kann insbesondere das Carry Flag auch<br />
gezielt setzen und löschen:<br />
• CLC <strong>zu</strong>m Löschen des Carry-Flags<br />
• STC <strong>zu</strong>m Setzen des Carry-Flags<br />
• CMC <strong>zu</strong>m Invertieren des Carry-Flags<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-57<br />
<strong>Der</strong> Stack<br />
• Bisher:<br />
• alle Daten entweder in einem Register<br />
• ... oder in einem festen Speicherplatz<br />
• schwierig wenn Funktionen realisiert werden sollen<br />
• ... die auch rekursiv aufrufbar sein sollen<br />
• <strong>Der</strong> Stack:<br />
• Datenstruktur aus Informatik I bekannt!<br />
• hier: ein Speicherbereich auf dem dynamisch Daten abgelegt<br />
werden können<br />
• der Stack beginnt bei einer hohen Speicheradresse und wächst<br />
nach unten<br />
• elementare Instruktionen sind push (ablegen auf Stack) und pop<br />
(herunternehmen vom Stack)<br />
• weitere Stack-Instruktionen für die Unterstüt<strong>zu</strong>ng von Funktionen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-58<br />
Beispiel für Elementare Stack Instruktionen<br />
• <strong>Der</strong> Stack hat einen<br />
Anfang, hier ist dieser<br />
bei der Adresse 0x2000<br />
• <strong>Der</strong> Stack hat ab dem<br />
80386 Prozessor<br />
üblicherweise eine<br />
Breite von 4 Byte<br />
• Man kann auch kürzere<br />
Daten auf den Stack<br />
legen, üblicherweise<br />
richtet man diese aber<br />
an 4 Byte Grenzen aus<br />
• ESP (Extended Stack<br />
Pointer) ist ein Register,<br />
welches auf den<br />
aktuellen Eintrag des<br />
Stacks zeigt<br />
Adresse: 0x2000<br />
0x1000<br />
●<br />
●<br />
4 Byte Breite<br />
...<br />
0x0000FFFF<br />
Nächste Aktion:<br />
push dword 1<br />
Bedeutung: 1 als ein Double<br />
Word (4 Byte) auf den<br />
Stack legen<br />
Anfang des Stacks<br />
ESP<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-59<br />
Beispiel für Elementare Stack Instruktionen<br />
• Aktuelle Aktion:<br />
Adresse: 0x2000<br />
4 Byte Breite<br />
Anfang des Stacks<br />
push dword 1<br />
...<br />
• ESP wird um 4<br />
verringert<br />
0x1000<br />
0x0FFC<br />
0x0000FFFF<br />
0x00000001<br />
ESP<br />
• Dann wird in den<br />
Speicher auf den<br />
ESP zeigt die 1<br />
als ein Double<br />
Word (4 Byte)<br />
geschrieben<br />
●<br />
●<br />
Nächste Aktion:<br />
push dword 2<br />
Bedeutung: 2 als ein Double<br />
Word (4 Byte) auf den<br />
Stack legen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-60<br />
Beispiel für Elementare Stack Instruktionen<br />
• Aktuelle Aktion:<br />
Adresse: 0x2000<br />
4 Byte Breite<br />
Anfang des Stacks<br />
push dword 2<br />
...<br />
• ESP wird um 4<br />
verringert<br />
• Dann wird in den<br />
Speicher auf den<br />
ESP zeigt die 2<br />
als Double Word<br />
(4 Byte)<br />
geschrieben<br />
0x1000<br />
0x0FFC<br />
0x0FF8<br />
●<br />
●<br />
0x0000FFFF<br />
0x00000001<br />
Nächste Aktion:<br />
pop eax<br />
0x00000002<br />
ESP<br />
Bedeutung: das oberste Double Word (4 Byte)<br />
vom Stack in das Register eax laden<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-61<br />
Beispiel für Elementare Stack Instruktionen<br />
• Aktuelle Aktion:<br />
Adresse: 0x2000<br />
4 Byte Breite<br />
Anfang des Stacks<br />
pop eax<br />
...<br />
• <strong>Der</strong> Inhalt auf den<br />
ESP zeigt wird in<br />
das Register eax<br />
geschrieben<br />
• ESP wird um 4<br />
erhöht<br />
0x1000 0x0000FFFF<br />
0x0FFC 0x00000001<br />
●<br />
Nächste Aktion:<br />
pop ebx<br />
ESP<br />
●<br />
Bedeutung: das oberste Double Word (4 Byte)<br />
vom Stack in das Register ebx laden<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-62<br />
Beispiel für Elementare Stack Instruktionen<br />
• Aktuelle Aktion:<br />
Adresse: 0x2000<br />
4 Byte Breite<br />
Anfang des Stacks<br />
pop ebx<br />
...<br />
• <strong>Der</strong> Inhalt auf den<br />
ESP zeigt wird in<br />
das Register ebx<br />
geschrieben<br />
0x1000<br />
0x0000FFFF<br />
ESP<br />
• ESP wird um 4<br />
erhöht<br />
●<br />
Fertig!<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-63<br />
Funktionen<br />
• Für die Unterstüt<strong>zu</strong>ng von Funktionen müssen 3 wichtige<br />
Probleme gelöst werden:<br />
• Rücksprungadresse merken (auf dem Stack)<br />
• Parameterübergabe regeln (auf dem Stack)<br />
• Übergabe des Rückgabewertes regeln (meist in eax)<br />
• <strong>Der</strong> Instruktionssatz stellt Hilfsmittel <strong>zu</strong>r Lösung dieser<br />
Probleme <strong>zu</strong>r Verfügung<br />
• Die Regelung wie diese Hilfsmittel angewendet werden ist<br />
abhängig von Compiler und Programmiersprache<br />
• Man nennt diese Regelung „Calling Convention“<br />
• Wir betrachten in Folgenden die Calling Convention von C<br />
• Wenn man <strong>Assembler</strong> mit anderen Hochsprachen<br />
kombinieren will muss man deren Calling Convention<br />
verwenden<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-64<br />
Rücksprungadresse merken:<br />
call und ret<br />
• In <strong>Assembler</strong> wird eine Funktion mit call aufgerufen:<br />
• Beispiel: call eingabe<br />
• ESP wird um 4 verringert, die Rücksprungadresse (Adresse des<br />
Befehls nach call) wird an diese Stelle gelegt (wie bei push)<br />
• dann wird <strong>zu</strong>r Instruktion mit dem Label eingabe gesprungen<br />
• In <strong>Assembler</strong> kehrt man mit ret aus einer Funktion <strong>zu</strong>rück:<br />
• Beispiel: ret<br />
• Das Register EIP wird vom Stack geladen, ESP wird um 4 erhöht<br />
- EIP ist der Extended Instruction Pointer, er zeigt auf den als nächstes<br />
aus<strong>zu</strong>führenden Befehl<br />
• Da<strong>zu</strong> muss natürlich der ESP auf die richtige Position im Stack<br />
zeigen<br />
- problematisch wenn die Funktion den Stack selbst verwendet<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-65<br />
Beispiel für Funktionsaufruf<br />
mov eax, 0x10 ; Die größere der beiden Zahlen<br />
mov ebx, 0x20 ; soll in ecx gespeichert werden<br />
dump_regs 1 ; Registerwerte ausgeben<br />
dump_stack2 1,0,2 ; Stack ausgeben<br />
call max<br />
dump_regs 2 ; Registerwerte ausgeben<br />
...<br />
max: dump_stack2 2,0,2 ; Stack ausgeben<br />
cmp eax, ebx ; <strong>Der</strong> Vergleich<br />
jl bgr<br />
mov ecx, eax<br />
jmp ende<br />
bgr: mov ecx, ebx<br />
ende: ret<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-66<br />
Beispiel für Funktionsaufruf<br />
Ausgabe:<br />
Register Dump # 1<br />
EAX = 00000010 EBX = 00000020 ECX = 401579A8 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 0804843F FLAGS = 200286 SF PF<br />
Stack Dump # 1<br />
EBP = BFFFF4E8 ESP = BFFFF4C8<br />
+8 BFFFF4D0 BFFFF4E8<br />
+4 BFFFF4CC 40014580<br />
+0 BFFFF4C8 BFFFF544<br />
Stack Dump # 2<br />
EBP = BFFFF4E8 ESP = BFFFF4C4<br />
+8 BFFFF4CC 40014580<br />
+4 BFFFF4C8 BFFFF544<br />
+0 BFFFF4C4 08048462<br />
Register Dump # 2<br />
EAX = 00000010 EBX = 00000020 ECX = 00000020 EDX = 40158E90<br />
ESI = 40014580 EDI = BFFFF544 EBP = BFFFF4E8 ESP = BFFFF4C8<br />
EIP = 08048462 FLAGS = 200287 SF PF CF<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-67<br />
Parameterübergabe<br />
• Bei den Calling Conventions von C werden<br />
Parameter auf dem Stack übergeben<br />
• Ablauf<br />
• der Aufrufer legt die Parameter auf den Stack (push)<br />
• der Aufrufer ruft die Funktion auf (call)<br />
• die Funktion wird bearbeit und beendet (ret)<br />
• der Aufrufer nimmt die Parameter vom Stack (add<br />
esp,wert)<br />
• Achtung: Parameter bleiben auf dem Stack liegen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-68<br />
Beispiel für Parameterübergabe<br />
Prof. Dr. Stefan Fischer<br />
push dword 0x10 ; Parameter auf den Stack legen<br />
push dword 0x20<br />
dump_stack2 1,0,2 ; Stack ausgeben<br />
call max ; Funktion aufrufen<br />
dump_regs 1 ; Registerwerte ausgeben<br />
add esp, 8 ; Parameter vom Stack nehmen<br />
...<br />
max: mov ebx, [esp+8]<br />
cmp ebx, [esp+4]<br />
jl bkl<br />
mov eax, ebx<br />
jmp ende<br />
bkl: mov eax, [esp+4]<br />
ende: ret<br />
; Achtung Rücksprungadresse steht auf<br />
; dem Stack<br />
; Rückgabe über eax<br />
Stack Dump # 1<br />
EBP = BFFFDF58 ESP = BFFFDF30<br />
+8 BFFFDF38 BFFFDFB4<br />
+4 BFFFDF34 00000010<br />
+0 BFFFDF30 00000020<br />
Register Dump # 1<br />
EAX = 00000020 EBX = 00000010 ECX = 00000001 EDX = 401570C0<br />
ESI = 40014020 EDI = BFFFDFB4 EBP = BFFFDF58 ESP = BFFFDF30<br />
EIP = 08048418 FLAGS = 0287 SF PF CF<br />
Informatik III: <strong>Assembler</strong>
3-69<br />
Lokale Variablen<br />
• Lokale Variablen werden ebenfalls auf dem Stack abgelegt<br />
• Wenn sich ESP innerhalb einer Funktion ändert wird es<br />
schwierig auf die Parameter und die lokalen Variablen<br />
<strong>zu</strong><strong>zu</strong>greifen<br />
• Daher: ein weiteres spezielles Register<br />
• Extended Base Pointer (EBP)<br />
• EBP markiert den Beginn einer Funktion auf dem Stack<br />
• bei Funktionseintritt wird der alte Wert von EBP auf den Stack<br />
gelegt (push)<br />
- ... um ihn für die Rückkehr <strong>zu</strong>r aufrufenden Funktion <strong>zu</strong> speichern<br />
• dann wird EBP der Wert von ESP <strong>zu</strong>gewiesen<br />
• dann wird Platz für lokale Variablen geschaffen:<br />
- addiere <strong>zu</strong> ESP die Größe der lokalen Variablen<br />
• bei Funktionsende werden die lokalen Variablen vom Stack<br />
gelöscht und der alte Wert von EBP wieder hergestellt<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-70<br />
Beispiel<br />
diff: dump_stack2 1,0,2 ; Stack ausgeben<br />
push ebp ; alter Wert von ebp sichern<br />
mov ebp, esp ; neuen Wert von ebp laden<br />
sub esp, 4 ; 4 Byte für lokale Variablen reservieren<br />
mov eax, [ebp+12] ; Parameter 1 in der lokalen Variablen speichern<br />
mov [ebp-4], eax<br />
mov eax, [ebp+8] ; Parameter 2 von der lokalen Variablen abziehen<br />
sub [ebp-4], eax ; danach müsste man sinnvoller Weise was damit<br />
; machen<br />
dump_stack2 2,0,4 ; wir geben es nur aus<br />
add esp, 4<br />
; lokale Variablen vom Stack nehmen<br />
pop ebp<br />
; ebp wieder herstellen<br />
ret ; <strong>zu</strong>rück <strong>zu</strong>m Aufrufer<br />
Stack Dump # 1<br />
EBP = BFFFEBD8 ESP = BFFFEBAC<br />
+8 BFFFEBB4 00000020<br />
+4 BFFFEBB0 00000010<br />
+0 BFFFEBAC 08048404<br />
Stack Dump # 2<br />
EBP = BFFFEBA8 ESP = BFFFEBA4<br />
+16 BFFFEBB4 00000020<br />
+12 BFFFEBB0 00000010<br />
+8 BFFFEBAC 08048404<br />
+4 BFFFEBA8 BFFFEBD8<br />
+0 BFFFEBA4 00000010<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-71<br />
Vereinfachung<br />
• Das Setzen von ebp und das Reservieren von Speicher für<br />
lokale Variablen nennt man Prolog einer Funktion<br />
• Das Löschen der Variablen vom Stack und das<br />
Wiederherstellen von ebp nennt man Epilog einer Funktion<br />
• Da Prolog und Epilog sehr häufig vorkommen gibt es spezielle<br />
Instruktionen dafür:<br />
• enter op1, op2<br />
- push ebp<br />
- mov ebp, esp<br />
- sub esp op1<br />
- op2 wird bei den C Calling Conventions nicht benötigt<br />
• leave<br />
- mov esp, ebp<br />
- pop ebp<br />
• Achtung: enter benötigt mehr Zeit für die Ausführung als die<br />
einzelnen Instruktionen <strong>zu</strong>sammen<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-72<br />
Beispiel<br />
diff: dump_stack2 1,0,2 ; Stack ausgeben<br />
enter 4,0 ; ebp setzen, Platz für lokale Variablen schaffen<br />
mov eax, [ebp+12] ; Parameter 1 in der lokalen Variablen speichern<br />
mov [ebp-4], eax<br />
mov eax, [ebp+8] ; Parameter 2 von der lokalen Variablen abziehen<br />
sub [ebp-4], eax ; danach müsste man sinnvoller Weise was damit<br />
; machen<br />
dump_stack2 2,0,4 ; wir geben es nur aus<br />
leave ; lokale Variablen löschen, ebp wieder herstellen<br />
ret ; <strong>zu</strong>rück <strong>zu</strong>m Aufrufer<br />
Stack Dump # 1<br />
EBP = BFFFEBD8 ESP = BFFFEBAC<br />
+8 BFFFEBB4 00000020<br />
+4 BFFFEBB0 00000010<br />
+0 BFFFEBAC 08048404<br />
Stack Dump # 2<br />
EBP = BFFFEBA8 ESP = BFFFEBA4<br />
+16 BFFFEBB4 00000020<br />
+12 BFFFEBB0 00000010<br />
+8 BFFFEBAC 08048404<br />
+4 BFFFEBA8 BFFFEBD8<br />
+0 BFFFEBA4 00000010<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-73<br />
Aufruf einer C-Funktion<br />
• C-Funktionen können direkt von <strong>Assembler</strong> aus aufgerufen<br />
werden<br />
• Parameter werden in umgekehrter Reihenfolge auf den<br />
Stack gelegt (der letzte Parameter als erstes)<br />
• Sinnvoll, da bei manchen Funktionen in C die Anzahl der<br />
Parameter variabel ist<br />
• Einer der nicht variablen Parameter bestimmt wie viele Parameter<br />
vorhanden sind<br />
• Die nicht variablen Parameter stehen damit relativ <strong>zu</strong>m EBP an<br />
einer festen Stelle<br />
• Beispiel: printf(“x = %d\n“,100);<br />
• Unter Windows: „_“ dem Funktionsnamen voranstellen<br />
• Rückgabe: erfolgt bei Integer Werten über eax<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-74<br />
Beispiel: Aufruf von printf<br />
extern printf ; Versprechen, dass das Symbol printf später hin<strong>zu</strong>kommt<br />
segment .data<br />
x: dd 100<br />
format: db "X = %d",10,0<br />
; 10=lf, 0=Ende des Strings<br />
; (C Konvention)<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0 ; Funktion initialisieren<br />
pusha<br />
push dword [x]<br />
push dword format<br />
call printf<br />
add esp, 8<br />
; x auf den Stack legen<br />
; die Adresse! von format auf den Stack<br />
; legen<br />
; Funktion aufrufen<br />
popa ; Zu C <strong>zu</strong>rückkehren<br />
mov eax, 0<br />
leave<br />
ret<br />
Ausgabe: X = 100<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-75<br />
Retten von Registern<br />
• C erwartet, dass einige Register nach Rückkehr<br />
aus einer Funktion wieder ihren alten Wert<br />
beinhalten<br />
• Unterstützt durch pusha und popa:<br />
• pusha schreibt die Register EAX, ECX, EDX, EBX,<br />
ESP, EBP, ESI und EDI auf den Stack (=32 Byte) und<br />
reduziert dann ESP um 32<br />
• popa holt die Register in umgekehrter Reihenfolge vom<br />
Stack und erhöht ESP dann um 32<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-76<br />
Beispiel<br />
%include "asm_io.inc"<br />
segment .text<br />
global asm_main<br />
asm_main:<br />
enter 0,0 ; Funktionseintritt<br />
pusha<br />
mov ebx, 1 ; lade eine 1 in das Register ebx<br />
dump_regs 1 ; gib Register aus<br />
popa ; nach C <strong>zu</strong>rückkehren<br />
mov eax, 0<br />
; Rückgabeparameter setzen<br />
leave<br />
ret<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-77<br />
Stack Frame<br />
• Mit Stack Frame bezeichnet man den Bereich auf<br />
dem Stack, der <strong>zu</strong> einer Funktion gehört<br />
• Das ist der Bereich von EBP bis <strong>zu</strong>m ESP:<br />
• alter EBP<br />
• gesicherte Register Inhalte<br />
• lokale Variablen<br />
• sonstiges<br />
• Achtung, übergebene Parameter gehören daher<br />
<strong>zu</strong>m Stackframe der aufrufenden Funktion<br />
• darüber kann man sich streiten<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-78<br />
Von C <strong>zu</strong> <strong>Assembler</strong><br />
• Ein Kompiler übersetzt Programme einer Hochsprache in<br />
Instruktionen des Befehlssatzes eines Prozessors<br />
• Das kann man mit gcc sehr gut ausprobieren<br />
• Was macht gcc wenn er für eine .c Datei aufgerufen wird:<br />
• <strong>zu</strong>ächst wird der C-Präprozessor (cpp) ausgeführt<br />
- Resultat: eine .C Datei<br />
• dann wird kompiliert, das C-Programm wird in ein <strong>Assembler</strong><br />
Programm übersetzt<br />
- Resultat: eine .s Datei<br />
• dann wird assembliert (mit gas), das <strong>Assembler</strong> Programm wird in<br />
Instruktionen des Prozessors umgesetzt<br />
- Resultat: eine .o Datei<br />
• dann werden alle benötigten Dateinen und Bibliotheken<br />
<strong>zu</strong>sammengelinkt (mit ld)<br />
- Resultat: ausführbares Programm<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-79<br />
Beispiel<br />
#include <br />
int main() {<br />
printf("Hello World!\n");<br />
return 0;<br />
}<br />
Übersetzen mit gcc hello.c -S<br />
Ergebnis: hello.s<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-80<br />
<strong>Assembler</strong> Code<br />
.file "hello.c"<br />
.section .rodata<br />
.LC0:<br />
.string "Hello World!\n"<br />
.text<br />
.globl main<br />
.type main, @function<br />
main:<br />
pushl %ebp # push ebp<br />
movl %esp, %ebp # mov ebp, esp<br />
subl $8, %esp # sub esp, 8<br />
andl $-16, %esp # and eps, -16 (löscht die unteren 4 Bit)<br />
movl $0, %eax # mov eax, 0<br />
subl %eax, %esp # sub esp, eax<br />
movl $.LC0, (%esp) # mov esp, .LC0<br />
call printf # cal printf<br />
movl $0, %eax # mov eax, 0<br />
leave # leave<br />
ret # ret<br />
.size main, .-main<br />
.section .note.GNU-stack,"",@progbits<br />
.ident "GCC: (GNU) 3.3.2 20040119 (Gentoo Linux 3.3.2-r7)"<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-81<br />
gdb – ein einfacher Debugger<br />
• Bisher:<br />
• Finden von Fehlern durch Ausgabe der Register<br />
• Umständlich und unpraktisch<br />
• Besser wäre:<br />
- Programm ab einem kritischen Punkt Schrittweise abarbeiten<br />
- Bei jedem Schritt Inhalt von Registern und Stack untersuchen<br />
• Dafür gibt es sogenannte Debugger:<br />
• Für alle Programmiersprachen<br />
• unterschiedlich komfortabel (Benutzeroberfläche)<br />
• für Java -> Behandlung im Programmierpraktikum<br />
• für <strong>Assembler</strong>:<br />
- gdb (GNU DeBugger)<br />
- unter Linux<br />
(unter Windows: debug, anderer Debugger, andere Befehle!)<br />
- Kommandozeile<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-82<br />
gdb<br />
• Starten mit: gdb <br />
• Z.B. gdb ./first<br />
• Hilfe mit help<br />
• Starten des Programms im gdb: run<br />
• .... dann läuft das Programm normal ab<br />
• Um es an einer bestimmten Stelle an<strong>zu</strong>halten, verwendet<br />
man Breakpoints (vor Starten mit run!):<br />
• setzen mit break *+offset<br />
- label = ein Label im <strong>Assembler</strong> Sourcecode<br />
- offset = Verschieben um offset Bytes<br />
• Auflisten aller Breakpoints mit info break<br />
• Löschen von Breakpoints mit delete <br />
- nummer=die Nummer des Breakpoints (bekommt man über info break)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-83<br />
Beispiel<br />
fischer@picard:~/cvs/lehre/info3/vorlesung/assembler$ gdb ./first<br />
GNU gdb 5.3<br />
Copyright 2002 Free Software Foundation, Inc.<br />
(gdb) break *asm_main<br />
Breakpoint 1 at 0x8048410<br />
(gdb) info break<br />
Num Type Disp Enb Address What<br />
1 breakpoint keep y 0x08048410 <br />
(gdb) delete 1<br />
(gdb) info break<br />
No breakpoints or watchpoints.<br />
(gdb)<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-84<br />
Weitere typische Kommandos<br />
• Wenn man einen Breakpoint mit break gesetzt hat und das<br />
Programm mit run gestartet hat, dann hält es bei Erreichen des<br />
Breakpoints an.<br />
• Nun kann man den Inhalt von Speicher und Registern<br />
betrachten:<br />
• Ausgabe von Registern:<br />
• Ausgabe einzelner Register und Speicherbereiche<br />
• Ausführen der nächsten Instruktion(en):<br />
• stepi<br />
• Ausführen der nächsten Instruktion(en), überspringen von<br />
Funktionsaufrufen:<br />
• nexti<br />
• Ausführen bis <strong>zu</strong>m Ende einer Funktion: finish<br />
• Ausführen bis <strong>zu</strong>m nächsten Breakpoint: continue<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>
3-85<br />
Fazit Debugger<br />
• Debugger sind SEHR! hilfreich<br />
• Man benötigt fast immer einen Debugger wenn man<br />
ernsthaft Software entwickelt<br />
• gdb ist etwas archaisch<br />
• Insbesondere bei Entwicklungsumgebungen unter<br />
Windows gibt es sehr komfortable Debugger<br />
• mit grafischer Oberfläche<br />
• Unter Unix ist ddd als Benutzeroberfläche für gdb <strong>zu</strong><br />
empfehlen<br />
• für <strong>Assembler</strong> nicht ganz unproblematisch<br />
Prof. Dr. Stefan Fischer<br />
Informatik III: <strong>Assembler</strong>