क्या कोई समझा सकता है कि निम्नलिखित विधानसभा कोड क्या करता है?
int 0x80
क्या कोई समझा सकता है कि निम्नलिखित विधानसभा कोड क्या करता है?
int 0x80
जवाबों:
यह वेक्टर 0x80 को बाधित करने के लिए नियंत्रण पास करता है
Http://en.wikipedia.org/wiki/Interrupt_vector देखें
लिनक्स पर, पर एक नजर है इस : इसे संभाल करने के लिए इस्तेमाल किया गया था system_call
। बेशक दूसरे OS पर इसका मतलब कुछ अलग हो सकता है।
int 0x80
एक विशेष प्रकार के call
फ़ंक्शन के रूप में (द्वारा चयनित eax
)।
int
का मतलब है रुकावट, और संख्या 0x80
में बाधा संख्या है। एक व्यवधान कार्यक्रम के प्रवाह को पूर्णता में स्थानांतरित करता है जो उस रुकावट को संभाल रहा है, जो 0x80
इस मामले में बाधित है। लिनक्स में, 0x80
बाधा हैंडलर कर्नेल है, और कर्नेल को अन्य कार्यक्रमों द्वारा सिस्टम कॉल करने के लिए उपयोग किया जाता है।
कर्नेल को सूचित किया जाता है कि रजिस्टर में मूल्य %eax
(एटी एंड टी सिंटैक्स और इंटेल सिंटैक्स में ईएक्सएक्स) की जांच करके कौन सा सिस्टम कॉल करना चाहता है । प्रत्येक प्रणाली कॉल में अन्य रजिस्टरों के उपयोग के बारे में अलग-अलग आवश्यकताएं हैं। उदाहरण के लिए, के एक मूल्य 1
में %eax
की एक प्रणाली कॉल का मतलब है exit()
, और में मूल्य %ebx
के लिए स्थिति कोड का मान रखती है exit()
।
ध्यान रखें कि 0x80
= 80h
=128
आप यहां देख सकते हैं कि INT
कई निर्देशों में से एक है (वास्तव में असेंबली लैंग्वेज प्रतिनिधित्व (या मुझे इसे 'मेनेमोनिक' कहना चाहिए) जो कि x86 इंस्ट्रक्शन सेट में मौजूद है। आप इस निर्देश के बारे में अधिक जानकारी इंटेल के स्वयं के मैनुअल में पा सकते हैं ।
पीडीएफ से सारांशित करने के लिए:
INT n / INTO / INT 3-बाधित प्रक्रिया को बुलावा
INT n निर्देश गंतव्य ऑपरेंड के साथ निर्दिष्ट बाधा या अपवाद हैंडलर को कॉल उत्पन्न करता है। गंतव्य ऑपरेंड एक वेक्टर को 0 से 255 तक निर्दिष्ट करता है, जिसे 8-बिट अहस्ताक्षरित मध्यवर्ती मान के रूप में एन्कोड किया गया है। INT n निर्देश एक सॉफ्टवेयर-जनरेट किए गए कॉल को एक हैंडलर को निष्पादित करने के लिए सामान्य महामारी है।
आप देख सकते हैं 0x80 है गंतव्य संकार्य अपने प्रश्न में। इस बिंदु पर सीपीयू जानता है कि उसे कर्नेल में रहने वाले कुछ कोड को निष्पादित करना चाहिए, लेकिन क्या कोड? यह लिनक्स में इंटरप्ट वेक्टर द्वारा निर्धारित किया जाता है।
सबसे उपयोगी डॉस सॉफ्टवेयर में से एक इंटरप्ट 0x21 था। रजिस्टरों (ज्यादातर आह और अल) में विभिन्न मापदंडों के साथ इसे कॉल करके आप विभिन्न IO संचालन, स्ट्रिंग आउटपुट और अधिक का उपयोग कर सकते हैं।
अधिकांश यूनिक्स सिस्टम और डेरिवेटिव्स सॉफ्टवेयर इंटरप्ट का उपयोग नहीं करते हैं, 0x80 के बीच के अंतर के साथ, सिस्टम कॉल करने के लिए उपयोग किया जाता है। यह प्रोसेसर के EAX रजिस्टर में कर्नेल फ़ंक्शन के अनुरूप 32-बिट मान दर्ज करके और फिर INT 08080 निष्पादित करके पूरा किया जाता है ।
कृपया इस पर एक नज़र डालें कि इंटरप्ट हैंडलर टेबल में अन्य उपलब्ध मान कहाँ दिखाए गए हैं:
जैसा कि आप देख सकते हैं कि टेबल एक सिस्टम कॉल को निष्पादित करने के लिए सीपीयू को इंगित करता है। आप यहां लिनक्स सिस्टम कॉल टेबल पा सकते हैं ।
तो मान 0x1 को EAX रजिस्टर में ले जाकर और अपने प्रोग्राम में INT 0x80 पर कॉल करके, आप प्रक्रिया को कर्नेल में कोड को निष्पादित कर सकते हैं जो वर्तमान चल रही प्रक्रिया (लिनक्स, x86 इंटेल सीपीयू पर) को रोक देगा (बाहर निकल जाएगा)।
एक हार्डवेयर व्यवधान को सॉफ़्टवेयर रुकावट के साथ भ्रमित नहीं होना चाहिए। यहाँ इस संबंध में एक बहुत अच्छा जवाब है।
यह भी अच्छा स्रोत है।
int 0x80
I386 लिनक्स सिस्टम कॉल ABI अत्यंत डॉस के समान है int 0x21
ABI। एक रजिस्टर में एक कॉल नंबर डालें (डॉस के लिए एएच, लिनक्स के लिए ईएक्सएक्स), और अन्य रजिस्टरों में अन्य आर्ग्स, फिर एक सॉफ्टवेयर-इंटरफेयर इंस्ट्रक्शन चलाएं। मुख्य अंतर यह है कि सिस्टम कॉल आपको क्या करने देता है (हार्डवेयर को सीधे डॉस में नहीं बल्कि लिनक्स में एक्सेस करें), न कि आप उन्हें कैसे इनवाइट करते हैं।
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
न्यूनतम रननीय लिनक्स सिस्टम कॉल उदाहरण
लिनक्स 0x80
इस तरह के लिए बाधा हैंडलर सेट करता है कि यह सिस्टम कॉल को लागू करता है, कर्नेल के साथ संवाद करने के लिए उपयोगकर्तालैंड प्रोग्राम का एक तरीका है।
.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
इसके साथ संकलित करें और चलाएं:
as -o main.o main.S
ld -o main.out main.o
./main.out
परिणाम: कार्यक्रम प्रिंट करने के लिए:
hello world
और सफाई से बाहर निकलता है।
आप अपने स्वयं के व्यवधान संचालकों को उपयोगकर्ताभूमि से सीधे सेट नहीं कर सकते क्योंकि आपके पास केवल रिंग 3 है और लिनक्स आपको ऐसा करने से रोकता है ।
गिटहब ऊपर । उबंटू 16.04 पर परीक्षण किया गया।
बेहतर विकल्प
int 0x80
सिस्टम कॉल करने के लिए बेहतर विकल्पों से अलग हो गया है: पहले sysenter
, फिर VDSO।
x86_64 में एक नया syscall
निर्देश है ।
यह भी देखें: बेहतर क्या है "int 0x80" या "syscall"?
न्यूनतम 16-बिट उदाहरण
पहले सीखें कि कैसे एक न्यूनतम बूटलोडर ओएस बनाया जाए और इसे QEMU और असली हार्डवेयर पर चलाया जाए जैसा कि मैंने यहां बताया है: https://stackoverflow.com/a/32483545/895245
अब आप 16-बिट वास्तविक मोड में चला सकते हैं:
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
यह क्रम में करना होगा:
Do 0.
Do 1.
hlt
: अमल करना बंद करोध्यान दें कि प्रोसेसर पते पर पहले हैंडलर के लिए कैसा दिखता है 0
, और दूसरा एक 4
: जो हैंडलर की एक तालिका है जिसे आईवीटी कहा जाता है , और प्रत्येक प्रविष्टि में 4 बाइट्स हैं।
न्यूनतम उदाहरण जो हैंडलर को दृश्यमान बनाने के लिए कुछ IO करता है ।
न्यूनतम संरक्षित मोड उदाहरण है
आधुनिक ऑपरेटिंग सिस्टम तथाकथित संरक्षित मोड में चलते हैं।
इस मोड में हैंडलिंग के अधिक विकल्प हैं, इसलिए यह अधिक जटिल है, लेकिन भावना समान है।
प्रमुख कदम LGDT और LIDT निर्देशों का उपयोग कर रहा है, जो हैंडलर का वर्णन करने वाली इन-मेमोरी डेटा संरचना (इंटरप्ट डिस्क्रिप्टर टेबल) के पते को इंगित करता है।
int 0x80 असेंबली लैंग्वेज इंस्ट्रक्शन है जिसका उपयोग लिनक्स में x86 (यानी, इंटेल-कम्पेटिबल) प्रोसेसर पर सिस्टम कॉल को इनवोक करने के लिए किया जाता है।
"इंट" निर्देश एक बाधा का कारण बनता है।
सरल उत्तर: एक रुकावट, बस रखा जाता है, एक ऐसी घटना है जो सीपीयू को बाधित करती है, और इसे एक विशिष्ट कार्य चलाने के लिए कहती है।
विस्तृत जवाब :
CPU में मेमोरी में संग्रहीत इंटरप्ट सर्विस रूटिन (या ISRs) की एक तालिका होती है। रियल (16-बिट) मोड में, इस रूप में संग्रहीत किया जाता है IVT , या मैं nterrupt वी Ector टी में सक्षम। IVT आम तौर पर 0x0000:0x0000
(भौतिक पते 0x00000
) पर स्थित होता है , और यह खंड-ऑफसेट पते की एक श्रृंखला है जो ISRs को इंगित करता है। OS पहले से मौजूद IVT प्रविष्टियों को अपने ISRs से बदल सकता है।
(नोट: आईवीटी का आकार 1024 (0x400) बाइट्स पर तय किया गया है)
संरक्षित (32-बिट) मोड में, CPU एक IDT का उपयोग करता है। IDT एक वैरिएबल-लेंथ स्ट्रक्चर है , जिसमें डिस्क्रिप्टर होते हैं (जिन्हें गेट्स के रूप में जाना जाता है), जो CPU को इंटरप्ट हैंडलर के बारे में बताते हैं। इन विवरणकों की संरचना आईवीटी के सरल सेगमेंट-ऑफ़सेट प्रविष्टियों की तुलना में बहुत अधिक जटिल है; यह रहा:
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 परिवर्तनशील आकार का हो सकता है, लेकिन यह अनुक्रमिक होना चाहिए, अर्थात यदि आप अपना IDT 0x00 से 0x50 तक होने की घोषणा करते हैं, तो आपके पास 0x00 से 0x50 तक प्रत्येक व्यवधान होना चाहिए। ओएस आवश्यक रूप से उन सभी का उपयोग नहीं करता है, इसलिए वर्तमान बिट सीपीयू को ठीक से संभालने की अनुमति देता है बाधित ओएस ओएस को संभालने का इरादा नहीं करता है।
जब एक IRQ में (या int
किसी प्रोग्राम से निर्देश के द्वारा एक बाहरी ट्रिगर (जैसे एक हार्डवेयर डिवाइस) द्वारा एक अवरोध उत्पन्न होता है ), CPU EFLAGS, फिर CS, और फिर EIP को धकेलता है। (ये स्वचालित रूप से बहाल हो जाते हैं iret
, बाधा वापसी निर्देश।) ओएस आमतौर पर मशीन की स्थिति के बारे में अधिक जानकारी संग्रहीत करता है, बाधा को संभालता है, मशीन की स्थिति को पुनर्स्थापित करता है, और जारी रहता है।
कई * NIX OSes (लिनक्स सहित) में, सिस्टम कॉल आधारित हैं। कार्यक्रम रजिस्टर (EAX, EBX, ECX, EDX, आदि) में सिस्टम कॉल के लिए तर्कों को डालता है, और 0x80 को बाधित करता है। कर्नेल ने पहले से ही 0x80 पर एक बाधा हैंडलर रखने के लिए IDT निर्धारित किया है, जिसे तब कहा जाता है जब इसे 0x80 के बीच अवरोध प्राप्त होता है। कर्नेल फिर तर्कों को पढ़ता है और तदनुसार कर्नेल फ़ंक्शन को आमंत्रित करता है। यह EAX / EBX में रिटर्न स्टोर कर सकता है। सिस्टम कॉल काफी हद तक ने ले ली है sysenter
और sysexit
(या syscall
और sysret
एएमडी पर) निर्देश है, जो अंगूठी 0 में तेजी से प्रवेश के लिए अनुमति देते हैं।
इस रुकावट का एक अलग ओएस में एक अलग अर्थ हो सकता है। इसके प्रलेखन की जाँच अवश्य करें।
eax
syscall नंबर के लिए उपयोग किया जाता है। asm.sourceforge.net/intro/hello.html
जैसा कि उल्लेख किया गया है, यह वेक्टर 0x80 को बाधित करने के लिए कूदने के लिए नियंत्रण का कारण बनता है। व्यवहार में इसका अर्थ है (कम से कम लिनक्स के तहत) यह है कि एक सिस्टम कॉल को लागू किया जाता है; सटीक सिस्टम कॉल और तर्कों को रजिस्टरों की सामग्री द्वारा परिभाषित किया गया है। उदाहरण के लिए, एग्जिट () '% 0x80' के बाद% eax को 1 पर सेट करके लागू किया जा सकता है।
यह सीपीयू को बाधित वेक्टर 0x80 को सक्रिय करने के लिए कहता है, जो कि लिनक्स ओएस पर सिस्टम-कॉल इंटरप्ट है, जिसका उपयोग open()
फाइलों, एट सीटेरा जैसे सिस्टम फ़ंक्शन को लागू करने के लिए किया जाता है ।
int एक रुकावट के अलावा कुछ भी नहीं है अर्थात प्रोसेसर अपने वर्तमान निष्पादन को रोक कर रखेगा।
0x80 एक सिस्टम कॉल या कर्नेल कॉल के अलावा कुछ भी नहीं है। यानी सिस्टम फ़ंक्शन को निष्पादित किया जाएगा।
विशिष्ट होने के लिए 0x80 rt_sigtimedwait / init_module / restart_sys का प्रतिनिधित्व करता है जो वास्तुकला से वास्तुकला में भिन्न होता है।
अधिक जानकारी के लिए https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md देखें