Que signifie "int 0x80" en code d'assemblage?
quelqu'un peut-il expliquer ce que fait le code d'assemblage suivant?
int 0x80
8 réponses
il passe le contrôle pour interrompre le vecteur 0x80
voir http://en.wikipedia.org/wiki/Interrupt_vector
sur Linux, jetez un oeil à ce : il a été utilisé pour gérer system_call
. Bien sûr sur un autre OS cela pourrait signifier quelque chose de totalement différent.
int
signifie interruption, et le nombre 0x80
est le nombre d'interruption.
Une interruption transfère le flux du programme à celui qui s'occupe de cette interruption, qui est l'interruption 0x80
dans ce cas.
Sous Linux ,le gestionnaire d'interruptions 0x80
est le noyau, et est utilisé pour faire des appels système au noyau par d'autres programmes.
le noyau est informé de l'appel système que le programme veut faire, en examinant la valeur dans le registre %eax
(syntaxe de gaz, et EAX dans la syntaxe Intel). Chaque appel système a des exigences différentes en ce qui concerne l'utilisation des autres registres. Par exemple , une valeur de 1
dans %eax
signifie un appel système de exit()
, et la valeur dans %ebx
contient la valeur du code d'État pour exit()
.
gardez à l'esprit que 0x80 = 80h =128
, Vous pouvez voir ici que INT est juste l'une des nombreuses instructions (en fait, la Langue de l'Assembly de la représentation (ou devrais-je dire "mnémonique')) qui existe dans le jeu d'instructions x86. Vous pouvez également trouver plus d'informations sur cette instruction dans le propre manuel D'Intel trouvé ici .
pour résumer à partir du PDF:
INT n/EN/INT 3-l'Appel à l'Interruption de la Procédure
l'instruction interne génère un appel à l'interruption ou à l'exception gestionnaire spécifié avec l'opérande de destination. Destination operand spécifie un vecteur de 0 à 255, encodé comme un 8-bit non signé des valeurs intermédiaires. L'instruction INT n est la mnémonique générale pour l'exécution d'un logiciel généré appel à un gestionnaire d'interruption.
As vous pouvez voir 0x80 est le opérande de destination dans votre question. À ce stade, le CPU sait qu'il doit exécuter un code qui réside dans le noyau, mais quel code? C'est déterminé par le vecteur D'interruption de Linux.
L'une des interruptions les plus utiles du logiciel DOS était l'interruption 0x21. En l'appelant avec différents paramètres dans les registres (surtout ah et al) vous pouvez accéder à diverses opérations IO, sortie de chaîne et de plus en plus.
la plupart des systèmes Unix et de leurs dérivés n'utilisent pas d'interruptions logicielles, à l'exception de l'interruption 0x80, utilisée pour faire des appels système. Ceci est accompli en entrant une valeur 32 bits correspondant à une fonction du noyau dans le registre EAX du processeur et en exécutant ensuite INT 0x80.
jetez un oeil à ceci s'il vous plaît où d'autres valeurs disponibles dans les tableaux du gestionnaire d'interruption sont indiquées:
comme vous pouvez le voir la table pointe le CPU pour exécuter un appel système. Vous pouvez trouver la table D'appel du système Linux ici .
ainsi, en déplaçant la valeur 0x1 à EAX register et en appelant L'INT 0x80 dans votre programme, vous pouvez faire que le processus exécute le code dans le noyau qui arrêtera (exit) le processus courant (sur Linux, x86 Intel CPU).
Une interruption matérielle ne doit pas être confondu avec une interruption logicielle. Ici est une très bonne réponse à cet égard.
ce est aussi une bonne source.
vous pouvez voir int 80h en action ici .
int 0x80 est la langue d'Assemblée instruction utilisée pour invoquer appels système sous Linux sur x86 (i.e., Compatible Intel) processeurs.
exemple D'appel Minimal du système Linux
Linux installe le gestionnaire d'interruption pour 0x80
de sorte qu'il implémente les appels système, une façon pour les programmes userland de communiquer avec le noyau.
.data
s:
.ascii "hello world\n"
len = . - s
.text
.global _start
_start:
movl , %eax /* write system call number */
movl , %ebx /* stdout */
movl $s, %ecx /* the data to print */
movl $len, %edx /* length of the buffer */
int "151900920"x80
movl , %eax /* exit system call number */
movl "151900920", %ebx /* exit status */
int "151900920"x80
compiler et exécuter avec:
as -o main.o main.S
ld -o main.out main.o
./main.out
résultat: le programme imprime à stdout:
hello world
et sort proprement.
vous ne pouvez pas configurer vos propres gestionnaires d'interruptions directement depuis userland car vous n'avez que ring 3 et Linux vous en empêche .
GitHub en amont . Testé sur Ubuntu 16.04.
meilleures alternatives
int 0x80
a été remplacé par de meilleures alternatives pour faire des appels système: d'abord sysenter
, puis VDSO.
x86_64 a "1519400920 une" nouvelle syscall
instruction .
Voir aussi: Quoi de mieux "int 0x80" ou "syscall"?
exemple Minimal de 16 bits
tout d'abord apprendre à créer un OS bootloader minimal et l'exécuter sur QEMU et du matériel réel comme je l'ai expliqué ici: https://stackoverflow.com/a/32483545/895245
Maintenant, vous pouvez exécuter en mode réel 16 bits:
movw $handler0, 0x00
mov %cs, 0x02
movw $handler1, 0x04
mov %cs, 0x06
int "151930920"
int
hlt
handler0:
/* Do 0. */
iret
handler1:
/* Do 1. */
iret
Ce serait faire dans l'ordre:
-
Do 0.
-
Do 1.
-
hlt
: arrêt de l'exécution
notez comment le processeur recherche le premier handler à l'adresse 0
, et le second à 4
: c'est une table de handlers appelée IVT , et chaque entrée a 4 octets.
exemple Minimal qui fait quelque IO pour rendre les manipulateurs visibles.
exemple de mode Minimal protégé
les systèmes D'exploitation modernes fonctionnent en mode protégé.
La manipulation a plus d'options dans ce mode, il est plus complexe, mais l'esprit est le même.
l'étape clé est d'utiliser les instructions LGDT et LIDT, qui pointent l'adresse d'une structure de données en mémoire (la Table des descripteurs D'interruption) qui décrit les gestionnaires.
l'instruction " int " provoque une interruption.
qu'est-ce qu'une interruption?
réponse Simple: une interruption, en termes simples, est un événement qui interrompt le CPU, et lui dit d'exécuter une tâche spécifique.
Réponse Détaillée :
le CPU a une table de Routines D'interruption de Service (ou ISRs) stockée en mémoire. En Mode Réel (16 bits), ceci est stocké comme le IVT , ou je nterrupt V ector T en mesure. L'IVT est typiquement situé à 0x0000:0x0000
(adresse physique 0x00000
), et il s'agit d'une série d'adresses segment-offset qui pointent vers les ISRs. L'OS peut remplacer les entrées IVT existantes par ses propres ISR.
(Note: la taille de L'IVT est fixée à 1024 (0x400) octets.)
dans protégé (32 bits) Mode, le CPU utilise un IDT. L'IDT est une structure de longueur variable qui se compose de descripteurs (autrement connu sous le nom de gates), qui informent le CPU au sujet des manipulateurs d'interruption. La structure de ces descripteurs est beaucoup plus complexe que les simples entrées segment-offset de L'IVT; ici il est:
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
*L'IDT peut être de taille variable, mais il doit être séquentiel, c.-à-d. Si vous déclarez que votre IDT est de 0x00 à 0x50, vous devez avoir chaque interruption de 0x00 à 0x50. Le système D'exploitation ne les utilise pas nécessairement tous, de sorte que le bit actuel permet au CPU de gérer correctement les interruptions que le système d'exploitation n'a pas l'intention de gérer.
Lorsqu'une interruption se produit (soit par un déclencheur externe (par exemple un dispositif matériel) dans un IRQ, soit par l'instruction int
d'un programme), le CPU pousse EFLAGS, puis CS, et puis EIP. (Ceux-ci sont automatiquement restaurés par iret
, l'instruction de retour d'interruption.) L'OS habituellement stocke plus d'informations sur l'état de la machine, gère l'interruption, rétablit l'état de la machine, et continue.
dans beaucoup de *Linux, les appels système sont basés sur des interruptions. Le programme place les arguments à l'appel système dans les registres (EAX, EBX, ECX, EDX, etc..), et les appels interrompent 0x80. Le noyau a déjà défini L'IDT pour contenir un gestionnaire d'interruption sur 0x80, qui est appelé quand il reçoit l'interruption 0x80. Le noyau lit alors le arguments et invoque une fonction du noyau en conséquence. Il peut stocker un retour dans EAX/EBX. Les appels de système ont été largement remplacés par les instructions sysenter
et sysexit
(ou syscall
et sysret
sur AMD), qui permettent une entrée plus rapide dans l'anneau 0.
cette interruption pourrait avoir un sens différent dans un OS différent. Assurez-vous de vérifier sa documentation.
comme mentionné, le contrôle saute pour interrompre le vecteur 0x80. En pratique, cela signifie (Du moins sous Linux) qu'un appel système est invoqué; l'appel système exact et les arguments sont définis par le contenu des registres. Par exemple, exit() peut être invoqué en définissant %eax à 1 suivi de 'int 0x80'.
il dit au cpu d'activer le vecteur d'interruption 0x80, qui sur Linux OSes est l'interruption d'appel système, utilisé pour invoquer des fonctions système comme open()
pour les fichiers, et cetera.