Weitere Informationen zu den folgenden Themen finden Sie hier: Der endgültige Leitfaden für Linux-Systemaufrufe
Ich habe diese mit GNU Assembler (Gas) unter Linux überprüft.
Kernel-Schnittstelle
x86-32 aka i386 Linux Systemaufrufkonvention:
In x86-32 werden Parameter für Linux-Systemaufrufe mithilfe von Registern übergeben. %eax
für syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp werden zum Übergeben von 6 Parametern an Systemaufrufe verwendet.
Der Rückgabewert ist in %eax
. Alle anderen Register (einschließlich EFLAGS) werden in der gesamten Region beibehalten int $0x80
.
Ich nahm folgenden Ausschnitt aus dem Linux Assembly Tutorial genommen , bin mir aber nicht sicher. Wenn jemand ein Beispiel zeigen kann, wäre es großartig.
Wenn es mehr als sechs Argumente gibt,
%ebx
muss der Speicherort enthalten sein, in dem die Liste der Argumente gespeichert ist. Machen Sie sich darüber jedoch keine Sorgen, da es unwahrscheinlich ist, dass Sie einen Systemaufruf mit mehr als sechs Argumenten verwenden.
Ein Beispiel und etwas mehr Informationen finden Sie unter http://www.int80h.org/bsdasm/#alternate-calling-convention . Ein weiteres Beispiel für eine Hello World für i386 Linux mit int 0x80
: Hello, Welt in Assemblersprache mit Linux-Systemaufrufen?
Es gibt eine schnellere Möglichkeit, 32-Bit-Systemaufrufe durchzuführen: using sysenter
. Der Kernel ordnet jedem Prozess (dem vDSO) eine Speicherseite mit der User-Space-Seite des sysenter
Tanzes zu, die mit dem Kernel zusammenarbeiten muss, damit er die Rücksprungadresse finden kann. Die Zuordnung von Arg zu Register ist dieselbe wie für int $0x80
. Normalerweise sollten Sie das vDSO aufrufen, anstatt es sysenter
direkt zu verwenden. (Weitere Informationen zum Verknüpfen und Aufrufen von vDSO sowie weitere Informationen zu und alles andere, was mit Systemaufrufen zu tun hat, finden Sie im Definitiven Handbuch zu Linux-sysenter
Systemaufrufen.)
x86-32 [Free | Open | Net | DragonFly] BSD UNIX-Systemaufrufkonvention:
Parameter werden auf dem Stapel übergeben. Schieben Sie die Parameter (letzter Parameter zuerst gedrückt) auf den Stapel. Drücken Sie dann weitere 32-Bit-Dummy-Daten (es handelt sich nicht um Dummy-Daten. Weitere Informationen finden Sie unter folgendem Link) und geben Sie dann eine Systemaufrufanweisungint $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
x86-64 Linux Systemaufrufkonvention:
x86-64 Mac OS X ist ähnlich, aber unterschiedlich . TODO: Überprüfen Sie, was * BSD tut.
Siehe Abschnitt: "A.2 AMD64- Linux- Kernelkonventionen" der System V-Anwendungsbinärschnittstelle AMD64 Architecture Processor Supplement . Die neuesten Versionen der psABIs von i386 und x86-64 System V finden Sie auf dieser Seite im Repo des ABI-Betreuers . (Siehe auch diex86 Tag-Wiki für aktuelle ABI-Links und viele andere gute Dinge über x86 asm.)
Hier ist der Ausschnitt aus diesem Abschnitt:
- Anwendungen auf Benutzerebene werden als Ganzzahlregister zum Übergeben der Sequenzen% rdi,% rsi,% rdx,% rcx,% r8 und% r9 verwendet. Die Kernel-Schnittstelle verwendet% rdi,% rsi,% rdx,% r10,% r8 und% r9.
- Ein Systemaufruf erfolgt über die
syscall
Anweisung . Dadurch werden% rcx und% r11 sowie der Rückgabewert% rax blockiert , andere Register bleiben jedoch erhalten.
- Die Nummer des Systemaufrufs muss im Register% rax übergeben werden.
- Systemaufrufe sind auf sechs Argumente beschränkt, es wird kein Argument direkt an den Stapel übergeben.
- Zurück vom Systemaufruf enthält das Register% rax das Ergebnis des Systemaufrufs. Ein Wert im Bereich zwischen -4095 und -1 zeigt einen Fehler an
-errno
.
- Nur Werte der Klasse INTEGER oder der Klasse MEMORY werden an den Kernel übergeben.
Denken Sie daran, dass dies aus dem Linux-spezifischen Anhang zum ABI stammt und selbst für Linux informativ und nicht normativ ist. (Aber es ist tatsächlich genau.)
Dieses 32-Bit - int $0x80
ABI ist verwendbar in 64-Bit - Code (aber sehr nicht empfohlen). Was passiert, wenn Sie das 32-Bit-Linux-ABI int 0x80 in 64-Bit-Code verwenden? Es schneidet seine Eingaben immer noch auf 32-Bit ab, ist also für Zeiger ungeeignet und setzt r8-r11 auf Null.
Benutzeroberfläche: Funktionsaufruf
x86-32 Funktionsaufrufkonvention:
In x86-32 wurden Parameter auf Stack übergeben. Der letzte Parameter wurde zuerst auf den Stapel geschoben, bis alle Parameter fertig sind, und dann wurde die call
Anweisung ausgeführt. Dies wird zum Aufrufen von Funktionen der C-Bibliothek (libc) unter Linux aus der Assembly verwendet.
Moderne Versionen des i386 System V ABI (unter Linux verwendet) erfordern eine 16-Byte-Ausrichtung %esp
vor a call
, wie dies beim x86-64 System V ABI immer erforderlich war. Callees dürfen davon ausgehen und SSE-16-Byte-Ladevorgänge / -Speicher verwenden, die diesen Fehler bei nicht ausgerichteter Ausführung verursachen. In der Vergangenheit erforderte Linux jedoch nur eine 4-Byte-Stapelausrichtung, sodass zusätzliche Arbeit erforderlich war, um natürlich ausgerichteten Speicherplatz selbst für 8 Byte double
oder ähnliches zu reservieren .
Einige andere moderne 32-Bit-Systeme erfordern immer noch nicht mehr als 4-Byte-Stapelausrichtung.
x86-64 System V User-Space Funktion Aufrufkonvention:
x86-64 System V übergibt Argumente in Registern, was effizienter ist als die Stapelargument-Konvention von i386 System V. Es vermeidet die Latenz und zusätzliche Anweisungen, Argumente im Speicher (Cache) zu speichern und sie dann wieder in den Angerufenen zu laden. Dies funktioniert gut, da mehr Register verfügbar sind, und ist besser für moderne Hochleistungs-CPUs geeignet, bei denen Latenz und Ausführung außerhalb der Reihenfolge von Bedeutung sind. (Der i386 ABI ist sehr alt).
In diesem neuen Mechanismus: Zuerst werden die Parameter in Klassen unterteilt. Die Klasse jedes Parameters bestimmt, wie er an die aufgerufene Funktion übergeben wird.
Vollständige Informationen finden Sie unter: "3.2 Funktionsaufrufsequenz" des AMD64-Architekturprozessor-Supplements der System V-Anwendungsbinärschnittstelle, das teilweise lautet:
Sobald die Argumente klassifiziert sind, werden die Register (von links nach rechts) für die Übergabe wie folgt zugewiesen:
- Wenn die Klasse MEMORY ist, übergeben Sie das Argument auf dem Stapel.
- Wenn die Klasse INTEGER ist, wird das nächste verfügbare Register der Sequenz% rdi,% rsi,% rdx,% rcx,% r8 und% r9 verwendet
Dies %rdi, %rsi, %rdx, %rcx, %r8 and %r9
gilt auch für die Register , die verwendet werden, um Ganzzahl- / Zeigerparameter (dh die INTEGER-Klasse) von einer Assembly an eine beliebige libc-Funktion zu übergeben. % rdi wird für den ersten INTEGER-Parameter verwendet. % rsi für 2.,% rdx für 3. und so weiter. Dann call
sollte eine Anweisung gegeben werden. Der Stack ( %rsp
) muss bei der Ausführung 16B-ausgerichtet sein call
.
Wenn mehr als 6 INTEGER-Parameter vorhanden sind, werden der 7. INTEGER-Parameter und höher an den Stapel übergeben. (Anrufer knallt wie x86-32.)
Die ersten 8 Gleitkomma-Argumente werden später im Stapel in% xmm0-7 übergeben. Es gibt keine aufruferhaltenen Vektorregister. (Eine Funktion mit einer Mischung aus FP- und Integer-Argumenten kann insgesamt mehr als 8 Registerargumente enthalten.)
Variadische Funktionen ( wieprintf
) benötigen immer %al
= die Anzahl der FP-Registerargumente.
Es gibt Regeln, wann Strukturen in Register ( rdx:rax
bei Rückgabe) oder im Speicher gepackt werden sollen . Weitere Informationen finden Sie im ABI. Überprüfen Sie die Compilerausgabe, um sicherzustellen, dass Ihr Code mit den Compilern übereinstimmt, wie etwas übergeben / zurückgegeben werden soll.
Beachten Sie, dass die Windows x64-Funktionsaufrufkonvention mehrere signifikante Unterschiede zu x86-64 System V aufweist, z. B. Schattenbereich, der vom Aufrufer reserviert werden muss (anstelle einer roten Zone), und aufruferhaltenes xmm6-xmm15. Und ganz andere Regeln, für welche Argumente in welches Register gehen.