Что означает «int 0x80» в коде сборки? - PullRequest
72 голосов
/ 30 ноября 2009

Может кто-нибудь объяснить, что делает следующий ассемблерный код?

 int 0x80  

Ответы [ 8 ]

105 голосов
/ 04 декабря 2009

int означает прерывание, а число 0x80 является номером прерывания. Прерывание передает поток программы тому, кто обрабатывает это прерывание, в данном случае это прерывание 0x80. В Linux обработчик прерываний 0x80 является ядром и используется для выполнения системных вызовов ядра другими программами.

Ядро уведомляется о том, какой системный вызов хочет сделать программа, проверяя значение в регистре %eax (синтаксис газа и EAX в синтаксисе Intel). Каждый системный вызов предъявляет разные требования к использованию других регистров. Например, значение 1 в %eax означает системный вызов exit(), а значение в %ebx содержит значение кода состояния для exit().

53 голосов
/ 30 ноября 2009

Передает управление на вектор прерывания 0x80

См. http://en.wikipedia.org/wiki/Interrupt_vector

В Linux посмотрите на this : он использовался для обработки system_call. Конечно, на другой ОС это может означать что-то совершенно другое.

35 голосов
/ 28 февраля 2015

Имейте в виду, что 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.

Посмотрите на это, где показаны другие доступные значения в таблицах обработчиков прерываний:

enter image description here

Как вы можете видеть из таблицы, указывает на ЦП для выполнения системного вызова. Вы можете найти таблицу системных вызовов Linux здесь .

Таким образом, перемещая значение 0x1 в регистр EAX и вызывая INT 0x80 в вашей программе, вы можете заставить процесс выполнить код в Kernel, который остановит (выйдет) текущий запущенный процесс (в Linux, процессор Intel x86 x86) .

Аппаратное прерывание не следует путать с программным прерыванием. Здесь - очень хороший ответ на этот счет.

Этот также является хорошим источником.

Вы можете увидеть int 80h в действии здесь .

9 голосов
/ 30 ноября 2009

int 0x80 - это язык ассемблера инструкция, которая используется для вызова системные вызовы в Linux на x86 (т.е. Intel-совместимые) процессоры.

http://www.linfo.org/int_0x80.html

7 голосов

Пример минимального запуска системного вызова 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

Результат: программа выводит на стандартный вывод:

hello world

и чисто выходит.

Вы не можете устанавливать свои собственные обработчики прерываний непосредственно из пользовательского пространства, потому что у вас есть только ring 3, а Linux не позволяет вам сделать это .

GitHub upstream . Протестировано на 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, которые указывают адрес структуры данных в памяти (таблица дескрипторов прерываний), которая описывает обработчики.

Минимальный пример

3 голосов
/ 16 июня 2017

Инструкция "int" вызывает прерывание.

Что за прерывание?

Простой ответ: Проще говоря, прерывание - это событие, которое прерывает ЦП и предписывает ему выполнить определенную задачу.

Подробный ответ :

ЦПУ имеет таблицу подпрограмм обработки прерываний (или ISR), хранящихся в памяти. В реальном (16-битном) режиме он сохраняется как IVT или I nterrupt V ector T . IVT обычно находится по адресу 0x0000:0x0000 (физический адрес 0x00000), и это серия адресов со смещением сегмента, которые указывают на ISR. ОС может заменить ранее существующие записи IVT своими собственными ISR.

(Примечание. Размер IVT фиксирован и равен 1024 (0x400) байтов.)

В защищенном (32-разрядном) режиме процессор использует IDT. IDT - это структура переменной длины, состоящая из дескрипторов (также называемых gates), которые сообщают ЦПУ об обработчиках прерываний. Структура этих дескрипторов намного сложнее, чем простые записи смещения сегментов в 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.

Это прерывание может иметь другое значение в другой ОС. Обязательно ознакомьтесь с его документацией.

2 голосов
/ 30 ноября 2009

Как уже упоминалось, управление вызывает переход к вектору прерываний 0x80. На практике это означает (по крайней мере, в Linux), что системный вызов вызывается; точный системный вызов и аргументы определяются содержимым регистров. Например, exit () можно вызвать, установив% eax на 1, за которым следует 'int 0x80'.

1 голос
/ 30 ноября 2009

Он сообщает процессору активировать вектор прерывания 0x80, который в ОС Linux является системным вызовом прерывания, используется для вызова системных функций, таких как open() для файлов и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...