Qualcuno può spiegare cosa fa il seguente codice assembly?
int 0x80
Qualcuno può spiegare cosa fa il seguente codice assembly?
int 0x80
Risposte:
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.
int 0x80come un tipo speciale di calluna funzione nel kernel (selezionata da eax).
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().
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:

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.
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.
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
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'esecuzioneNota 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.
int 0x80 è l'istruzione in linguaggio assembly utilizzata per richiamare le chiamate di sistema in Linux su processori x86 (cioè compatibili con Intel).
L'istruzione "int" provoca un interrupt.
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.
eaxè utilizzato per il numero syscall. asm.sourceforge.net/intro/hello.html
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".
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.
int non è altro che un'interruzione, ovvero il processore sospenderà la sua esecuzione corrente.
0x80 non è altro che una chiamata di sistema o la chiamata del kernel. cioè la funzione di sistema verrà eseguita.
Per essere precisi 0x80 rappresenta rt_sigtimedwait / init_module / restart_sys e varia da architettura ad architettura.
Per maggiori dettagli, fare riferimento a https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md