Unter Linux haben Sie einen Blick auf diese : es wurde verwendet , um handhaben system_call. Auf einem anderen Betriebssystem könnte dies natürlich etwas völlig anderes bedeuten.
durch verkürzen der langen Geschichte, die Anweisungen bedeutet, bedeutet, dass DO IT für Anweisungen vorher war.
Yuda Prawira
2
@YudaPrawira: Sie sollten sich die früheren Anweisungen als das Einrichten von Argumenten in Registern und int 0x80als eine besondere Art calleiner Funktion im Kernel vorstellen (ausgewählt von eax).
Peter Cordes
Warum hast du gesagt "Wurde benutzt?" Wird es nicht mehr verwendet?
Liga
124
intbedeutet Interrupt, und die Nummer 0x80ist die Interrupt-Nummer. Ein Interrupt überträgt den Programmablauf an denjenigen, der diesen Interrupt behandelt, 0x80in diesem Fall Interrupt . Unter Linux ist der 0x80Interrupt-Handler der Kernel und wird verwendet, um Systemaufrufe des Kernels durch andere Programme durchzuführen.
Der Kernel wird benachrichtigt, welchen Systemaufruf das Programm ausführen möchte, indem der Wert im Register %eaxüberprüft wird (AT & T-Syntax und EAX in Intel-Syntax). Jeder Systemaufruf hat unterschiedliche Anforderungen an die Verwendung der anderen Register. Zum Beispiel ein Wert von 1in%eax einen Systemaufruf von exit(), und der Wert in %ebxenthält den Wert des Statuscodes für exit().
Sie können hier sehen , dass dies INTnur eine der vielen Anweisungen (tatsächlich die Assembler-Darstellung (oder sollte ich 'mnemonisch' sagen)) ist, die im x86-Befehlssatz vorhanden sind. Weitere Informationen zu dieser Anleitung finden Sie auch in Intels eigenem Handbuch hier .
Um aus dem PDF zusammenzufassen:
INT n / INTO / INT 3 - Aufruf zum Unterbrechen der Prozedur
Der Befehl INT n generiert einen Aufruf an den mit dem Zieloperanden angegebenen Interrupt- oder Exception-Handler. Der Zieloperand gibt einen Vektor von 0 bis 255 an, der als vorzeichenloser 8-Bit-Zwischenwert codiert ist. Der Befehl INT n ist die allgemeine Mnemonik zum Ausführen eines durch Software generierten Aufrufs an einen Interrupt-Handler.
Wie Sie sehen können, ist 0x80 der Zieloperand in Ihrer Frage. Zu diesem Zeitpunkt weiß die CPU, dass sie Code ausführen sollte, der sich im Kernel befindet, aber welcher Code? Dies wird durch den Interrupt-Vektor unter Linux bestimmt.
Einer der nützlichsten DOS-Software-Interrupts war Interrupt 0x21. Durch Aufrufen mit verschiedenen Parametern in den Registern (meistens ah und al) können Sie auf verschiedene E / A-Operationen, Zeichenfolgenausgabe und mehr zugreifen.
Die meisten Unix-Systeme und -Derivate verwenden keine Software-Interrupts, mit Ausnahme des Interrupts 0x80, der zum Tätigen von Systemaufrufen verwendet wird. Dies wird erreicht, indem ein 32-Bit-Wert, der einer Kernelfunktion entspricht, in das EAX-Register des Prozessors eingegeben und dann INT 0x80 ausgeführt wird.
Schauen Sie sich dies bitte an, wo andere verfügbare Werte in den Interrupt-Handler-Tabellen angezeigt werden:
Wie Sie in der Tabelle sehen können, weist die CPU darauf hin, einen Systemaufruf auszuführen. Die Linux System Call-Tabelle finden Sie hier .
Wenn Sie also den Wert 0x1 in das EAX-Register verschieben und INT 0x80 in Ihrem Programm aufrufen, können Sie den Prozess veranlassen, den Code im Kernel auszuführen, der den aktuell ausgeführten Prozess stoppt (beendet) (unter Linux, x86 Intel-CPU).
Ein Hardware-Interrupt darf nicht mit einem Software-Interrupt verwechselt werden. Hier ist eine sehr gute Antwort in dieser Hinsicht.
Die meisten Unix-Systeme und -Derivate verwenden keine Software-Interrupts (außer int 0x80). Dies scheint eine seltsame Art zu sein. Der int 0x80i386 Linux-Systemaufruf ABI ist dem DOS int 0x21ABI sehr ähnlich . Fügen Sie eine Rufnummer in ein Register (AH für DOS, EAX für Linux) und andere Argumente in andere Register ein und führen Sie dann eine Software-Interrupt-Anweisung aus. Der Hauptunterschied besteht darin, was Sie mit den Systemaufrufen tun können (Zugriff auf Hardware direkt unter DOS, jedoch nicht unter Linux) und nicht darauf, wie Sie sie aufrufen.
Peter Cordes
Hier ist ein nicht unterbrochener Syscall-Tabellenlink. syscalls.kernelgrok.com Erweitern Sie es einfach, um alle Anrufe oben anzuzeigen .
ollien
11
Beispiel für einen minimal ausführbaren Linux-Systemaufruf
Linux richtet den Interrupt-Handler 0x80so ein, dass er Systemaufrufe implementiert, sodass Userland-Programme mit dem Kernel kommunizieren können.
.data
s:
.ascii "hello world\n"
len = . - s
.text
.global _start
_start:
movl $4, %eax /* write system call number */
movl $1, %ebx /* stdout */
movl $s, %ecx /* the data to print */
movl $len, %edx /* length of the buffer */
int $0x80
movl $1, %eax /* exit system call number */
movl $0, %ebx /* exit status */
int $0x80
Kompilieren und ausführen mit:
as -o main.o main.S
ld -o main.out main.o
./main.out
Erfahren Sie zunächst, wie Sie ein minimales Bootloader-Betriebssystem erstellen und auf QEMU und realer Hardware ausführen, wie hier erläutert: https://stackoverflow.com/a/32483545/895245
Jetzt können Sie im 16-Bit-Real-Modus arbeiten:
movw $handler0, 0x00
mov %cs, 0x02
movw $handler1, 0x04
mov %cs, 0x06
int $0
int $1
hlt
handler0:
/* Do 0. */
iret
handler1:
/* Do 1. */
iret
Dies würde in der Reihenfolge tun:
Do 0.
Do 1.
hlt: Stoppen Sie die Ausführung
Beachten Sie, wie der Prozessor nach dem ersten Handler an der Adresse 0und dem zweiten unter der Adresse sucht 4: Dies ist eine Tabelle von Handlern, die als IVT bezeichnet wird , und jeder Eintrag hat 4 Bytes.
Moderne Betriebssysteme laufen im sogenannten geschützten Modus.
Das Handling hat in diesem Modus mehr Optionen, ist also komplexer, aber der Geist ist der gleiche.
Der Schlüsselschritt ist die Verwendung der LGDT- und LIDT-Anweisungen, die auf die Adresse einer speicherinternen Datenstruktur (Interrupt Descriptor Table) verweisen, die die Handler beschreibt.
Einfache Antwort: Ein Interrupt ist einfach ausgedrückt ein Ereignis, das die CPU unterbricht und sie anweist, eine bestimmte Aufgabe auszuführen.
Detaillierte Antwort :
In der CPU ist eine Tabelle mit Interrupt Service Routines (oder ISRs) gespeichert. Im Real (16-Bit) -Modus wird dies als IVT gespeichert , oder ich nterrupt V ector T können. Das IVT befindet sich normalerweise unter 0x0000:0x0000(physikalische Adresse 0x00000) und besteht aus einer Reihe von Segmentversatzadressen, die auf die ISRs verweisen. Das Betriebssystem kann die bereits vorhandenen IVT-Einträge durch eigene ISRs ersetzen.
(Hinweis: Die Größe des IVT ist auf 1024 (0x400) Byte festgelegt.)
Im geschützten (32-Bit) Modus verwendet die CPU eine IDT. Das IDT ist eine Struktur variabler Länge, die aus Deskriptoren (auch als Gates bezeichnet) besteht, die die CPU über die Interrupt-Handler informieren. Die Struktur dieser Deskriptoren ist viel komplexer als die einfachen Segmentversatzeinträge des IVT. hier ist es:
bytes 0, 1: Lower 16 bits of the ISR's address.
bytes 2, 3: A code segment selector (in the GDT/LDT)
byte 4: Zero.
byte 5: A type field consisting of several bitfields.
bit 0: P (Present): 0 for unused interrupts, 1 for used interrupts.*
bits 1, 2: DPL (Descriptor Privilege Level): The privilege level the descriptor (bytes 2, 3) must have.
bit 3: S (Storage Segment): Is 0 for interrupt and trap gates. Otherwise, is one.
bits 4, 5, 6, 7: GateType:
0101: 32 bit task gate
0110: 16-bit interrupt gate
0111: 16-bit trap gate
1110: 32-bit interrupt gate
1111: 32-bit trap gate
* Die IDT kann eine variable Größe haben, muss jedoch sequentiell sein. Wenn Sie also angeben, dass Ihre IDT zwischen 0x00 und 0x50 liegt, muss jeder Interrupt zwischen 0x00 und 0x50 liegen. Das Betriebssystem verwendet nicht unbedingt alle, daher ermöglicht das Present-Bit der CPU, Interrupts, die das Betriebssystem nicht verarbeiten möchte, ordnungsgemäß zu behandeln.
Wenn ein Interrupt auftritt (entweder durch einen externen Trigger (z. B. ein Hardwaregerät) in einem IRQ oder durch die intAnweisung eines Programms), drückt die CPU EFLAGS, dann CS und dann EIP. (Diese werden automatisch von wiederhergestelltiret die Interrupt-Rückgabeanweisung .) Das Betriebssystem speichert normalerweise mehr Informationen über den Status der Maschine, behandelt den Interrupt, stellt den Maschinenzustand wieder her und fährt fort.
In vielen * NIX-Betriebssystemen (einschließlich Linux) basieren Systemaufrufe auf Interrupts. Das Programm legt die Argumente für den Systemaufruf in den Registern (EAX, EBX, ECX, EDX usw.) ab und ruft den Interrupt 0x80 auf. Der Kernel hat das IDT bereits so eingestellt, dass es einen Interrupt-Handler auf 0x80 enthält, der aufgerufen wird, wenn er den Interrupt 0x80 empfängt. Der Kernel liest dann die Argumente und ruft entsprechend eine Kernelfunktion auf. Möglicherweise wird eine Rückgabe in EAX / EBX gespeichert. Systemaufrufe wurden weitgehend durch sysenterund ersetztsysexit (oder syscallund ersetztsysret Anweisungen auf AMD) ersetzt, die einen schnelleren Eintritt in Ring 0 ermöglichen.
Dieser Interrupt kann in einem anderen Betriebssystem eine andere Bedeutung haben. Überprüfen Sie unbedingt die Dokumentation.
Unterhaltsame Tatsache: FreeBSDs i386-Systemaufruf ABI übergibt Argumente auf dem User-Space-Stack. Nur eaxwird für die Syscall-Nummer verwendet. asm.sourceforge.net/intro/hello.html
Peter Cordes
2
Wie bereits erwähnt, springt die Steuerung zum Interruptvektor 0x80. In der Praxis bedeutet dies (zumindest unter Linux), dass ein Systemaufruf aufgerufen wird. Der genaue Systemaufruf und die Argumente werden durch den Inhalt der Register definiert. Zum Beispiel kann exit () aufgerufen werden, indem% eax auf 1 gefolgt von 'int 0x80' gesetzt wird.
Es weist die CPU an, den Interrupt-Vektor 0x80 zu aktivieren, der unter Linux-Betriebssystemen der Systemaufruf-Interrupt ist, der zum Aufrufen von Systemfunktionen wie open()für Dateien usw. verwendet wird.
Genau genommen sagt es dem Kernel nichts ... Es sagt der CPU, die den Handler in der IDT nachschlägt, was letztendlich ein Zeiger auf einen Kernel-Code ist.
Asveikau
Wahr. Ich nehme an, die bessere Formulierung wäre, wenn die CPU angewiesen wird, den Vektor zu aktivieren, und der Vektor (als Teil des Kernels) die Funktion aufruft.
Amber
was am Ende das tut, was am Ende das tut, was dann das tut, was dann verwirrt dorthin geht . : / Amber hat eine Antwort, die verständlich ist .. das ist es ..
Antworten:
Es übergibt die Steuerung an den Interruptvektor 0x80
Sehen http://en.wikipedia.org/wiki/Interrupt_vector
Unter Linux haben Sie einen Blick auf diese : es wurde verwendet , um handhaben
system_call
. Auf einem anderen Betriebssystem könnte dies natürlich etwas völlig anderes bedeuten.quelle
int 0x80
als eine besondere Artcall
einer Funktion im Kernel vorstellen (ausgewählt voneax
).int
bedeutet Interrupt, und die Nummer0x80
ist die Interrupt-Nummer. Ein Interrupt überträgt den Programmablauf an denjenigen, der diesen Interrupt behandelt,0x80
in diesem Fall Interrupt . Unter Linux ist der0x80
Interrupt-Handler der Kernel und wird verwendet, um Systemaufrufe des Kernels durch andere Programme durchzuführen.Der Kernel wird benachrichtigt, welchen Systemaufruf das Programm ausführen möchte, indem der Wert im Register
%eax
überprüft wird (AT & T-Syntax und EAX in Intel-Syntax). Jeder Systemaufruf hat unterschiedliche Anforderungen an die Verwendung der anderen Register. Zum Beispiel ein Wert von1
in%eax
einen Systemaufruf vonexit()
, und der Wert in%ebx
enthält den Wert des Statuscodes fürexit()
.quelle
Denken Sie daran, dass
0x80
=80h
=128
Sie können hier sehen , dass dies
INT
nur eine der vielen Anweisungen (tatsächlich die Assembler-Darstellung (oder sollte ich 'mnemonisch' sagen)) ist, die im x86-Befehlssatz vorhanden sind. Weitere Informationen zu dieser Anleitung finden Sie auch in Intels eigenem Handbuch hier .Um aus dem PDF zusammenzufassen:
Wie Sie sehen können, ist 0x80 der Zieloperand in Ihrer Frage. Zu diesem Zeitpunkt weiß die CPU, dass sie Code ausführen sollte, der sich im Kernel befindet, aber welcher Code? Dies wird durch den Interrupt-Vektor unter Linux bestimmt.
Einer der nützlichsten DOS-Software-Interrupts war Interrupt 0x21. Durch Aufrufen mit verschiedenen Parametern in den Registern (meistens ah und al) können Sie auf verschiedene E / A-Operationen, Zeichenfolgenausgabe und mehr zugreifen.
Die meisten Unix-Systeme und -Derivate verwenden keine Software-Interrupts, mit Ausnahme des Interrupts 0x80, der zum Tätigen von Systemaufrufen verwendet wird. Dies wird erreicht, indem ein 32-Bit-Wert, der einer Kernelfunktion entspricht, in das EAX-Register des Prozessors eingegeben und dann INT 0x80 ausgeführt wird.
Schauen Sie sich dies bitte an, wo andere verfügbare Werte in den Interrupt-Handler-Tabellen angezeigt werden:
Wie Sie in der Tabelle sehen können, weist die CPU darauf hin, einen Systemaufruf auszuführen. Die Linux System Call-Tabelle finden Sie hier .
Wenn Sie also den Wert 0x1 in das EAX-Register verschieben und INT 0x80 in Ihrem Programm aufrufen, können Sie den Prozess veranlassen, den Code im Kernel auszuführen, der den aktuell ausgeführten Prozess stoppt (beendet) (unter Linux, x86 Intel-CPU).
Ein Hardware-Interrupt darf nicht mit einem Software-Interrupt verwechselt werden. Hier ist eine sehr gute Antwort in dieser Hinsicht.
Dies ist auch eine gute Quelle.
quelle
int 0x80
i386 Linux-Systemaufruf ABI ist dem DOSint 0x21
ABI sehr ähnlich . Fügen Sie eine Rufnummer in ein Register (AH für DOS, EAX für Linux) und andere Argumente in andere Register ein und führen Sie dann eine Software-Interrupt-Anweisung aus. Der Hauptunterschied besteht darin, was Sie mit den Systemaufrufen tun können (Zugriff auf Hardware direkt unter DOS, jedoch nicht unter Linux) und nicht darauf, wie Sie sie aufrufen.Beispiel für einen minimal ausführbaren Linux-Systemaufruf
Linux richtet den Interrupt-Handler
0x80
so ein, dass er Systemaufrufe implementiert, sodass Userland-Programme mit dem Kernel kommunizieren können.Kompilieren und ausführen mit:
Ergebnis: Das Programm druckt auf stdout:
und geht sauber aus.
Sie können Ihre eigenen Interrupt-Handler nicht direkt vom Benutzerland aus festlegen, da Sie nur Ring 3 haben und Linux Sie daran hindert .
GitHub stromaufwärts . Getestet unter Ubuntu 16.04.
Bessere Alternativen
int 0x80
wurde durch bessere Alternativen für Systemaufrufe abgelöst: zuerstsysenter
VDSO.x86_64 hat eine neue
syscall
Anweisung .Siehe auch: Was ist besser "int 0x80" oder "syscall"?
Minimales 16-Bit-Beispiel
Erfahren Sie zunächst, wie Sie ein minimales Bootloader-Betriebssystem erstellen und auf QEMU und realer Hardware ausführen, wie hier erläutert: https://stackoverflow.com/a/32483545/895245
Jetzt können Sie im 16-Bit-Real-Modus arbeiten:
Dies würde in der Reihenfolge tun:
Do 0.
Do 1.
hlt
: Stoppen Sie die AusführungBeachten Sie, wie der Prozessor nach dem ersten Handler an der Adresse
0
und dem zweiten unter der Adresse sucht4
: Dies ist eine Tabelle von Handlern, die als IVT bezeichnet wird , und jeder Eintrag hat 4 Bytes.Minimales Beispiel, das einige E / A- Vorgänge ausführt , um Handler sichtbar zu machen.
Beispiel für einen minimalen geschützten Modus
Moderne Betriebssysteme laufen im sogenannten geschützten Modus.
Das Handling hat in diesem Modus mehr Optionen, ist also komplexer, aber der Geist ist der gleiche.
Der Schlüsselschritt ist die Verwendung der LGDT- und LIDT-Anweisungen, die auf die Adresse einer speicherinternen Datenstruktur (Interrupt Descriptor Table) verweisen, die die Handler beschreibt.
Minimales Beispiel
quelle
http://www.linfo.org/int_0x80.html
quelle
Der Befehl "int" verursacht einen Interrupt.
Was ist eine Unterbrechung?
Einfache Antwort: Ein Interrupt ist einfach ausgedrückt ein Ereignis, das die CPU unterbricht und sie anweist, eine bestimmte Aufgabe auszuführen.
Detaillierte Antwort :
In der CPU ist eine Tabelle mit Interrupt Service Routines (oder ISRs) gespeichert. Im Real (16-Bit) -Modus wird dies als IVT gespeichert , oder ich nterrupt V ector T können. Das IVT befindet sich normalerweise unter
0x0000:0x0000
(physikalische Adresse0x00000
) und besteht aus einer Reihe von Segmentversatzadressen, die auf die ISRs verweisen. Das Betriebssystem kann die bereits vorhandenen IVT-Einträge durch eigene ISRs ersetzen.(Hinweis: Die Größe des IVT ist auf 1024 (0x400) Byte festgelegt.)
Im geschützten (32-Bit) Modus verwendet die CPU eine IDT. Das IDT ist eine Struktur variabler Länge, die aus Deskriptoren (auch als Gates bezeichnet) besteht, die die CPU über die Interrupt-Handler informieren. Die Struktur dieser Deskriptoren ist viel komplexer als die einfachen Segmentversatzeinträge des IVT. hier ist es:
* Die IDT kann eine variable Größe haben, muss jedoch sequentiell sein. Wenn Sie also angeben, dass Ihre IDT zwischen 0x00 und 0x50 liegt, muss jeder Interrupt zwischen 0x00 und 0x50 liegen. Das Betriebssystem verwendet nicht unbedingt alle, daher ermöglicht das Present-Bit der CPU, Interrupts, die das Betriebssystem nicht verarbeiten möchte, ordnungsgemäß zu behandeln.
Wenn ein Interrupt auftritt (entweder durch einen externen Trigger (z. B. ein Hardwaregerät) in einem IRQ oder durch die
int
Anweisung eines Programms), drückt die CPU EFLAGS, dann CS und dann EIP. (Diese werden automatisch von wiederhergestelltiret
die Interrupt-Rückgabeanweisung .) Das Betriebssystem speichert normalerweise mehr Informationen über den Status der Maschine, behandelt den Interrupt, stellt den Maschinenzustand wieder her und fährt fort.In vielen * NIX-Betriebssystemen (einschließlich Linux) basieren Systemaufrufe auf Interrupts. Das Programm legt die Argumente für den Systemaufruf in den Registern (EAX, EBX, ECX, EDX usw.) ab und ruft den Interrupt 0x80 auf. Der Kernel hat das IDT bereits so eingestellt, dass es einen Interrupt-Handler auf 0x80 enthält, der aufgerufen wird, wenn er den Interrupt 0x80 empfängt. Der Kernel liest dann die Argumente und ruft entsprechend eine Kernelfunktion auf. Möglicherweise wird eine Rückgabe in EAX / EBX gespeichert. Systemaufrufe wurden weitgehend durch
sysenter
und ersetztsysexit
(odersyscall
und ersetztsysret
Anweisungen auf AMD) ersetzt, die einen schnelleren Eintritt in Ring 0 ermöglichen.Dieser Interrupt kann in einem anderen Betriebssystem eine andere Bedeutung haben. Überprüfen Sie unbedingt die Dokumentation.
quelle
eax
wird für die Syscall-Nummer verwendet. asm.sourceforge.net/intro/hello.htmlWie bereits erwähnt, springt die Steuerung zum Interruptvektor 0x80. In der Praxis bedeutet dies (zumindest unter Linux), dass ein Systemaufruf aufgerufen wird. Der genaue Systemaufruf und die Argumente werden durch den Inhalt der Register definiert. Zum Beispiel kann exit () aufgerufen werden, indem% eax auf 1 gefolgt von 'int 0x80' gesetzt wird.
quelle
Es weist die CPU an, den Interrupt-Vektor 0x80 zu aktivieren, der unter Linux-Betriebssystemen der Systemaufruf-Interrupt ist, der zum Aufrufen von Systemfunktionen wie
open()
für Dateien usw. verwendet wird.quelle