Cosa significa "int 0x80" nel codice assembly?


Risposte:


69

Passa il controllo per interrompere il vettore 0x80

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

Su Linux, dai un'occhiata a questo : era usato per gestire system_call. Ovviamente su un altro sistema operativo questo potrebbe significare qualcosa di completamente diverso.


5
accorciare la storia lunga che le istruzioni significano che DO IT per l'istruzione era prima.
Yuda Prawira

2
@YudaPrawira: dovresti pensare alle istruzioni precedenti come impostare gli argomenti nei registri e int 0x80come un tipo speciale di calluna funzione nel kernel (selezionata da eax).
Peter Cordes

Perché hai detto "È stato usato?" Non viene più utilizzato?
Liga

129

intsignifica interruzione e il numero 0x80è il numero di interruzione. Un interrupt trasferisce il flusso del programma a chi gestisce quell'interruzione, che 0x80in questo caso è interruzione . In Linux, il 0x80gestore degli interrupt è il kernel e viene utilizzato per effettuare chiamate di sistema al kernel da altri programmi.

Il kernel viene informato su quale chiamata di sistema il programma vuole effettuare, esaminando il valore nel registro %eax(sintassi AT&T e EAX nella sintassi Intel). Ogni chiamata di sistema ha requisiti diversi sull'uso degli altri registri. Ad esempio, un valore di 1in %eaxindica una chiamata di sistema di exit()e il valore in %ebxcontiene il valore del codice di stato per exit().


47

Tieni presente che 0x80= 80h=128

Puoi vedere qui che INTè solo una delle tante istruzioni (in realtà la rappresentazione del linguaggio Assembly (o dovrei dire 'mnemonico') di essa) che esiste nel set di istruzioni x86. È inoltre possibile trovare ulteriori informazioni su questa istruzione nel manuale di Intel disponibile qui .

Per riassumere dal PDF:

INT n / INTO / INT 3 — Chiamata alla procedura di interruzione

L'istruzione INT n genera una chiamata al gestore di interrupt o eccezioni specificato con l'operando di destinazione. L'operando di destinazione specifica un vettore da 0 a 255, codificato come valore intermedio senza segno a 8 bit. L'istruzione INT n è lo mnemonico generale per eseguire una chiamata generata dal software a un gestore di interrupt.

Come puoi vedere 0x80 è l' operando di destinazione nella tua domanda. A questo punto la CPU sa che dovrebbe eseguire del codice che risiede nel Kernel, ma quale codice? Ciò è determinato dal vettore di interrupt in Linux.

Uno degli interrupt software DOS più utili è stato l'interrupt 0x21. Chiamandolo con diversi parametri nei registri (principalmente ah e al) è possibile accedere a varie operazioni di I / O, output di stringhe e altro.

La maggior parte dei sistemi e derivati ​​Unix non utilizza interrupt software, ad eccezione dell'interrupt 0x80, utilizzato per effettuare chiamate di sistema. Ciò si ottiene immettendo un valore a 32 bit corrispondente a una funzione del kernel nel registro EAX del processore e quindi eseguendo INT 0x80.

Dai un'occhiata a questo per favore dove sono mostrati altri valori disponibili nelle tabelle del gestore di interrupt:

inserisci qui la descrizione dell'immagine

Come puoi vedere la tabella indica alla CPU di eseguire una chiamata di sistema. Puoi trovare la tabella delle chiamate di sistema Linux qui .

Quindi spostando il valore 0x1 nel registro EAX e chiamando INT 0x80 nel tuo programma, puoi fare in modo che il processo esegua il codice nel kernel che interromperà (uscirà) il processo in esecuzione corrente (su Linux, CPU Intel x86).

Un interrupt hardware non deve essere confuso con un interrupt software. Ecco un'ottima risposta a questo proposito.

Anche questa è una buona fonte.


4
Il collegamento alla tabella delle chiamate di sistema Linux è interrotto = \
Miguel Angelo

1
La maggior parte dei sistemi e derivati ​​Unix non usano interrupt software (tranne int 0x80) sembra un modo strano per dirlo. La int 0x80chiamata di sistema di i386 Linux ABI è estremamente simile int 0x21all'ABI DOS . Metti un numero di chiamata in un registro (AH per DOS, EAX per Linux) e altri argomenti in altri registri, quindi esegui un'istruzione di interruzione del software. La differenza principale è in ciò che le chiamate di sistema ti consentono di fare (accedere all'hardware direttamente in DOS ma non in Linux), non nel modo in cui le invochi.
Peter Cordes

Ecco un collegamento alla tabella di syscall non interrotto. syscalls.kernelgrok.com Basta espanderlo per mostrare tutte le chiamate in alto.
ollien

Quando si usa Linux a 64 bit, è possibile vedere la chiamata di sistema disponibile a/usr/include/x86_64-linux-gnu/asm/unistd_64.h
ton

11

Esempio minimo di chiamata di sistema Linux eseguibile

Linux imposta il gestore degli interrupt in 0x80modo tale da implementare le chiamate di sistema, un modo per i programmi userland di comunicare con il kernel.

.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

Compila ed esegui con:

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

Risultato: il programma stampa su stdout:

hello world

ed esce in modo pulito.

Non puoi impostare i tuoi gestori di interrupt direttamente da userland perché hai solo l' anello 3 e Linux ti impedisce di farlo .

GitHub a monte . Testato su Ubuntu 16.04.

Alternative migliori

int 0x80è stato sostituito da migliori alternative per effettuare chiamate di sistema: prima sysenter, poi VDSO.

x86_64 ha una nuova syscallistruzione .

Vedi anche: Cosa è meglio "int 0x80" o "syscall"?

Esempio minimo a 16 bit

Per prima cosa impara come creare un sistema operativo bootloader minimo ed eseguirlo su QEMU e hardware reale come ho spiegato qui: https://stackoverflow.com/a/32483545/895245

Ora puoi eseguire in modalità reale a 16 bit:

    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

Questo farebbe in ordine:

  • Do 0.
  • Do 1.
  • hlt: interrompi l'esecuzione

Nota come il processore cerca il primo gestore all'indirizzo 0e il secondo all'indirizzo 4: questa è una tabella di gestori chiamata IVT e ogni voce ha 4 byte.

Esempio minimo che esegue operazioni di I / O per rendere visibili i gestori.

Esempio di modalità protetta minima

I sistemi operativi moderni funzionano nella cosiddetta modalità protetta.

La gestione ha più opzioni in questa modalità, quindi è più complessa, ma lo spirito è lo stesso.

Il passaggio chiave è l'utilizzo delle istruzioni LGDT e LIDT, che puntano all'indirizzo di una struttura di dati in memoria (la tabella descrittore degli interrupt) che descrive i gestori.

Esempio minimo



4

L'istruzione "int" provoca un interrupt.

Cos'è un'interruzione?

Risposta semplice: un interrupt, in parole povere, è un evento che interrompe la CPU e le dice di eseguire un'attività specifica.

Risposta dettagliata :

La CPU ha una tabella delle routine di servizio di interrupt (o ISR) archiviate in memoria. In reale (16 bit) Mode, questo viene memorizzato come IVT , o io nterrupt V ector T grado. L'IVT si trova in genere in 0x0000:0x0000(indirizzo fisico 0x00000) ed è una serie di indirizzi con offset di segmento che puntano agli ISR. Il sistema operativo può sostituire le voci IVT preesistenti con i propri ISR.

(Nota: la dimensione dell'IVT è fissata a 1024 (0x400) byte.)

In modalità protetta (32 bit), la CPU utilizza un IDT. L'IDT è una struttura a lunghezza variabile composta da descrittori (altrimenti noti come porte), che informano la CPU sui gestori di interrupt. La struttura di questi descrittori è molto più complessa delle semplici voci con offset di segmento dell'IVT; Ecco qui:

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 può essere di dimensione variabile, ma deve essere sequenziale, cioè se dichiari il tuo IDT da 0x00 a 0x50, devi avere ogni interrupt da 0x00 a 0x50. Il sistema operativo non li utilizza necessariamente tutti, quindi il bit Present consente alla CPU di gestire correttamente gli interrupt che il sistema operativo non intende gestire.

Quando si verifica un interrupt (da un trigger esterno (ad esempio un dispositivo hardware) in un IRQ, o da intun'istruzione da un programma), la CPU preme EFLAGS, quindi CS e infine EIP. (Questi vengono ripristinati automaticamente da iret, l'istruzione di ritorno dell'interrupt.) Il sistema operativo di solito memorizza più informazioni sullo stato della macchina, gestisce l'interrupt, ripristina lo stato della macchina e continua.

In molti sistemi operativi * NIX (incluso Linux), le chiamate di sistema sono basate su interrupt. Il programma inserisce gli argomenti della chiamata di sistema nei registri (EAX, EBX, ECX, EDX, ecc.) E chiama l'interrupt 0x80. Il kernel ha già impostato l'IDT per contenere un gestore di interrupt su 0x80, che viene chiamato quando riceve l'interrupt 0x80. Il kernel quindi legge gli argomenti e invoca una funzione del kernel di conseguenza. Può memorizzare un reso in EAX / EBX. Le chiamate di sistema sono state in gran parte sostituite dalle istruzioni sysentere sysexit(o syscalle sysretsu AMD), che consentono un accesso più rapido allo squillo 0.

Questo interrupt potrebbe avere un significato diverso in un sistema operativo diverso. Assicurati di controllare la sua documentazione.


Fatto divertente: la chiamata di sistema i386 di FreeBSD ABI passa gli argomenti nello stack dello spazio utente. Solo eaxè utilizzato per il numero syscall. asm.sourceforge.net/intro/hello.html
Peter Cordes

2

Come accennato, fa sì che il controllo salti per interrompere il vettore 0x80. In pratica, ciò significa (almeno sotto Linux) che viene invocata una chiamata di sistema; la chiamata di sistema e gli argomenti esatti sono definiti dal contenuto dei registri. Ad esempio, exit () può essere invocata impostando% eax su 1 seguito da "int 0x80".


1

Indica alla CPU di attivare il vettore di interrupt 0x80, che sui sistemi operativi Linux è l'interrupt della chiamata di sistema, utilizzato per invocare le funzioni di sistema come open()per i file, eccetera.


9
A rigor di termini, non lo dice al kernel ... Lo dice alla CPU, che cerca il gestore nell'IDT, che finisce per essere un puntatore a un codice del kernel.
asveikau

Vero. Suppongo che la frase migliore sarebbe che dice alla CPU di attivare il vettore, e il vettore (come parte del kernel) invoca la funzione.
Amber

che finisce per fare questo, che poi finisce per fare quello, che poi fa questo, che poi va lì confuso . : / Amber ha una risposta comprensibile..questa è ..
Afzaal Ahmad Zeeshan

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.