Birisi aşağıdaki montaj kodunun ne yaptığını açıklayabilir mi?
int 0x80
Birisi aşağıdaki montaj kodunun ne yaptığını açıklayabilir mi?
int 0x80
Yanıtlar:
0x80 vektörünü kesmek için kontrolden geçer
Bkz. Http://en.wikipedia.org/wiki/Interrupt_vector
Linux'ta, bir göz bu : o işlemek için kullanıldı system_call
. Elbette başka bir işletim sisteminde bu tamamen farklı bir anlama gelebilir.
int 0x80
özel bir türü olarak düşünmelisiniz . call
eax
int
kesme anlamına gelir ve sayı 0x80
, kesme numarasıdır. Bir kesme, program akışını bu kesmeyi işleyen kişiye aktarır, 0x80
bu durumda bu kesintidir . Linux'ta, 0x80
kesme işleyicisi çekirdektir ve diğer programlar tarafından çekirdeğe sistem çağrıları yapmak için kullanılır.
Çekirdek, kayıttaki değer incelenerek programın hangi sistem çağrısını yapmak istediği konusunda bilgilendirilir %eax
(AT&T sözdizimi ve Intel sözdiziminde EAX). Her sistem çağrısının diğer kayıtların kullanımıyla ilgili farklı gereksinimleri vardır. Örneğin, 1
in değeri %eax
bir sistem çağrısı anlamına gelir exit()
ve içindeki değer %ebx
için durum kodunun değerini tutar exit()
.
Unutmayın 0x80
= 80h
=128
Burada bunun INT
x86 komut setinde bulunan birçok talimattan (aslında Assembly Dili gösterimi (veya 'anımsatıcı' demeliyim)) sadece biri olduğunu görebilirsiniz . Bu talimat hakkında daha fazla bilgiyi burada bulunan Intel'in kendi kılavuzunda da bulabilirsiniz .
PDF'den özetlemek için:
INT n / INTO / INT 3 - İşlemi Kesmek İçin Çağrı
INT n komutu, hedef işlenen ile belirtilen kesme veya istisna işleyicisine bir çağrı üretir. Hedef işlenen, 8 bitlik işaretsiz ara değer olarak kodlanmış, 0 ile 255 arasında bir vektör belirtir. INT n komutu, bir kesme işleyicisine yazılım tarafından üretilen bir çağrıyı yürütmek için genel bir anımsatıcıdır.
Gördüğünüz gibi 0x80 , hedef işlenen sorunuzdaki . Bu noktada CPU, Çekirdekte bulunan bazı kodları yürütmesi gerektiğini bilir, ancak hangi kod? Bu, Linux'taki Kesme Vektörü tarafından belirlenir.
En kullanışlı DOS yazılım kesintilerinden biri 0x21 kesintisiydi. Kayıtlarda (çoğunlukla ah ve al) farklı parametrelerle çağırarak çeşitli IO işlemlerine, dizgi çıkışına ve daha fazlasına erişebilirsiniz.
Çoğu Unix sistemi ve türevi, sistem çağrıları yapmak için kullanılan 0x80 kesintisi dışında yazılım kesintilerini kullanmaz. Bu, işlemcinin EAX yazmacına bir çekirdek işlevine karşılık gelen 32 bitlik bir değer girilerek ve ardından INT 0x80 çalıştırılarak gerçekleştirilir.
Lütfen kesme işleyici tablolarındaki diğer mevcut değerlerin gösterildiği şuna bir göz atın:
Gördüğünüz gibi, tablo CPU'nun bir sistem çağrısı yürütmesini işaret ediyor. Linux Sistem Çağrısı tablosunu burada bulabilirsiniz .
Bu nedenle, 0x1 değerini EAX kaydına taşıyarak ve programınızda INT 0x80'i çağırarak, sürecin devam eden kodu Çekirdekte yürütmesini sağlayabilirsiniz, bu da geçerli çalışan işlemi durdurur (Linux'ta, x86 Intel CPU'da).
Bir donanım kesintisi, bir yazılım kesintisi ile karıştırılmamalıdır. Buraya bu konuda çok güzel bir cevap.
Bu da iyi bir kaynaktır.
int 0x80
İ386 Linux sistem çağrısı ABI DOS son derece benzerdir int 0x21
ABI. Bir kayda bir çağrı numarası (DOS için AH, Linux için EAX) ve diğer kayıtlara diğer argümanlar koyun, ardından bir yazılım kesme talimatı çalıştırın. Temel fark, sistem çağrılarının size nasıl izin verdiğidir (donanıma doğrudan DOS'ta erişir, ancak Linux'ta değil), onları nasıl çağırdığınızla değil.
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
Minimum çalıştırılabilir Linux sistem çağrısı örneği
Linux 0x80
, kullanıcı alanındaki programların çekirdekle iletişim kurması için bir yol olan sistem çağrılarını uygulayacak şekilde kesme işleyicisini ayarlar .
.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
Aşağıdakilerle derleyin ve çalıştırın:
as -o main.o main.S
ld -o main.out main.o
./main.out
Sonuç: program stdout'a yazdırır:
hello world
ve temiz bir şekilde çıkar.
Kendi kesme işleyicilerinizi doğrudan kullanıcı bölgesinden ayarlayamazsınız çünkü yalnızca ring 3'e sahipsiniz ve Linux bunu yapmanızı engelliyor .
GitHub yukarı akış . Ubuntu 16.04'te test edilmiştir.
Daha iyi alternatifler
int 0x80
yerini sistem çağrıları yapmak için daha iyi alternatifler almıştır: önce sysenter
, sonra VDSO.
x86_64 yeni bir syscall
talimat içeriyor .
Ayrıca bkz: "int 0x80" veya "syscall" daha iyi nedir?
Minimum 16 bit örnek
Öncelikle minimal bir önyükleyici işletim sisteminin nasıl oluşturulacağını ve burada açıkladığım gibi QEMU ve gerçek donanım üzerinde nasıl çalıştırılacağını öğrenin: https://stackoverflow.com/a/32483545/895245
Artık 16 bit gerçek modda çalıştırabilirsiniz:
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
Bu sırayla yapacaktı:
Do 0.
Do 1.
hlt
: yürütmeyi durdurİşlemcinin adreste ilk işleyiciyi nasıl aradığına ve 0
ikincisini 4
: bu IVT adı verilen bir işleyiciler tablosudur ve her girişin 4 baytı vardır.
Biraz IO yapan minimal örnek görünür kılmak için yapan
Minimum korumalı mod örneği
Modern işletim sistemleri sözde korumalı modda çalışır.
Bu modda kullanım daha fazla seçeneğe sahiptir, bu nedenle daha karmaşıktır, ancak ruhu aynıdır.
Anahtar adım, işleyicileri tanımlayan bir bellek içi veri yapısının (Kesme Tanımlayıcı Tablosu) adresini işaret eden LGDT ve LIDT talimatlarını kullanmaktır.
int 0x80, x86 (yani Intel uyumlu) işlemcilerde Linux'ta sistem çağrılarını çağırmak için kullanılan birleştirme dili talimatıdır.
"İnt" komutu bir kesmeye neden olur.
Basit Cevap: Basitçe ifade etmek gerekirse, kesme, CPU'yu kesintiye uğratan ve ona belirli bir görevi çalıştırmasını söyleyen bir olaydır.
Ayrıntılı Cevap :
CPU, bellekte depolanan bir Kesme Servis Rutinleri (veya ISR'ler) tablosuna sahiptir. Real, (16-bit) Modunda, bu şekilde depolanan IVT veya bir nterrupt V ector T mümkün. IVT tipik olarak 0x0000:0x0000
(fiziksel adres 0x00000
) konumunda bulunur ve ISR'leri işaret eden bir dizi segment ofset adresidir . İşletim sistemi, önceden var olan IVT girişlerini kendi ISR'leriyle değiştirebilir.
(Not: IVT'nin boyutu 1024 (0x400) bayta sabitlenmiştir.)
Korumalı (32 bit) Modda, CPU bir IDT kullanır. IDT, CPU'ya kesme işleyicileri hakkında bilgi veren tanımlayıcılardan (kapılar olarak da bilinir) oluşan değişken uzunluklu bir yapıdır . Bu tanımlayıcıların yapısı, IVT'nin basit segment ofset girişlerinden çok daha karmaşıktır; işte burada:
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 değişken boyutta olabilir, ancak sıralı olmalıdır, yani IDT'nizin 0x00 ile 0x50 arasında olduğunu bildirirseniz, 0x00 ile 0x50 arasında her kesmeye sahip olmalısınız. İşletim sistemi bunların hepsini kullanmak zorunda değildir, bu nedenle Sunum biti, CPU'nun işletim sisteminin işlemeyi düşünmediği kesintileri düzgün bir şekilde işlemesine izin verir.
Bir kesinti meydana geldiğinde (bir int
IRQ'da harici bir tetikleyici (örneğin bir donanım aygıtı) veya bir programdan gelen talimatla), CPU EFLAGS, ardından CS ve ardından EIP'ye basar. (Bunlar iret
, kesme dönüş talimatı tarafından otomatik olarak geri yüklenir .) İşletim sistemi genellikle makinenin durumu hakkında daha fazla bilgi depolar, kesmeyi ele alır, makine durumunu geri yükler ve devam eder.
Birçok * NIX işletim sisteminde (Linux dahil), sistem çağrıları kesintiye dayalıdır. Program kayıtlardaki sistem çağrısına argümanları koyar (EAX, EBX, ECX, EDX, vb.) Ve interrupt 0x80'i çağırır. Çekirdek, IDT'yi 0x80'de bir kesme işleyicisi içerecek şekilde ayarlamıştır; bu, kesme 0x80 aldığında çağrılır. Çekirdek daha sonra argümanları okur ve buna göre bir çekirdek işlevini çağırır. EAX / EBX'te bir iadeyi saklayabilir. Sistem çağrılarının yerini büyük ölçüde sysenter
ve sysexit
(veya syscall
vesysret
halka 0 içine daha hızlı giriş için izin talimatlar, AMD üzerine).
Bu kesintinin farklı bir işletim sisteminde farklı bir anlamı olabilir. Belgelerini kontrol ettiğinizden emin olun.
eax
sistem çağrı numarası için kullanılır. asm.sourceforge.net/intro/hello.html
Belirtildiği gibi, denetimin 0x80 vektörünü kesmek için atlamasına neden olur. Pratikte bunun anlamı (en azından Linux altında) bir sistem çağrısının başlatılmasıdır; tam sistem çağrısı ve argümanlar kayıtların içeriği ile tanımlanır. Örneğin, exit (),% eax olarak 1 ve ardından 'int 0x80' ayarlanarak çağrılabilir.
İşlemciye, Linux işletim sistemlerinde open()
dosyalar vb. Gibi sistem işlevlerini çağırmak için kullanılan sistem çağrısı kesmesi olan 0x80 kesinti vektörünü etkinleştirmesini söyler .
int bir kesintiden başka bir şey değildir, yani işlemci mevcut yürütmesini beklemeye alacaktır.
0x80, bir sistem çağrısı veya çekirdek çağrısından başka bir şey değildir. yani sistem işlevi yürütülecektir.
Belirli bir 0x80 olması, rt_sigtimedwait / init_module / restart_sys'i temsil eder, mimariden mimariye değişir.
Daha fazla ayrıntı için https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md adresine bakın.