Хтось може пояснити, що робить наступний код збірки?
int 0x80
Хтось може пояснити, що робить наступний код збірки?
int 0x80
Відповіді:
Він передає управління вектору переривання 0x80
Див. Http://en.wikipedia.org/wiki/Interrupt_vector
У Linux подивіться на це : він використовувався для обробки system_call
. Звичайно, в іншій ОС це може означати щось зовсім інше.
int 0x80
як про особливий вид call
функції в ядрі (вибраний eax
).
int
означає переривання, а число 0x80
є числом переривання. Переривання передає потік програми тому, хто обробляє це переривання, яке 0x80
в цьому випадку є перериванням . У Linux 0x80
обробник переривань є ядром і використовується для здійснення системних викликів до ядра іншими програмами.
Ядро отримує повідомлення про те, який системний виклик хоче зробити програма, перевіряючи значення в реєстрі %eax
(синтаксис AT&T та EAX у синтаксисі Intel). Кожен системний виклик має різні вимоги щодо використання інших регістрів. Наприклад, значення 1
in %eax
означає системний виклик exit()
, а значення in %ebx
містить значення коду стану для exit()
.
Майте на увазі, що 0x80
= 80h
=128
Ви можете побачити тут , що INT
це тільки один з багатьох інструкцій ( на насправді уявлення асемблера (або я повинен сказати «Мнемоніка») з неї) , яка існує в наборі команд x86. Ви також можете знайти додаткову інформацію про цю інструкцію у власному посібнику Intel, який знаходиться тут .
Підсумовуємо з PDF-файлу:
INT n / INTO / INT 3 — Процедура виклику до переривання
Інструкція INT n генерує виклик обробнику переривання або винятку, вказаному з операндом призначення. Операнд призначення вказує вектор від 0 до 255, кодований як 8-бітове беззнакове проміжне значення. Інструкція INT n є загальною мнемонікою для виконання програмно-генерованого виклику до обробника переривань.
Як бачите, 0x80 - операнд призначення у вашому запитанні. На даний момент центральний процесор знає, що він повинен виконати якийсь код, який знаходиться в ядрі, але який код? Це визначається вектором переривань у Linux.
Одним з найкорисніших програмних переривань DOS було переривання 0x21. Зателефонувавши до нього з різними параметрами в регістрах (переважно ah та al), ви отримаєте доступ до різних операцій вводу-виводу, виводу рядків тощо.
Більшість систем Unix та похідних не використовують програмні переривання, за винятком переривання 0x80, що використовується для здійснення системних дзвінків. Це досягається введенням 32-бітового значення, що відповідає функції ядра, в регістр EAX процесора, а потім виконанням INT 0x80.
Погляньте на це, будь-де, де показані інші доступні значення в таблицях обробників переривань:
Як ви можете бачити, таблиця вказує на центральний процесор для виконання системного виклику. Ви можете знайти таблицю системних дзвінків Linux тут .
Отже, перемістивши значення 0x1 до реєстру EAX і викликавши INT 0x80 у вашій програмі, ви можете змусити процес виконати код у ядрі, який зупинить (вийде) поточний запущений процес (на Linux, x86 Intel CPU).
Апаратне переривання не слід плутати з програмним перериванням. Ось дуже гарна відповідь з цього приводу.
Це також є хорошим джерелом.
int 0x80
I386 Linux системного виклику ABI дуже схожий на DOS int 0x21
ABI. Помістіть номер виклику в реєстр (AH для DOS, EAX для Linux) та інші аргументи в інші регістри, а потім запустіть інструкцію переривання програмного забезпечення. Основна відмінність полягає в тому, що дозволяють вам системні виклики (доступ до обладнання безпосередньо в DOS, але не в Linux), а не в тому, як ви їх викликаєте.
/usr/include/x86_64-linux-gnu/asm/unistd_64.h
Приклад мінімального запуску системного виклику Linux
Linux налаштовує обробник переривань 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
Результат: програма друкує до stdout:
hello world
і виходить чисто.
Ви не можете встановити власні обробники переривань безпосередньо з користувацької області, оскільки у вас є лише кільце 3, і Linux заважає вам це робити .
GitHub вгору за течією . Перевірено на Ubuntu 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
: це таблиця обробників, що називається IVT , і кожен запис має 4 байти.
Мінімальний приклад, який робить деякий IO, щоб зробити обробники видимими.
Приклад мінімального захищеного режиму
Сучасні операційні системи працюють у так званому захищеному режимі.
У цьому режимі обробки є більше опцій, тому він складніший, але дух той самий.
Ключовим кроком є використання інструкцій LGDT та LIDT, які вказують адресу структури даних в пам'яті (таблиця дескрипторів переривань), яка описує обробники.
int 0x80 - це інструкція асемблерної мови, яка використовується для виклику системних викликів у Linux на процесорах x86 (тобто сумісних з Intel).
Інструкція "int" викликає переривання.
Проста відповідь: Простіше кажучи, переривання - це подія, яка перериває центральний процесор і повідомляє йому про те, щоб запустити певне завдання.
Детальна відповідь :
Процесор має таблицю процедур обслуговування переривань (або ISR), що зберігаються в пам'яті. У реальному (16-біт) режимі, це зберігається як IVT , або я nterrupt В Ector Т стані. IVT, як правило, знаходиться за 0x0000:0x0000
(фізичною адресою 0x00000
) і являє собою ряд адрес із зміщенням сегментів, які вказують на ISR. ОС може замінити попередні записи IVT власними ISR.
(Примітка: Розмір IVT встановлений на рівні 1024 (0x400) байт.)
У захищеному (32-розрядному) режимі центральний процесор використовує IDT. IDT - це структура змінної довжини, яка складається з дескрипторів (інакше їх називають воротами), які повідомляють ЦП про обробники переривань. Структура цих дескрипторів набагато складніша, ніж прості записи про зміщення сегментів IVT; ось:
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. ОС не обов’язково використовує всі з них, тому Present біт дозволяє процесору правильно обробляти переривання, які ОС не збирається обробляти.
Коли відбувається переривання (або зовнішнім тригером (наприклад, апаратним пристроєм) у IRQ, або int
інструкцією програми), процесор штовхає EFLAGS, потім CS, а потім EIP. (Вони автоматично відновлюються iret
інструкцією повернення переривання.) ОС зазвичай зберігає більше інформації про стан машини, обробляє переривання, відновлює стан машини і продовжує далі.
У багатьох операційних системах * NIX (включаючи Linux) системні дзвінки базуються на перериваннях. Програма поміщає аргументи до системного виклику в регістри (EAX, EBX, ECX, EDX тощо) і викликає переривання 0x80. Ядро вже встановило IDT, щоб містив обробник переривань на 0x80, який викликається, коли він отримує переривання 0x80. Потім ядро читає аргументи і відповідно викликає функцію ядра. Він може зберігати повернення в EAX / EBX. Системні виклики були в значній мірі замінити sysenter
і sysexit
(або syscall
і sysret
на AMD) інструкції, які дозволяють швидше входу в кільце 0.
Це переривання може мати різне значення в іншій ОС. Обов’язково перевірте його документацію.
eax
для номера syscall. asm.sourceforge.net/intro/hello.html
Як уже згадувалося, це змушує управління переходити до вектора переривання 0x80. На практиці це означає (принаймні під Linux) те, що викликається системний виклик; точний системний виклик та аргументи визначаються вмістом регістрів. Наприклад, вихід () можна викликати, встановивши для% eax значення 1, а потім "int 0x80".
Він повідомляє процесору активувати вектор переривання 0x80, який в ОС Linux є перериванням системного виклику, що використовується для виклику системних функцій, таких як open()
файли тощо.
int - це не що інше, як переривання, тобто процесор утримує поточне виконання.
0x80 - це не що інше, як системний виклик або виклик ядра. тобто буде виконана функція системи.
Якщо бути конкретним, 0x80 представляє rt_sigtimedwait / init_module / restart_sys, він змінюється від архітектури до архітектури.
Детальніше див. Https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md