Früher:
Ein aktiver Prozess, der Zugriff auf alles hat (DOS, DOS-Spiele)
Direkter Hardware-Zugriff durch die Prozesse
Heute:
Mehrere Prozesse, die (quasi-)parallel arbeiten
Betriebssystem muss Hardware-Zugriff der Prozesse abstrahieren und verwalten
(Mehr Details in der Veranstaltung Betriebs- und Kommunikationssysteme, dem 2. Teil des Moduls)
Programmfluss des aktuellen Prozesses wird unterbrochen
Betriebssystem wir mitgeteilt, dass ein Syscall des Prozesses ausgeführt wurde
Betriebssystem führt die Funktionalität aus
Prozess wird fortgesetzt
Wollen ein kleines Programm schreiben, welches nicht mit dem gcc kompiliert werden muss
section .text
global _start ; Wird ein Prozess gestartet, wird bei
_start: ; _start mit der Ausführung begonnen
retWir müssen weiterhin zuerst assemblieren
nasm -f elf64 test.asmDie entstehende o-Datei muss ausführbargemacht werden (Linken)
ld -o test test.oBeim Ausführen stürzt das Programm ab
Wir gucken uns an, an welche Adresse im Code er denn springen möchte
section .text
global _start
_start:
pop rax
retAngucken im Debugger:
gdb test # Debugger mit unserem Programm starten
break _start # Beim Erreichen der Marke _start stoppen
run # Programm starten
stepi # Nächste Instruktion (pop rax) ausführen
print $rax # Wert von rax ausgeben
quit # Debugger beendenErgebnis: Er will an Adresse 1 Code ausführen, dort liegt aber kein Code
Dies ist offenbar nicht der richtige Weg das Programm zu beenden
Weglassen von ret führt auch zu Absturz
Lösung: Wir müssen dem Betriebssystem mitteilen, dass wir fertig sind, damit das Betriebssystem den Prozess entfernt
Dafür benötigen wir einen Syscall
Grundlegend ist die Benutzung nicht (viel) anders als bei normalen Funktionsaufrufen
Funktionsparameter werden in den Registern rdi, rsi, rdx, r10, r8 und r9 übergeben
Unterschied: Statt call funktionsname muss die Nummer des gewünschten Syscalls in rax geschrieben und danach der Befehl syscall verwendet werden
Hier findet sich eine Liste von Syscalls für 64-bit-Linux
Dort finden wir den Syscall sys_exit mit der Nummer 60 und einem Parameter
section .text
global _start
_start:
mov rax, 60 ; Syscall sys_exit verwenden
mov rdi, 0 ; Programm war erfolgreich
syscall ; Betriebssystem Bescheid gebenZum lesen aus und schreiben in „Dateien“ gibt es sys_read und sys_write, entsprechend den C-Funktionen read und write
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);Der erste Parameter ist ein sogenannter Dateideskriptor (englisch file descriptor), eine Zahl die eine geöffnete Datei eindeutig referenziert
Es gibt drei Standard-Deskriptoren:
0 für die Standardeingabe (dort kann ich als Benutzer nach Start des Programms etwas eintippen)
1 für die Standardausgabe (dort landet alles, was ihr z.b. auch per printf ausgegeben habt)
2 für die Fehlerausgabe, für uns nicht so wichtig und fast das gleiche wie 1