Question

Quelqu'un peut-il expliquer le rôle du code d'assemblage suivant?

 int 0x80  
Était-ce utile?

La solution

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

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

Sous Linux, consultez this : il a été utilisé pour gérer appel_système . Bien sûr, sur un autre système d’exploitation, cela pourrait signifier quelque chose de totalement différent.

Autres conseils

int signifie une interruption et le nombre 0x80 est le numéro de l'interruption. Une interruption transfère le flux de programme à la personne qui gère cette interruption, l’interruption 0x80 dans ce cas. Sous Linux, le gestionnaire d'interruption 0x80 est le noyau et est utilisé pour effectuer 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 gas et EAX en syntaxe Intel). Chaque appel système a des exigences différentes concernant 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 () .

N'oubliez pas que 0x80 = 80h = 128

Vous pouvez voir ici que INT est Une des nombreuses instructions (en fait, la représentation du langage d'assemblage (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, à l'adresse ici .

Pour résumer à partir du PDF:

  

INT n / INTO / INT 3 & # 8212; Procédure d'appel à une interruption

     

L'instruction INT n génère un appel à l'interruption ou à l'exception   gestionnaire spécifié avec l'opérande de destination. La destination   L'opérande spécifie un vecteur de 0 à 255, codé comme un signe non signé de 8 bits   valeur intermédiaire. L’instruction INT n est la mnémonique générale pour   exécution d'un appel généré par logiciel à un gestionnaire d'interruptions.

Comme vous pouvez le constater, 0x80 est l'opérande de destination dans votre question. À ce stade, la CPU sait qu'elle doit exécuter du code résidant dans le noyau, mais quel code? Cela est déterminé par le vecteur d'interruption sous Linux.

L’une des interruptions logicielles DOS les plus utiles a été 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’IO, à 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. Pour ce faire, entrez une valeur 32 bits correspondant à une fonction du noyau dans le registre EAX du processeur , puis exécutez INT 0x80.

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

entrer la description de l'image ici

Comme vous pouvez le voir sur le tableau, la CPU exécute un appel système. Vous pouvez trouver la table d'appel système Linux ici .

Donc, en déplaçant la valeur 0x1 dans le registre EAX et en appelant l'INT 0x80 dans votre programme, vous pouvez obliger le processus à exécuter le code dans le noyau qui arrêtera (quittera) le processus en cours d'exécution (sous Linux, x86 Intel CPU) .

Une interruption matérielle ne doit pas être confondue avec une interruption logicielle. Ici est très bonne réponse à cet égard.

Cette est également une bonne source.

Vous pouvez voir int 80h en action ici .

  

int 0x80 est le langage d'assemblage   instruction qui est utilisée pour invoquer   appels système sous Linux sur x86 (c.-à-d.,   Processeurs compatibles Intel).

http://www.linfo.org/int_0x80.html

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

Linux configure le gestionnaire d'interruption pour 0x80 de sorte qu'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 
as -o main.o main.S
ld -o main.out main.o
./main.out
x80 movl $1, %eax /* exit system call number */ movl
hello world
, %ebx /* exit status */ int
    movw $handler0, 0x00
    mov %cs, 0x02
    movw $handler1, 0x04
    mov %cs, 0x06
    int <*>
    int $1
    hlt
handler0:
    /* Do 0. */
    iret
handler1:
    /* Do 1. */
    iret
x80

Compiler et exécuter avec:

<*>

Résultat: le programme imprime sur la sortie standard:

<*>

et quitte proprement.

Vous ne pouvez pas définir vos propres gestionnaires d'interruptions directement à partir de l'utilisateur, car vous ne disposez que de anneau 3 et Linux vous en empêche .

syscall .

Voir aussi: Quoi de mieux & int; Int 0x80 " ou "syscall"

Exemple 16 bits minimal

Tout d'abord, apprenez à 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 le mode réel 16 bits:

<*>

Ceci ferait dans l'ordre:

  • Faites 0.
  • Faites 1.
  • hlt : arrêtez l'exécution

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

Exemple mortel pour ce qui est de votre santé > rendre visibles les gestionnaires.

Exemple de mode de protection minimale

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

La gestion 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 indiquent l'adresse d'une structure de données en mémoire (la table des descripteurs d'interruption) qui décrit les gestionnaires.

Minimal exemple

Le " int " instruction provoque une interruption.

Qu'est-ce qu'une interruption?

Réponse simple: Une interruption est un événement qui interrompt le processeur et lui indique d'exécuter une tâche spécifique.

Réponse détaillée :

La CPU dispose d’une table de routines de service d’interruption (ou ISR) stockée en mémoire. En mode réel (16 bits), il est stocké sous le nom IVT ou I en cas de rupture V , T . capable. L'IVT est généralement situé à 0x0000: 0x0000 (adresse physique 0x00000 ), et il s'agit d'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 composée de descripteurs (autrement appelés portes), qui renseignent la CPU sur les gestionnaires d'interruptions. La structure de ces descripteurs est beaucoup plus complexe que les simples entrées de décalage de segment de l'IVT; la voici:

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

* La taille de l’IDT peut être variable, mais elle doit être séquentielle: c’est-à-dire que si vous déclarez que votre IDT est compris entre 0x00 et 0x50, toutes les interruptions doivent être comprises entre 0x00 et 0x50. Le système d'exploitation ne les utilise pas nécessairement tous. Par conséquent, le bit Present 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'instruction int d'un programme), la CPU envoie EFLAGS, puis CS, puis EIP. (Celles-ci sont automatiquement restaurées par iret , l'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 place 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 une interruption 0x80. Le noyau lit ensuite les arguments et appelle une fonction du noyau en conséquence. Il peut stocker une déclaration dans EAX / EBX. Les appels système ont été en grande partie remplacés par les instructions sysenter et sysexit (ou syscall et sysret sur AMD), qui permettre une entrée plus rapide dans l'anneau 0.

Cette interruption pourrait avoir une signification différente dans un système d'exploitation différent. Assurez-vous de consulter sa documentation.

Comme mentionné, le contrôle saute au vecteur d’interruption 0x80. En pratique, cela signifie (du 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'.

Il indique au processeur d'activer le vecteur d'interruption 0x80, qui, sous les systèmes d'exploitation Linux, correspond à l'interruption d'appel système, utilisé pour appeler des fonctions système telles que open () pour les fichiers, etc.

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top