Que signifie «int 0x80» dans le code d'assemblage?


Réponses:


69

Il passe le contrôle pour interrompre le vecteur 0x80

Voir http://en.wikipedia.org/wiki/Interrupt_vector

Sur Linux, jetez un œil à ceci : il était utilisé pour gérer system_call. Bien sûr, sur un autre système d'exploitation, cela pourrait signifier quelque chose de totalement différent.


5
par raccourcir longue histoire, ce sont les instructions signifient DO IT for instruction était avant.
Yuda Prawira

2
@YudaPrawira: vous devriez considérer les instructions précédentes comme la configuration d'arguments dans les registres, et int 0x80comme une sorte spéciale de callfonction dans le noyau (sélectionnée par eax).
Peter Cordes

Pourquoi avez-vous dit "était utilisé?" N'est-il plus utilisé?
Liga

129

intsignifie interruption, et le nombre 0x80est le numéro d'interruption. Une interruption transfère le flux de programme à celui qui gère cette interruption, ce qui est une interruption 0x80dans ce cas. Sous Linux, le 0x80gestionnaire d'interruption 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 souhaite effectuer, en examinant la valeur dans le registre %eax(syntaxe AT&T et EAX dans la syntaxe Intel). Chaque appel système a des exigences différentes concernant l'utilisation des autres registres. Par exemple, une valeur de 1in %eaxsignifie un appel système de exit()et la valeur de %ebxcontient la valeur du code d'état pour exit().


47

Gardez à l'esprit que 0x80= 80h=128

Vous pouvez voir ici que ce INTn'est qu'une des nombreuses instructions (en fait la représentation en langage d'assemblage (ou devrais-je dire «mnémonique») de celui-ci) qui existe dans le jeu d'instructions x86. Vous pouvez également trouver plus d'informations sur cette instruction dans le manuel d'Intel disponible ici .

Pour résumer à partir du PDF:

INT n / INTO / INT 3 - Procédure d'appel pour interruption

L'instruction INT n génère un appel au gestionnaire d'interruption ou d'exception spécifié avec l'opérande de destination. L'opérande de destination spécifie un vecteur de 0 à 255, codé en tant que valeur intermédiaire non signée de 8 bits. L'instruction INT n est le mnémonique général pour exécuter un appel généré par logiciel à un gestionnaire d'interruption.

Comme vous pouvez le voir, 0x80 est l' opérande de destination dans votre question. À ce stade, le CPU sait qu'il doit exécuter du code qui réside dans le noyau, mais quel code? Cela est déterminé par le vecteur d'interruption sous 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 (principalement ah et al), vous pouvez accéder à diverses opérations d'E / S, à la sortie de chaîne et plus encore.

La plupart des systèmes Unix et dérivés n'utilisent pas d'interruptions logicielles, à l'exception de l'interruption 0x80, utilisée pour effectuer des appels système. Ceci est accompli en entrant une valeur de 32 bits correspondant à une fonction du noyau dans le registre EAX du processeur , puis en exécutant INT 0x80.

Jetez un œil à ceci s'il vous plaît où d'autres valeurs disponibles dans les tables de gestionnaire d'interruption sont affichées:

entrez la description de l'image ici

Comme vous pouvez le voir, le tableau indique à la CPU d'exécuter un appel système. Vous pouvez trouver le tableau des appels système Linux ici .

Ainsi, en déplaçant la valeur 0x1 vers le registre EAX et en appelant le INT 0x80 dans votre programme, vous pouvez faire en sorte que le processus exécute le code dans le noyau qui arrêtera (quittera) le processus en cours d'exécution (sous Linux, processeur Intel x86).

Une interruption matérielle ne doit pas être confondue avec une interruption logicielle. Voici une très bonne réponse à ce sujet.

C'est aussi une bonne source.


4
Le lien de la table des appels système Linux est rompu = \
Miguel Angelo

1
La plupart des systèmes Unix et dérivés n'utilisent pas d'interruptions logicielles (sauf int 0x80) semble être une façon étrange de le dire. L' int 0x80appel système ABI i386 Linux est extrêmement similaire à l' int 0x21ABI DOS . Mettez un numéro d'appel dans un registre (AH pour DOS, EAX pour Linux) et d'autres arguments dans d'autres registres, puis exécutez une instruction d'interruption de logiciel. La principale différence réside dans ce que les appels système vous permettent de faire (accéder directement au matériel sous DOS mais pas sous Linux), pas dans la façon dont vous les appelez.
Peter Cordes

Voici un lien de table syscall non rompu. syscalls.kernelgrok.com Développez-le simplement pour afficher tous les appels en haut.
ollien le

Lors de l'utilisation de Linux 64bits, vous pouvez voir l'appel système disponible à/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton

11

Exemple d'appel système Linux exécutable minimal

Linux configure le gestionnaire d'interruption pour 0x80qu'il implémente les appels système, un moyen pour les programmes utilisateur de communiquer avec le noyau.

.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

Compilez et exécutez avec:

as -o main.o main.S
ld -o main.out main.o
./main.out

Résultat: le programme imprime sur stdout:

hello world

et sort proprement.

Vous ne pouvez pas définir vos propres gestionnaires d'interruptions directement depuis le userland car vous n'avez que le ring 3 et Linux vous en empêche .

GitHub en amont . Testé sur Ubuntu 16.04.

Meilleures alternatives

int 0x80a été remplacé par de meilleures alternatives pour faire des appels système: d'abord sysenter, puis VDSO.

x86_64 a une nouvelle syscallinstruction .

Voir aussi: Qu'est-ce qui est mieux "int 0x80" ou "syscall"?

Exemple 16 bits minimal

Apprenez d'abord à créer un système d'exploitation de chargeur de démarrage 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

Vous pouvez maintenant exécuter en mode réel 16 bits:

    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

Cela ferait dans l'ordre:

  • Do 0.
  • Do 1.
  • hlt: arrêter l'exécution

Notez comment le processeur recherche le premier gestionnaire à l'adresse 0et le second à 4: c'est une table de gestionnaires appelée IVT , et chaque entrée a 4 octets.

Exemple minimal qui effectue des E / S pour rendre les gestionnaires visibles.

Exemple de mode protégé minimal

Les systèmes d'exploitation modernes fonctionnent en mode dit protégé.

La manipulation a plus d'options dans ce mode, donc c'est plus complexe, mais l'esprit est le même.

L'étape clé consiste à utiliser les instructions LGDT et LIDT, qui pointent l'adresse d'une structure de données en mémoire (le tableau des descripteurs d'interruption) qui décrit les gestionnaires.

Exemple minimal



4

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 processeur et lui dit d'exécuter une tâche spécifique.

Réponse détaillée :

L'UC a une table des routines de service d'interruption (ou ISR) stockées en mémoire. En réel (16 bits) mode, cela est stocké en tant que IVT , ou je nterrupt V ecteur T mesure. L'IVT est généralement situé à 0x0000:0x0000(adresse physique 0x00000), et c'est une série d'adresses de décalage de segment qui pointent vers les ISR. Le système d'exploitation peut remplacer les entrées IVT préexistantes par ses propres ISR.

(Remarque: la taille de l'IVT est fixée à 1024 (0x400) octets.)

En mode protégé (32 bits), la CPU utilise un IDT. L'IDT est une structure de longueur variable qui se compose de descripteurs (autrement appelés portes), qui indiquent au CPU les gestionnaires d'interruption. La structure de ces descripteurs est beaucoup plus complexe que les simples entrées de décalage de segment de l'IVT; C'est ici:

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'est-à-dire que si vous déclarez que votre IDT va 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 Présent permet au processeur 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 périphérique matériel) dans une IRQ, soit par l' intinstruction d'un programme), la CPU pousse EFLAGS, puis CS, puis EIP. (Ceux-ci sont automatiquement restaurés par iretl'instruction de retour d'interruption.) Le système d'exploitation stocke généralement plus d'informations sur l'état de la machine, gère l'interruption, restaure l'état de la machine et continue.

Dans de nombreux systèmes d'exploitation * NIX (y compris Linux), les appels système sont basés sur des interruptions. Le programme met les arguments de l'appel système dans les registres (EAX, EBX, ECX, EDX, etc.), et appelle l'interruption 0x80. Le noyau a déjà défini l'IDT pour qu'il contienne un gestionnaire d'interruption sur 0x80, qui est appelé lorsqu'il reçoit l'interruption 0x80. Le noyau lit ensuite les arguments et invoque une fonction de noyau en conséquence. Il peut stocker un retour dans EAX / EBX. Les appels système ont été largement remplacés par les instructions sysenteret sysexit(ou syscallet sysretsur AMD), qui permettent une entrée plus rapide dans l'anneau 0.

Cette interruption peut avoir une signification différente dans un autre système d'exploitation. Assurez-vous de vérifier sa documentation.


Fait amusant: l'appel système i386 de FreeBSD passe des arguments sur la pile d'espace utilisateur. Seul eaxest utilisé pour le numéro syscall. asm.sourceforge.net/intro/hello.html
Peter Cordes

2

Comme mentionné, cela fait sauter le contrôle pour interrompre le vecteur 0x80. En pratique, cela signifie (au moins sous Linux) qu'un appel système est appelé; l'appel système exact et les arguments sont définis par le contenu des registres. Par exemple, exit () peut être appelé en définissant% eax sur 1 suivi de «int 0x80».


1

Il indique au processeur d'activer le vecteur d'interruption 0x80, qui sur les OS Linux est l'interruption d'appel système, utilisée pour appeler des fonctions système comme open()pour les fichiers, et cetera.


9
Strictement parlant, il ne le dit pas au noyau ... Il en informe le CPU, qui recherche le gestionnaire dans l'IDT, qui finit par être un pointeur vers un code du noyau.
asveikau

Vrai. Je suppose que la meilleure formulation serait qu'elle indique au CPU d'activer le vecteur et que le vecteur (dans le cadre du noyau) invoque la fonction.
Ambre

qui finit par faire ceci, qui à son tour finit par faire cela, qui ensuite fait ceci, qui y va alors confus . : / Amber a une réponse compréhensible..c'est-ce que c'est ..
Afzaal Ahmad Zeeshan

1

int n'est rien d'autre qu'une interruption, c'est-à-dire que le processeur mettra son exécution en cours en attente.

0x80 n'est rien d'autre qu'un appel système ou un appel du noyau. c'est-à-dire que la fonction système sera exécutée.

Pour être précis, 0x80 représente rt_sigtimedwait / init_module / restart_sys, il varie d'une architecture à l'autre.

Pour plus de détails, consultez https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.