Ich hatte erst vor hier ein eigenes Wiki zu eröffnen, aber mir fehlt die Zeit um mich nun auch noch in dokuWiki einzuarbeiten und vieles in Assembler kann von dem C Tutorial abgeleitet werden (Stack, Variablen etc.). Sprich es wäre viel doppelte Arbeit.
Dennoch möchte ich an dieser Stelle ein paar Code Schnipsel übergeben, welche ich gestern für das Wiki Angefertigt habe. Der Quellcode ist gut dokumentiert und es sollte dem interessierten Leser gleich klar sein, worum es geht :
Ausgehend vom obigen Post, setzte ich die Programme : nasm, ddd und scite vorraus - sprich Linux Umgebung
Assembler Debuggen:
Die folgenden 3 Listings dienen dazu dem Interessierten mehr über Debugging und was da eigentlich während des Programmablaufs passiert zu veranschaulichen : [Register]
(Formatierung des Quellcodes ist leider verschoben, da die Tabulatoren nicht richtig interpretiert werden)
So sieht der Debugger mit folgendem Listing aus :
http://s1.directupload.net/file/d/2700/4wwh8csa_png.htm
Datei: example_001a.asm
Code: Alles auswählen
; Projekt : Debuggen
;
; Beschreibung : Kleines Tool zum Testen von Debug Informationen
; Es werden ein paar Dezimalwerte in die Register
; geschrieben.
; Register : eax, ebx, ecx, edx (32 bit)
; Uebersetzen :
; nasm -f elf -F dwarf example_001a.asm
; ld -o example_001a example_001a.o
; Debuggen :
; ddd ./example_001a
section .data
section .text
global _start
_start:
mov eax, 255 ; 255 Dez. nach eax schreiben
mov ebx, 127 ; 127 Dez. nach ebx schreiben
mov ecx, 3 ; 3 Dez. nach ecx schreiben
add ebx, ecx ; Addiere: ebx = ebx + ecx
mov edx, eax ; Kopiere den Wert von eax nach edx
sub edx, ecx ; Subtrahiere: edx = edx - ecx;
; Programmende: return (0)
mov eax,1 ; Systemcall fuer Exit
mov ebx,0 ; Exit Code (NULL)
int 80h ; Kernel zum Ausfuehren aufrufen
Listing 2 veranschaulicht die Benutzung des Stacks an einem sehr einfachen Beispiels.
Datei: example_001b.asm
Code: Alles auswählen
; Projekt : Debuggen
;
; Beschreibung : Kleines Tool zum Testen von Debug Informationen
; Es wird ein Dezimalwert auf den Stack gelegt und
; wieder abgerufen.
; Register : eax, ebx, ecx (32 bit)
; Stack : esp (32 bit)
; Uebersetzen :
; nasm -f elf -F dwarf example_001b.asm
; ld -o example_001b example_001b.o
; Debuggen :
; ddd ./example_001b
section .data
section .text
global _start
_start:
mov eax, 100 ; 100 Dez. nach eax schreiben
mov ebx, 25 ; 25 Dez. nach ebx schreiben
push eax ; eax auf den Stack legen (100)
sub eax, ebx ; Subtrahiere: eax = eax - ebx (75)
mov ecx,eax ; Kopiere eax nach ecx
pop eax ; Den letzen Stackwert abrufen und
; nach eax schreiben (100)
sub eax, ecx ; Subtrahiere: eax = eax - ecx (25)
; Programmende: return (0)
mov eax,1 ; Systemcall fuer Exit
mov ebx,0 ; Exit Code (NULL)
int 80h ; Kernel zum Ausfuehren aufrufen
Im folgenden Listing wird gezeigt, wie man durch indirekte Adressierung an Informationen auf dem Stack gelangt, ohne sie vorher abzurufen (pop).
Datei: example_001c.asm
Code: Alles auswählen
; Projekt : Debuggen
;
; Beschreibung : Kleines Tool zum Testen von Debug Informationen
; Es wird mit Hilfe des Stacks die Direkte Adressierung
; erklaert.
; Register : eax, ebx, ecx (32 bit)
; Stack : esp (32 bit)
; Uebersetzen :
; nasm -f elf -F dwarf example_001c.asm
; ld -o example_001c example_001c.o
; Debuggen :
; ddd ./example_001c
section .data
section .text
global _start
_start:
mov eax, 100 ; 100 Dez. nach eax schreiben
mov ebx, 50 ; 50 Dez. nach ebx schreiben
push eax ; Den Wert von eax auf den Stack legen
push ebx ; Den Wert von ebx auf den Stack legen
mov ecx,200 ; 200 Dez. nach ecx schreiben
sub ecx,[esp] ; Subtrahiere: ecx = ecx - letzen Stackeintrag[50] (150)
sub ecx,[4+esp] ; Subtrahiere: ecx = ecx - vorletzten Stackeintrag[100] (50)
; Der Stack ist 4 Byte (32bit) breit. Wenn wir
; also [4+esp] schreiben, zeigt der Zeiger auf
; das vorletzte Element. In diesem Beispiel also
; auf den Wert 100.
add ecx, 25 ; Addiere 25 zu ecx (75)
mov [4+esp],ecx ; Schreibe ecx (75) in den vorletzten Stackeintrag
; Damit ueberschreiben wir den Anfangswert von 100
; Im Stack sind nun [esp] 50 und [4+esp] 75 gespeichert.
mov eax, 0 ; Der Übersicht halber löschen wir die 3 Register
mov ebx, 0 ; um im Debugger das Ergebnis besser zu sehen.
mov ecx, 0
pop eax ; Hole letzten Stack Eintrag
pop ebx ; Hole letzten Stack Eintrag ( da wir ebend mit pop eax
; den letzten Eintrag geholt haben ist der vorletzte nun
; der letzte)
; Programmende: return (0)
mov eax,1 ; Systemcall fuer Exit
mov ebx,0 ; Exit Code (NULL)
int 80h ; Kernel zum Ausfuehren aufrufen
Das folgende Listing dient der Veranschaulichung von Macros innerhalb von Assembler. Macros können benutzt werden um den Quellcode lesbarer und besser Wartbar zu machen.
Hierbei sollte man beachten, das die Macros während des Kompilierungsprozesses inline übersetzt werden. Es sind also keine Funktionen. Wichtig bei der Benutzung von Registern die evtl. durch das Macro überschrieben werden können, obwohl es im Quellcode erstmal nicht den Anschein hat.
Datei: example_002a.asm
Code: Alles auswählen
; Projekt : Macros und I/O Operationen
;
; Beschreibung : Ein einfaches Beispiel wie Macros benutzt um die
; Lesbarkeit des Quellcodes zu erhalten.
; Ein einfaches 'Hello, World' Programm
; Uebersetzen :
; nasm -f elf -F dwarf example_002a.asm
; ld -o example_002a example_002a.o
; Debuggen :
; ddd ./example_002a
section .data
MSG_STR db 'Hallo Welt! ', 10 ; Wir hängen dem String noch ein LF (dez. 10) an.
MSG_SIZE equ $ - MSG_STR
section .bss
%macro write 2 ; Definiert ein Macro mit zwei Parametern [write (%1,%2)]
mov eax, 4 ; sys_write
mov ebx, 1 ; STDOUT
mov ecx, %1 ; const char *
mov edx, %2 ; size_t
int 80h ; Execute
%endmacro
section .text
global _start
_start:
write MSG_STR, MSG_SIZE ; Rufe das Macro write auf (printf)
; Schau dir den Code im Debugger an. Das
; Macro wird hier eingefügt, da es sich NICHT
; um eine Funktion handelt!
_exit:
; Programmende: return (0)
mov eax,1 ; Systemcall fuer Exit
mov ebx,0 ; Exit Code (NULL)
int 80h ; Kernel zum Ausfuehren aufrufen
Und zu guter Letzt: Nun wird es interactiv ....
Datei: example_002b.asm
Code: Alles auswählen
; Projekt : Macros und I/O Operationen
;
; Beschreibung : Ein einfaches Beispiel wie Macros benutzt um die
; Lesbarkeit des Quellcodes zu erhalten.
; Das Programm fragt den Benutzer nach seinem Namen und
; gibt danach eine nette Begrüßung aus.
; Uebersetzen :
; nasm -f elf -F dwarf example_002b.asm
; ld -o example_002b example_002b.o
; Debuggen :
; ddd ./example_002b
section .data
MSG_STR db 'Wie lautet dein Name : '
MSG_SIZE equ $ - MSG_STR
GREET_STR db 'Willkommen, '
GREET_SIZE equ $ - GREET_STR
section .bss
buff resb 25 ; Reserviere 25 Byte Speicher
%macro write 2 ; Definiert ein Macro mit zwei Parametern [write (%1,%2)]
mov eax, 4 ; sys_write
mov ebx, 1 ; STDOUT
mov ecx, %1 ; const char *
mov edx, %2 ; size_t
int 80h ; Execute
%endmacro
%macro read 2 ; Definiert ein Macro mit zwei Parametern [read (%1, %2)]
mov eax, 3 ; sys_read
mov ebx, 0 ; STDIN
mov ecx, %1 ; char *
mov edx, %2 ; size_t
int 80h
%endmacro
section .text
global _start
_start:
write MSG_STR, MSG_SIZE ; Rufe das Macro write auf (printf)
read buff, 25 ; Rufe das Macro read auf (cin)
push eax ; Die Länge der Eingabe wird von read in eax zurückgegeben
; die wir auf den Stack sichern
write GREET_STR, GREET_SIZE ; Rufe das Macro write auf (printf)
pop edx ; Hole die Länge des Strings wieder vom Stack
; und schreibe sie direkt in edx.
; (Warum nicht wieder nach eax? - Schau Dir den Code
; im Debugger an ...)
write buff, edx ; Rufe nun das Macro write auf (printf)
_exit:
; Programmende: return (0)
mov eax,1 ; Systemcall fuer Exit
mov ebx,0 ; Exit Code (NULL)
int 80h ; Kernel zum Ausfuehren aufrufen
Beim Letzten Listing: Versucht mal mehr als 25 Zeichen einzugeben und schaut was passiert. Frag dich, Warum ist das so? Wie kann ich das Problem lösen ?
Alle Programme wurden getestet und sind lauffähig. Ich wünsche dem Interessierten viel Spaß bei seinen ersten Schritten in Assembler.
Gruß Sunji