20.11.2013 Aufrufe

Der Assembler - Universität zu Lübeck

Der Assembler - Universität zu Lübeck

Der Assembler - Universität zu Lübeck

MEHR ANZEIGEN
WENIGER ANZEIGEN

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>

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!