Что означает «int 0x80» в коде сборки?

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

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

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

ЦП имеет таблицу программ обслуживания прерываний (или ISR), хранящуюся в памяти. В реальном (16-битном) режиме это сохраняется как IVT, или же япрервать Vэктор Тв состоянии. IVT обычно находится в (Физический адрес ), и это серия адресов со смещением сегмента, которые указывают на ISR. ОС может заменить существующие записи IVT своими собственными ISR.

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

В защищенном (32-битном) режиме ЦП использует IDT. IDT — это структура переменной длины, состоящая из дескрипторы (иначе известные как ворота), которые сообщают ЦП об обработчиках прерываний. Структура этих дескрипторов намного сложнее, чем простые записи смещения сегмента в IVT; вот:

* IDT может иметь переменный размер, но он должен быть последовательным, т.е. если вы объявляете IDT от 0x00 до 0x50, вы должны иметь каждое прерывание от 0x00 до 0x50. ОС не обязательно использует их все, поэтому бит «Присутствует» позволяет ЦП правильно обрабатывать прерывания, которые ОС не намерена обрабатывать.

Когда происходит прерывание (либо по внешнему триггеру (например, аппаратному устройству) в IRQ, либо по инструкция из программы), ЦП нажимает EFLAGS, затем CS, а затем EIP. (Они автоматически восстанавливаются , инструкция возврата из прерывания.) ОС обычно хранит дополнительную информацию о состоянии машины, обрабатывает прерывание, восстанавливает состояние машины и продолжает работу.

Во многих ОС * NIX (включая Linux) системные вызовы основаны на прерываниях. Программа помещает аргументы системного вызова в регистры (EAX, EBX, ECX, EDX и т. Д.) И вызывает прерывание 0x80. Ядро уже установило IDT, чтобы содержать обработчик прерывания на 0x80, который вызывается, когда он получает прерывание 0x80. Затем ядро ​​считывает аргументы и соответственно вызывает функцию ядра. Он может хранить возврат в EAX / EBX. Системные вызовы в значительной степени были заменены и (или же и на AMD) инструкции, которые позволяют быстрее войти в кольцо 0.

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

Интересный факт: системный вызов FreeBSD i386 ABI передает аргументы в стек пользовательского пространства. Только eax используется для номера системного вызова. asm.sourceforge.net/intro/hello.html

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

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

  • 9 Строго говоря, он не сообщает ядру … Он сообщает ЦП, который ищет обработчик в IDT, который в конечном итоге является указателем на некоторый код ядра.
  • Правда. Я полагаю, что лучше было бы сказать, что ЦП активировал вектор, а вектор (как часть ядра) вызывает функцию.
  • который в конечном итоге делает это, который в конечном итоге делает то, что затем делает это, что затем идет туда смущенный. : / У Эмбер есть ответ, который понятен .. вот оно ..

int — это не что иное, как прерывание, т.е. процессор приостанавливает свое текущее выполнение.

0x80 — это не что иное, как системный вызов или вызов ядра. то есть системная функция будет выполнена.

Чтобы быть конкретным, 0x80 представляет rt_sigtimedwait / init_module / restart_sys, он варьируется от архитектуры к архитектуре.

Для получения дополнительной информации см. Https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md.

Сегментные регистры

Сегменты — это специфические части программы, которые содержат данные, код и стек. Есть три основных сегмента:

   Сегмент кода (Code Segment или CS) — содержит все команды и инструкции, которые должны быть выполнены. 16-битный регистр сегмента кода или регистр CS хранит начальный адрес сегмента кода.

   Сегмент данных (Data Segment или DS) — содержит данные, константы и рабочие области. 16-битный регистр сегмента данных или регистр DS хранит начальный адрес сегмента данных.

   Сегмент стека (Stack Segment или SS) — содержит данные и возвращаемые адреса процедур или подпрограмм. Он представлен в виде структуры данных «Стек». Регистр сегмента стека или регистр SS хранит начальный адрес стека.

Кроме регистров CS, DS и SS существуют и другие регистры дополнительных сегментов — ES (Extra Segment), FS и GS, которые предоставляют дополнительные сегменты для хранения данных.

При написании программ на ассемблере, программе необходим доступ к ячейкам памяти. Все области памяти в сегменте относятся к начальному адресу сегмента. Сегмент начинается с адреса, равномерно делимого на десятичное 16 или на 10. Таким образом, крайняя правая шестнадцатеричная цифра во всех таких адресах памяти равна , которая обычно не хранится в сегментных регистрах.

Сегментные регистры хранят начальные адреса сегмента. Чтобы получить точное местоположение данных или команды в сегменте, требуется значение смещения. Чтобы сослаться на любую ячейку памяти в сегменте, процессор объединяет адрес сегмента в сегментном регистре со значением смещения местоположения.

Регистры данных

Регистры данных — это четыре 32-битных регистра, которые используются для арифметических, логических и других операций. Эти 32-битные регистры могут быть использованы следующими тремя способами:

   как полные 32-битные регистры данных: EAX, EBX, ECX, EDX;

   нижние половины 32-битных регистров могут использоваться как четыре 16-битных регистра данных: AX, BX, CX и DX;

   нижняя и верхняя половины вышеупомянутых четырех 16-битных регистров могут использоваться как восемь 8-битных регистров данных: AH, AL, BH, BL, CH, CL, DH и DL.

Некоторые из этих регистров данных имеют специфическое применение в арифметических операциях:

   AX (primary accumulator) — используется для ввода/вывода и в большинстве арифметических операций. Например, в операции умножения один операнд сохраняется в регистре EAX/AX/AL в соответствии с размером операнда.

   BX (base register) — используется при индексированной адресации.

   CX (count register) — хранит количество циклов в повторяющихся операциях (также, как и регистры ECX и CX).

   DX (data register) — используется в операциях ввода/вывода, а также с регистрами AX и DX для выполнения операций умножения и деления, связанных с большими значениями.

Адресация прямого смещения

Этот режим адресации использует арифметические операторы для изменения адреса. Например, следующие определения определяют таблицы данных:

BYTE_TABLE DB 14, 15, 22, 45 ; таблица байтов
WORD_TABLE DW 134, 345, 564, 123 ; таблица слов

1
2

BYTE_TABLEDB14,15,22,45; таблица байтов

WORD_TABLEDW134,345,564,123; таблица слов

Следующие операции копируют данные из таблиц в памяти в регистры:

MOV CL, BYTE_TABLE ; получаем 3-й элемент из BYTE_TABLE
MOV CL, BYTE_TABLE + 2 ; получаем 3-й элемент из BYTE_TABLE
MOV CX, WORD_TABLE ; получаем 4-й элемент из WORD_TABLE
MOV CX, WORD_TABLE + 3 ; получаем 4-й элемент из WORD_TABLE

1
2
3
4

MOVCL,BYTE_TABLE2; получаем 3-й элемент из BYTE_TABLE

MOVCL,BYTE_TABLE+2; получаем 3-й элемент из BYTE_TABLE

MOVCX,WORD_TABLE3; получаем 4-й элемент из WORD_TABLE

MOVCX,WORD_TABLE+3; получаем 4-й элемент из WORD_TABLE

Непрямая адресация памяти

Обычно для этой цели используются базовые регистры EBX, EBP (или BX, BP) и индексные регистры (DI, SI), используемые в квадратных скобках для ссылок на память.

Непрямая адресация обычно используется для переменных, содержащих несколько элементов, таких как массивы. Начальный адрес массива хранится, например, в регистре EBX.

В следующем примере мы получаем доступ к разным элементам переменной:

MY_TABLE TIMES 10 DW 0 ; выделяем 10 слов (2 байта), каждое из которых инициализируем значением 0
MOV EBX, ; помещаем эффективный адрес MY_TABLE в EBX
MOV , 110 ; MY_TABLE = 110
ADD EBX, 2 ; EBX = EBX +2
MOV , 123 ; MY_TABLE = 123

1
2
3
4
5

MY_TABLETIMES10DW; выделяем 10 слов (2 байта), каждое из которых инициализируем значением 0

MOVEBX,MY_TABLE; помещаем эффективный адрес MY_TABLE в EBX

MOVEBX,110; MY_TABLE = 110

ADDEBX,2; EBX = EBX +2

MOVEBX,123; MY_TABLE = 123

Кому и зачем нужен язык ассемблера?

Даже из нашего примера «Hello, World!» видно, что ассемблер не так удобен в разработке, как языки высокого уровня. Больших программ на этом языке сейчас никто не пишет, но есть области, где он незаменим:

  • На ассемблере разрабатывают встроенные программы для микроконтроллеров. Это миниатюрные компьютеры, установленные в системах сигнализации, пультах управления, датчиках, бытовой технике, модемах и во многих других устройствах. Микроконтроллеры используются даже в робототехнике и спутниковых навигационных системах. Объём памяти у этих мини-компьютеров ограничен, а ассемблер удобен для их программирования тем, что одна его команда транслируется в одну команду в двоичном коде. По исходному тексту программы можно определить время её исполнения и объём памяти для её хранения.
  • На ассемблере пишут драйверы устройств и некоторые компоненты операционных систем — например, ядро или загрузчик. Любительские операционные системы MenuetOS и KolibriOS полностью написаны на ассемблере. Ассемблерный код есть в программах для игровых приставок и мультимедийных кодеков.
  • Ассемблер применяется в реверс-инжиниринге — обратной разработке программ. Реверс-инжиниринг используют, чтобы понять, как работают программы, какой у них алгоритм. Это нужно в тех случаях, когда создатель по каким-то причинам не хочет публиковать исходный код. Обратной разработкой занимаются антивирусные компании, исследующие вирусы и трояны, создатели драйверов и операционных систем, а также просто любопытные. Ещё её активно применяют компьютерные злоумышленники всех мастей: взламывают программы, ищут уязвимости, пишут вирусы, генераторы ключей и тому подобное.

Режим адресации

В этой статье мы не собираемся углубляться в режим адресации, а сосредоточимся на формате инструкций архитектуры Intel IA32-64:

Вкратце, пожалуйста, обратитесь к руководству Intel для получения дополнительной информации:

— Prefixes : Используется для изменения кода операции, указания семантики блокировки, повтора и т. Д. — REX Prefix: —- Specify GPRs and SSE registers. —- Specify 64-bit operand size. —- Specify extended control registers. —Opcode: Код операции, такой как mov, push. —Mod R/M: Относительно адресации, см. Руководство для деталей. —SIB: В сочетании с Mod R / M для указания адресации. —Displacement: Сотрудничайте с Mod R / M и SIB для определения адресации. —Immediate: Немедленные данные.

Если вы не понимаете описанный выше код операции, Mod R / W, SIB, disp, imm, есть концепция для чтения компиляции предложений:

Если эта компиляция не понятна, сотрудничайте со следующими:

— Base + (Index ∗ Scale) + Displacement — Using all the addressing components together allows efficient indexing of a two-dimensional array when the elements of the array are 2, 4, or 8 bytes in size.

Microchip ATmega328P

Вторым в нашем списке идет 8-разрядный AVR микроконтроллер ATmega328P.

Рисунок 3 – Микроконтроллер ATmega328P от Microchip

Выводы GPIO с возможностью генерирования прерываний

ATmega328P имеет 23 вывода GPIO, разделенных на три порта: PORTB (восемь выводов), PORTC (семь выводов) и PORTD (восемь выводов). Все выводы имеют возможность генерирования прерываний по изменению состояния на выводе. Однако отдельных флагов прерываний выводов нет, вместо этого флаг прерывания есть у каждого порта. Но два вывода на PORTD можно настроить как внешние прерывания, у них есть отдельные флаги прерывания.

Настройка прерываний

23 прерывания по изменению состояния на выводе предварительно настроены для обнаружения логического изменения значения на выводах (с 0 на 1 или с 1 на 0). Два внешних прерывания могут быть сконфигурированы для обнаружения только нарастающего фронта (изменение с 0 на 1), только спадающего фронта (изменение с 1 на 0) или постоянного значения 0. Прерывание по изменению состояния на выводе для каждого вывода может быть отдельно включено или выключено. Кроме того, может быть включено или выключено прерывание для каждого порта.

Флаг прерывания для порта или любого из выводов внешних прерываний устанавливается всегда, когда происходит событие, для которого он настроен, независимо от того, включено ли прерывание или выключено. Кроме того, флаг будет установлен независимо от того, настроен ли вывод как выход или как вход.

Вектор прерывания, обработчик и приоритеты

Каждый порт имеет один вектор прерывания (у PORTB – это PCINT0, у PORTC – это PCINT1, у PORTD – это PCINT2). Кроме того, каждый вывод внешнего прерывания имеет свой собственный отдельный вектор (вывод 2 в PORTD – INT0, а вывод 3 в PORTD – INT1). Каждый вектор прерывания может быть включен или отключен индивидуально, но это делается в периферийном устройстве GPIO, а не в контроллере прерываний (то есть контроллер прерываний не имеет возможности отдельного включения векторов прерываний, и все разрешения векторов прерываний выполняются в периферийных устройствах).

Поскольку векторы прерываний есть только у портов (для прерываний по изменению состояния на выводе), в обработчике прерывания необходимо выяснить, какой вывод и какое событие вызвало прерывание. Для этого потребуется прочитать маску прерываний для порта (чтобы узнать, прерывания каких выводов включены) и текущее значение вывода, чтобы выяснить, какое логическое изменение произошло. Однако для двух внешних прерываний вы уже будете знать, какой вывод вызвал прерывание, поскольку каждый вывод имеет отдельный вектор. Аппаратное обеспечение автоматически очищает флаги прерываний для внешних прерываний, хотя, ради безопасности, вы также можете очистить их в своем коде.

В ATmega328P приоритеты прерываний фиксированы и не могут быть изменены. После прерывания сброса прерывания выводов имеют самый высокий приоритет среди всех прерываний в следующем порядке: INT0, INT1, PCINT0, PCINT1, PCINT2.

Обработчики прерываний в ATmega328P могут быть прерваны прерываниями с более высоким приоритетом, но это не происходит автоматически. Когда запускается обработчик прерывания, CPU отключает все прерывания. Вы должны вручную включить прерывания в коде своего обработчика, чтобы разрешить вытеснение. Кроме того, существует регистр, называемый регистром состояния AVR, который является частью CPU, и значение которого CPU не сохраняет автоматически перед входом в прерывание и не восстанавливает после выхода из прерывания. Вы должны в своем обработчике прерывания сохранить и восстановить его значение. Причина, по которой вы должны это сделать, заключается в том, что CPU должен возобновить работу в том состоянии, в котором он находился до возникновения прерывания. Возможно, что действия, которые вы выполняете в своем обработчике, могут изменить этот регистр, поэтому, если вы не сохраните значение, которое он имел до начала ваших действий, и не восстановите его, CPU после вашего прерывания вернется в другое состояние, что может трудноуловимые ошибки в вашей системе.

Прерывания

Для обработки событий, происходящих асинхронно
по отношению к выполнению программы, лучше всего
подходит механизм прерываний. Прерывание можно
рассматривать как некоторое особое событие в
системе, требующее моментальной реакции.

Практически все системы ввода/вывода в
компьютере работают с использованием
прерываний. В частности, когда вы нажимаете
клавиши или щелкаете мышью, аппаратура
вырабатывает прерывания. В ответ на них система,
соответственно, считывает код нажатой клавиши
или запоминает координаты курсора мыши.
Прерывания вырабатываются контроллером диска,
адаптером локальной сети, портами
последовательной передачи данных, звуковым
адаптером и другими устройствами.

Кажется очевидным, что возможны самые
разнообразные прерывания по самым различным
причинам. Поэтому с прерыванием связывают число —
так называемый номер прерывания.

Этот номер однозначно соответствует тому или
иному событию. Система умеет распознавать
прерывания и при их возникновении запускает
процедуру, соответствующую номеру прерывания.

Некоторые прерывания (первые пять по порядку
номеров) зарезервированы для использования
центральным процессором на случай каких-либо
особых событий вроде попытки деления на нуль,
переполнения и т. п.

Программы могут сами вызывать прерывания с
заданным номером. Для этого они используют
команду INT. Это так называемые программные
прерывания. Программные прерывания не являются
асинхронными, так как вызываются из программы.

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

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

Аппаратные прерывания вызываются физическими
устройствами и потому приходят асинхронно по
отношению к выполнению любых программ. Эти
прерывания информируют систему о событиях,
связанных с работой устройств. Например, о том,
что наконец-то завершилась печать символа на
принтере и неплохо было бы выдать следующий
символ, или о том, что сектор диска уже прочитан и
его содержимое доступно программе.

Использование прерываний при работе с
медленными внешними устройствами позволяют
совместить ввод/вывод с обработкой данных в
центральном процессоре. В результате этого
повышается общая производительность системы.

Иногда желательно сделать систему
нечувствительной ко всем или отдельным
аппаратным прерываниям . Для этого используют
так называемое маскирование прерываний, о
котором мы еще будем говорить. Но существует и
немаскируемое прерывание (которое, кстати,
все-таки можно замаскировать, или, точнее говоря,
заблокировать).

Заметим, что обработчики прерываний могут сами
вызывать программные прерывания, например, для
получения доступа к сервису BIOS или MS-DOS.

Составление собственных программ обработки
прерываний и замена стандартных обработчиков
MS-DOS и BIOS является достаточно сложной задачей.
Необходимо учитывать все тонкости работы
аппаратуры, а также взаимодействия программного
и аппаратного обеспечения. При отладке возможно
разрушение операционной системы с
непредсказуемыми последствиями, поэтому надо
очень внимательно следить за тем, что делает ваша
программа.

Как устроен язык ассемблера?

Ассемблер можно считать языком второго поколения, если за первый принять машинный язык. Он работает непосредственно с процессором, и каждая его команда — это инструкция процессора, а не операционной или файловой системы. Перевод языка ассемблера в машинный код называется ассемблированием.

Команды ассемблера состоят из кодов операций и операндов. Операнды — это адреса, из которых процессор будет брать данные для вычислений и в которые будет помещать результат. Адресами могут быть ячейки оперативной памяти и регистры — память внутри процессора. Процессор работает с регистрами гораздо быстрее, чем с оперативной памятью.

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

  • ADD — сложение (от англ. addition);
  • SUB — вычитание (от англ. subtraction);
  • MUL — умножение (от англ. multiplication) и так далее.

Регистрам и ячейкам памяти присваиваются символические имена, например:

EAX, EBX, AX, AH — имена для регистров;

meml — имя для ячейки памяти.

Например, так выглядит команда сложения чисел из регистров AX и BX:

add ax, bx

А это команда вычитания чисел из регистров AX и BX:

sub ax, bx

Кроме инструкций, в языке ассемблера есть директивы — команды управления компилятором, то есть программой-ассемблером.

Вот некоторые из них:

  • INCLUDE — открыть файл и начать его компиляцию;
  • EXIT — прекратить компиляцию файла;.
  • DEF — назначить регистру символическое имя и т. д.

Не думайте, что ассемблер — всего лишь набор инструкций процессора с удобной для программиста записью. Это полноценный язык программирования, на котором можно организовать циклы, условные переходы, процедуры и функции.

Вот, например, код, на ассемблере, выводящий на экран цифры от 1 до 10:

Здесь действие будет выполняться в цикле — как, например, в циклах for или do while в языках высокого уровня.

Единого стандарта для языков ассемблера нет. В работе с процессорами Intel разработчики придерживаются двух синтаксисов: Intel и AT&T. Ни у того ни у другого нет особых преимуществ: AT&T — стандартный синтаксис в Linux, а Intel используется в мире Microsoft.

Одна и та же команда в них выглядит по-разному.

Например, в синтаксисе Intel:

mov eax, ebx — команда перемещает данные из регистра eax в регистр ebx.

В синтаксисе AT&T эта команда выглядит так:

Настройка глобальной таблицы дескрипторов

Далее идёт настройка глобальной таблицы дескрипторов (GDT). Мы можем видеть функцию , которая настраивает GDT (вы можете прочитать про это в посте ). В этой функции определён массив , который содержит определение трёх сегментов:

	static const u64 boot_gdt[] __attribute__((aligned(16))) = {
		 = GDT_ENTRY(0xc09b, , 0xfffff),
		 = GDT_ENTRY(0xc093, , 0xfffff),
		 = GDT_ENTRY(0x0089, 4096, 103),
	};

для получения кода, данных и TSS (Task State Segment, сегмент состояния задачи). В данный момент мы не будем использовать сегмент состояния задачи. Как мы можем видеть в строке комментария, он был добавлен специально для Intel VT (здесь вы можете найти коммит, который описывает его). Давайте посмотри на . Прежде всего отметим, что она имеет атрибут . Это означает, что структура будет выровнена по 16 байтам. Давайте посмотрим на простой пример:

#include <stdio.h>

struct aligned {
	int a;
}__attribute__((aligned(16)));

struct nonaligned {
	int b;
};

int main(void)
{
	struct aligned    a;
	struct nonaligned na;

	printf("Not aligned - %zu \n", sizeof(na));
	printf("Aligned - %zu \n", sizeof(a));

	return ;
}

Технически, структура, которая содержит одно поле типа , должна иметь размер 4 байта, но для структуры потребуется 16 байт для хранения в памяти:

Здесь имеет индекс — 2, является и т.д. Он начинается с 2, поскольку первый является обязательным нулевым дескриптором (индекс — 0), а второй не используется (индекс — 1).

— это макрос, который принимает флаги, базовый адрес, предел и создаёт запись в GDT. Для примера посмотрим на запись сегмента кода. принимает следующие значения:

  • базовый адрес —
  • предел —
  • флаги —

Что это значит? Базовый адрес сегмента равен 0, а предел (размер сегмента) равен (1 Мб). Давайте посмотрим на флаги. В двоичном виде значение будет выглядеть следующим образом:

Попробуем понять, что означает каждый бит. Мы пройдёмся по всем битам слева направо

  • 1 — (G) бит гранулярности
  • 1 — (D) если равен 0 — 16-битный сегмент; 1 — 32-битный сегмент
  • 0 — (L) если 1 — выполняется в 64-битном режиме
  • 0 — (AVL) доступен для использования системным ПО
  • 0000 — 4 бита предела в 19:16 бит в дескрипторе
  • 1 — (P) присутствие сегмента в памяти
  • 00 — (DPL) — уровень привилегий, 0 является высшей привилегией
  • 1 — (S) сегмент кода или данных, не системный сегмент
  • 101 — тип сегмента и виды доступа к нему (чтение, выполнение)
  • 1 — бит обращения

После этого мы получаем длину GDT:

gdt.len = sizeof(boot_gdt)-1;

Здесь мы получаем размер и вычитаем 1 (последний действительный адрес в GDT).

Далее получаем указатель на GDT:

gdt.ptr = (u32)&boot_gdt + (ds() << 4);

Здесь мы просто получаем адрес и добавляем его к адресу сегмента данных, сдвинутого влево на 4 бита (не забывайте, что сейчас мы находимся в режиме реальных адресов).

И наконец, мы выполняем инструкцию для загрузки GDT в регистр GDTR:

asm volatile("lgdtl %0" : : "m" (gdt));

Когда и как был создан ассемблер?

Это произошло ещё в сороковых годах прошлого века. Ассемблер был создан для первых ЭВМ на электронных лампах, программы для которых писали на машинном языке. А так как памяти у компьютеров было мало, то команды вводили, переключая тумблеры и нажимая кнопки. Даже несложные вычисления занимали много времени.

Проблему решили, когда ЭВМ научились хранить программы в памяти. Уже в 1950 году была разработана первая программа-транслятор, которая переводила в машинный код программы, написанные на понятном человеку языке. Эту программу назвали программой-сборщиком, а язык — языком ассемблера (от англ. assembler — сборщик).

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

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

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

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

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

В защищенном (32-битном) режиме ЦП использует IDT. IDT — это структура переменной длины, состоящая из дескрипторов (иначе называемых воротами), которые сообщают ЦП об обработчиках прерываний. Структура этих дескрипторов намного сложнее, чем простые записи смещения сегмента IVT; вот:

* IDT может иметь переменный размер, но он должен быть последовательным, т.е. если вы объявляете IDT от 0x00 до 0x50, у вас должны быть все прерывания от 0x00 до 0x50. ОС не обязательно использует их все, поэтому бит «Присутствует» позволяет процессору правильно обрабатывать прерывания, которые ОС не намеревается обрабатывать.

Когда происходит прерывание (либо внешним триггером (например, аппаратным устройством) в IRQ, либо инструкцией из программы), ЦП отправляет EFLAGS, затем CS, а затем EIP. (Они автоматически восстанавливаются , инструкцией возврата из прерывания.) ОС обычно хранит дополнительную информацию о состоянии машины, обрабатывает прерывание, восстанавливает состояние машины и продолжает работу.

Во многих ОС * NIX (включая Linux) системные вызовы основаны на прерываниях. Программа помещает аргументы системного вызова в регистры (EAX, EBX, ECX, EDX и т. Д.) И вызывает прерывание 0x80. Ядро уже установило IDT, чтобы она содержала обработчик прерывания на 0x80, который вызывается при получении прерывания 0x80. Затем ядро ​​считывает аргументы и соответственно вызывает функцию ядра. Он может хранить возврат в EAX / EBX. Системные вызовы в значительной степени были заменены инструкциями и (или и на AMD), что позволяет ускорить вход в кольцо 0.

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

Рейтинг
( Пока оценок нет )
Понравилась статья? Поделиться с друзьями:
Все про сервера
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: