FreeBSD Developers' Handbook
Zurück | Kapitel 11. x86-Assembler-Programmierung | Weiter

# 11.3. Systemaufrufe

Übersetzt von Hagen Kühl.

## 11.3.1. Standard-Aufrufkonvention

Standardmäßig benutzt der FreeBSD-Kernel die C-Aufrufkonvention. Weiterhin wird, obwohl auf den Kernel durch `int 80h` zugegriffen wird, angenommen, dass das Programm eine Funktion aufruft, die `int 80h` verwendet, anstatt `int 80h` direkt aufzurufen.

Diese Konvention ist sehr praktisch und der Microsoft®-Konvention von MS-DOS® überlegen. Warum? Weil es die UNIX®-Konvention jedem Programm, egal in welcher Sprache es geschrieben ist, erlaubt auf den Kernel zuzugreifen.

Ein Assembler-Programm kann das ebenfalls. Beispielsweise könnten wir eine Datei öffnen:

    kernel:
    	int	80h	; Call kernel
    	ret

    open:
    	push	dword mode
    	push	dword flags
    	push	dword path
    	mov	eax, 5
    	call	kernel
    	add	esp, byte 12
    	ret

Das ist ein sehr sauberer und portabler Programmierstil. Wenn Sie das Programm auf ein anderes UNIX portieren, das einen anderen Interrupt oder eie andere Art der Parameterübergabe verwendet, müssen sie nur die Prozedur kernel ändern.

Aber Assembler-Programmierer lieben es Taktzyklen zu schinden. Das obige Beispiel benötigt eine `call/ret`-Kombination. Das können wir entfernen, indem wir einen weiteren Parameter mit `push` übergeben:

    open:
    	push	dword mode
    	push	dword flags
    	push	dword path
    	mov	eax, 5
    	push	eax		; Or any other dword
    	int	80h
    	add	esp, byte 16

Die Konstante `5`, die wir in `EAX` ablegen, identifiziert die Kernel-Funktion, die wir aufrufen. In diesem Fall ist das `open`.

## 11.3.2. Alternative Aufruf-Konvention

FreeBSD ist ein extrem flexibles System. Es bietet noch andere Wege, um den Kernel aufzurufen. Damit diese funktionieren muss allerdings die Linux-Emulation installiert sein.

Linux ist ein UNIX-artiges System. Allerdings verwendet dessen Kernel die gleiche Systemaufruf-Konvention, bei der Parameter in Registern abgelegt werden, wie MS-DOS. Genau wie bei der UNIX-Konvention wird die Nummer der Funktion in `EAX` abgelegt. Allerdings werden die Parameter nicht auf den Stack gelegt, sondern in die Register `EBX, ECX, EDX, ESI, EDI, EBP`:

    open:
    	mov	eax, 5
    	mov	ebx, path
    	mov	ecx, flags
    	mov	edx, mode
    	int	80h

Diese Konvention hat einen großen Nachteil gegenüber der von UNIX, was die Assembler-Programmierung angeht: Jedesmal, wenn Sie einen Kernel-Aufruf machen, müssen Sie die Register `push`en und sie später `pop`en. Das macht Ihren Code unförmiger und langsamer. Dennoch lässt FreeBSD ihnen die Wahl.

Wenn Sie sich für die Linux-Konvention entscheiden, müssen Sie es das System wissen lassen. Nachdem ihr Programm übersetzt und gebunden wurde, müssen Sie die ausführbare Datei kennzeichnen:

    %
    	brandelf -t Linux
    	filename

## 11.3.3. Welche Konvention Sie verwenden sollten

Wenn Sie speziell für FreeBSD programmieren, sollten Sie die UNIX-Konvention verwenden: Diese ist schneller, Sie können globale Variablen in Registern ablegen, Sie müssen die ausführbare Datei nicht kennzeichnen und Sie erzwingen nicht die Installation der Linux-Emulation auf dem Zielsystem.

Wenn Sie portablen Programmcode erzeugen wollen, der auch unter Linux funktioniert, wollen Sie den FreeBSD-Nutzern vielleicht dennoch den effizientesten Programmcode bieten, der möglich ist. Ich werde Ihnen zeigen, wie Sie das erreichen können, nachdem ich die Grundlagen erklärt habe.

## 11.3.4. Aufruf-Nummern

Um dem Kernel mitzuteilen welchen Dienst Sie aufrufen, legen Sie dessen Nummer in `EAX` ab. Natürlich müssen Sie dazu wissen welche Nummer die Richtige ist.

### 11.3.4.1. Die Datei `syscalls`

Die Nummer der Funktionen sind in der Datei `syscalls` aufgeführt. Mittels `locate syscalls` finden Sie diese in verschiedenen Formaten, die alle auf die gleiche Weise aus `syscalls.master` erzeugt werden.

Die Master-Datei für die UNIX-Standard-Aufrufkonvention finden sie unter `/usr/src/sys/kern/syscalls.master`. Falls Sie die andere Konvention, die im Linux-Emulations-Modus implementiert ist, verwenden möchten, lesen Sie bitte `/usr/src/sys/i386/linux/syscalls.master`.

> Anmerkung: FreeBSD und Linux unterscheiden sich nicht nur in den Aufrufkonventionen, sie haben teilweise auch verschiedene Nummern für die gleiche Funktion.

`syscalls.master` beschreibt, wie der Aufruf gemacht werden muss:

    0	STD	NOHIDE	{ int nosys(void); } syscall nosys_args int
    1	STD	NOHIDE	{ void exit(int rval); } exit rexit_args void
    2	STD	POSIX	{ int fork(void); }
    3	STD	POSIX	{ ssize_t read(int fd, void *buf, size_t nbyte); }
    4	STD	POSIX	{ ssize_t write(int fd, const void *buf, size_t nbyte); }
    5	STD	POSIX	{ int open(char *path, int flags, int mode); }
    6	STD	POSIX	{ int close(int fd); }
    etc...

In der ersten Spalte steht die Nummer, die in `EAX` abgelegt werden muss.

Die Spalte ganz rechts sagt uns welche Parameter wir `push`en müssen. Die Reihenfolge ist dabei von rechts nach links.

Um beispielsweise eine Datei mittels `open` zu öffnen, müssen wir zuerst den `mode` auf den Stack `push`en, danach die `flags`, dann die Adresse an der der `path` gespeichert ist.

Zurück | Zum Anfang | Weiter
Die Werkzeuge | Nach oben | Rückgabewerte

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.