Adakah yang bisa menjelaskan fungsi kode assembly berikut ini?
int 0x80
Adakah yang bisa menjelaskan fungsi kode assembly berikut ini?
int 0x80
Jawaban:
Ini melewati kontrol untuk mengganggu vektor 0x80
Lihat http://en.wikipedia.org/wiki/Interrupt_vector
Di Linux, lihat ini : ini digunakan untuk menangani system_call
. Tentu saja di OS lain ini bisa berarti sesuatu yang sama sekali berbeda.
int 0x80
sebagai jenis khusus dari call
fungsi di kernel (dipilih oleh eax
).
int
berarti interupsi, dan nomor tersebut 0x80
adalah nomor interupsi. Interupsi mentransfer aliran program ke siapa pun yang menangani interupsi tersebut, yang 0x80
dalam kasus ini interupsi . Di Linux, 0x80
interrupt handler adalah kernel, dan digunakan untuk membuat panggilan sistem ke kernel oleh program lain.
Kernel diberitahu tentang pemanggilan sistem mana yang ingin dibuat oleh program, dengan memeriksa nilai dalam register %eax
(sintaks AT&T, dan EAX dalam sintaks Intel). Setiap panggilan sistem memiliki persyaratan berbeda tentang penggunaan register lainnya. Misalnya, nilai 1
in %eax
berarti pemanggilan sistem exit()
, dan nilai in %ebx
menyimpan nilai kode status untuk exit()
.
Ingatlah bahwa 0x80
= 80h
=128
Anda dapat melihat di sini bahwa INT
hanya salah satu dari banyak instruksi (sebenarnya representasi Bahasa Assembly (atau harus saya katakan 'mnemonic') darinya) yang ada di set instruksi x86. Anda juga dapat menemukan informasi lebih lanjut tentang instruksi ini di manual Intel yang ditemukan di sini .
Untuk meringkas dari PDF:
INT n / INTO / INT 3 — Prosedur Panggilan untuk Menyela
Instruksi INT n menghasilkan panggilan ke interupsi atau penangan pengecualian yang ditentukan dengan operan tujuan. Operand tujuan menentukan vektor dari 0 sampai 255, dikodekan sebagai nilai antara 8-bit unsigned. Instruksi INT n adalah mnemonik umum untuk menjalankan panggilan yang dihasilkan perangkat lunak ke pengendali interupsi.
Seperti yang Anda lihat, 0x80 adalah operan tujuan dalam pertanyaan Anda. Pada titik ini CPU mengetahui bahwa ia harus mengeksekusi beberapa kode yang ada di Kernel, tetapi kode apa? Itu ditentukan oleh Vektor Interupsi di Linux.
Salah satu interupsi perangkat lunak DOS yang paling berguna adalah interupsi 0x21. Dengan memanggilnya dengan parameter yang berbeda di register (kebanyakan ah dan al) Anda dapat mengakses berbagai operasi IO, keluaran string dan banyak lagi.
Sebagian besar sistem Unix dan turunannya tidak menggunakan interupsi perangkat lunak, dengan pengecualian interupsi 0x80, yang digunakan untuk melakukan panggilan sistem. Ini dilakukan dengan memasukkan nilai 32-bit yang sesuai dengan fungsi kernel ke dalam register EAX prosesor dan kemudian menjalankan INT 0x80.
Silakan lihat ini, di mana nilai lain yang tersedia di tabel penangan interupsi ditampilkan:
Seperti yang Anda lihat, tabel menunjukkan CPU untuk menjalankan panggilan sistem. Anda dapat menemukan tabel Panggilan Sistem Linux di sini .
Jadi dengan memindahkan nilai 0x1 ke register EAX dan memanggil INT 0x80 di program Anda, Anda dapat membuat proses pergi menjalankan kode di Kernel yang akan menghentikan (keluar) proses yang sedang berjalan (di Linux, x86 Intel CPU).
Interupsi perangkat keras tidak boleh disamakan dengan interupsi perangkat lunak. Inilah jawaban yang sangat bagus tentang hal ini.
Ini juga merupakan sumber yang bagus.
int 0x80
Linux i386 memanggil ABI sangat mirip dengan int 0x21
ABI DOS . Masukkan nomor panggilan di register (AH untuk DOS, EAX untuk Linux), dan arg lainnya di register lain, kemudian jalankan instruksi interupsi perangkat lunak. Perbedaan utama adalah pada apa yang diizinkan oleh system call (mengakses perangkat keras secara langsung di DOS tetapi tidak di Linux), bukan pada cara Anda memanggilnya.
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
Contoh panggilan sistem Linux minimal yang dapat dijalankan
Linux menyiapkan pengendali interupsi 0x80
sedemikian rupa sehingga ia mengimplementasikan panggilan sistem, sebuah cara bagi program-program userland untuk berkomunikasi dengan 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
Kompilasi dan jalankan dengan:
as -o main.o main.S
ld -o main.out main.o
./main.out
Hasil: program mencetak ke stdout:
hello world
dan keluar dengan bersih.
Anda tidak dapat mengatur penangan interupsi Anda sendiri langsung dari userland karena Anda hanya memiliki ring 3 dan Linux mencegah Anda melakukannya .
GitHub upstream . Diuji di Ubuntu 16.04.
Alternatif yang lebih baik
int 0x80
telah digantikan oleh alternatif yang lebih baik untuk melakukan panggilan sistem: pertama sysenter
, kemudian VDSO.
x86_64 memiliki instruksi barusyscall
.
Lihat juga: Apa yang lebih baik "int 0x80" atau "syscall"?
Contoh minimal 16-bit
Pertama pelajari cara membuat OS bootloader minimal dan menjalankannya di QEMU dan perangkat keras nyata seperti yang telah saya jelaskan di sini: https://stackoverflow.com/a/32483545/895245
Sekarang Anda dapat menjalankan mode real 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
Ini akan dilakukan secara berurutan:
Do 0.
Do 1.
hlt
: berhenti mengeksekusiPerhatikan bagaimana prosesor mencari penangan pertama di alamat 0
, dan yang kedua di 4
: itu adalah tabel penangan yang disebut IVT , dan setiap entri memiliki 4 byte.
Contoh minimal yang melakukan beberapa IO untuk membuat penangan terlihat.
Contoh mode perlindungan minimal
Sistem operasi modern berjalan dalam apa yang disebut mode terlindungi.
Penanganannya memiliki lebih banyak opsi dalam mode ini, jadi lebih kompleks, tetapi semangatnya sama.
Langkah kuncinya adalah menggunakan instruksi LGDT dan LIDT, yang menunjukkan alamat struktur data dalam memori (Tabel Descriptor Interupsi) yang menjelaskan penangan.
int 0x80 adalah instruksi bahasa assembly yang digunakan untuk memanggil panggilan sistem di Linux pada prosesor x86 (yaitu, kompatibel dengan Intel).
Instruksi "int" menyebabkan interupsi.
Jawaban Sederhana: Sebuah interupsi, sederhananya, adalah peristiwa yang mengganggu CPU, dan menyuruhnya untuk menjalankan tugas tertentu.
Jawaban Rinci :
CPU memiliki tabel Interrupt Service Routines (atau ISRs) yang disimpan di memori. Dalam Real Mode (16-bit), ini disimpan sebagai IVT , atau saya nterrupt V ektor T mampu. IVT biasanya terletak di 0x0000:0x0000
(alamat fisik 0x00000
), dan merupakan rangkaian alamat offset segmen yang mengarah ke ISR. OS dapat mengganti entri IVT yang sudah ada dengan ISR-nya sendiri.
(Catatan: Ukuran IVT ditetapkan pada 1024 (0x400) byte.)
Dalam Mode Terproteksi (32-bit), CPU menggunakan IDT. IDT adalah struktur dengan panjang variabel yang terdiri dari deskriptor (atau dikenal sebagai gerbang), yang memberi tahu CPU tentang penangan interupsi. Struktur deskriptor ini jauh lebih kompleks daripada entri offset segmen sederhana IVT; ini dia:
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
* IDT mungkin berukuran variabel, tetapi harus berurutan, yaitu jika Anda mendeklarasikan IDT Anda dari 0x00 hingga 0x50, Anda harus memiliki setiap interupsi dari 0x00 hingga 0x50. OS tidak selalu menggunakan semuanya, jadi bit Present memungkinkan CPU untuk menangani interupsi yang tidak ingin ditangani OS.
Ketika interupsi terjadi (baik oleh pemicu eksternal (misalnya perangkat keras) di IRQ, atau dengan int
instruksi dari program), CPU mendorong EFLAGS, lalu CS, dan kemudian EIP. (Ini secara otomatis dipulihkan oleh iret
, instruksi pengembalian interupsi.) OS biasanya menyimpan lebih banyak informasi tentang status mesin, menangani interupsi, memulihkan status mesin, dan melanjutkan.
Di banyak * NIX OS (termasuk Linux), panggilan sistem berbasis interupsi. Program ini menempatkan argumen ke panggilan sistem di register (EAX, EBX, ECX, EDX, dll ..), dan panggilan interupsi 0x80. Kernel telah menetapkan IDT untuk memuat penangan interupsi pada 0x80, yang dipanggil ketika menerima interupsi 0x80. Kernel kemudian membaca argumen dan menjalankan fungsi kernel yang sesuai. Ini mungkin menyimpan pengembalian dalam EAX / EBX. Panggilan sistem sebagian besar telah digantikan oleh sysenter
dan sysexit
(atau syscall
dansysret
instruksi pada AMD), yang memungkinkan untuk masuk lebih cepat ke ring 0.
Interupsi ini bisa memiliki arti berbeda di OS yang berbeda. Pastikan untuk memeriksa dokumentasinya.
eax
digunakan untuk nomor syscall. asm.sourceforge.net/intro/hello.html
Seperti disebutkan, itu menyebabkan kontrol melompat ke vektor interupsi 0x80. Dalam praktiknya, ini berarti (setidaknya di Linux) adalah bahwa panggilan sistem dipanggil; panggilan sistem dan argumen yang tepat ditentukan oleh konten register. Misalnya, exit () bisa dipanggil dengan menyetel% eax ke 1 diikuti dengan 'int 0x80'.
Ini memberitahu cpu untuk mengaktifkan vektor interupsi 0x80, yang pada OS Linux adalah interupsi panggilan sistem, digunakan untuk menjalankan fungsi sistem seperti open()
untuk file, dan sebagainya.
int tidak lain adalah gangguan yaitu prosesor akan menahan eksekusi saat ini.
0x80 tidak lain adalah panggilan sistem atau panggilan kernel. yaitu fungsi sistem akan dijalankan.
Untuk lebih spesifiknya 0x80 mewakili rt_sigtimedwait / init_module / restart_sys, itu bervariasi dari satu arsitektur ke arsitektur lainnya.
Untuk detail selengkapnya, lihat https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md