Программирование ввода вывода ассемблер

Тема: Программирование операций ввода-вывода

Целью работы является закрепление лекционного материала по командам прерывания на языке ассемблера и приобретение практических навыков использования этих команд в программах с операциями ввода-вывода.

Основные теоретические сведения

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

Команды прерывания позволяют воспользоваться встроенными системными ресурсами (программами обработки прерываний) из программы пользователя. Под системными ресурсами понимаются программы, входящие в главную исполнительную программу ЭВМ, которая называется BIOS – базовая система ввода-вывода. В функции этой системы входит: запоминание символов, набираемых на клавиатуре, изображение символов на экране дисплея, обмен данными между устройствами, присоединенными к ЭВМ: дисководами, принтером и т.п. Чтобы обратиться к этим возможностям ЭВМ, пользовательская программа должна быть прервана и должна быть выполнена системная функция, после чего пользовательская программа продолжается со следующей после обращения к системным функциям команды. Эти функциональные возможности и выполняют команды прерывания, которые описаны в таблице 11.

В команде прерывания INT тип_прерывания представляет собой номер прерывания, которых в ЭВМ IBM насчитывается 256 (типы прерываний имеют номера 0-255):

  • тип 0 – возникает при делении на 0 или если частное от деления превышает разрядную сетку;
  • тип 1 – действует в режиме “трассировки” ( после выполнения каждой команды программы происходит останов);
  • тип 2 – немаскируемые технические прерывания;
  • тип 3 — прерывания по команде INT, включенной в программу (вызывает останов и отображение содержимого регистров микропроцессора);
  • тип 4 – прерывание по команде INTO, включенной в программу (выполняется при условии, что при выполнении предыдущей команды произошло переполнение разрядной сетки);
  • типы 8-15 – аппаратные прерывания, инициируемые внешними устройствами;
  • типы 16- 31 – планируемые программные прерывания BIOS;
  • типы 32-255 – программные прерывания DOS.
Читайте также:  Программирование ультразвукового датчика ардуино

В некоторых типах прерываний BIOS и DOS имеется много разновидностей, иногда более 10. Так, прерывание 33 (21Н) имеет около 100 разновидностей (это прерывание наиболее часто используется в программах пользователя). В таких случаях вид прерывания (внутри типа) определяется содержимым регистра AH.

Каждому прерыванию в памяти ЭВМ соответствует вектор прерывания (эти вектора размещены в оперативной памяти, начиная с нулевого адреса). Каждый вектор прерывания размещается в 32-битовой ячейке памяти и представляет собой адрес, по которому размещена собственно программа прерывания. По сути такие программы очень похожи на процедуры, отличие в том, что программа прерывания заканчивается командой возврата IRET.

При выполнении команды INT микропроцессор производит следующие действия:

а) помещает в стек регистр флагов;

б) обнуляет флаг трассировки TF и флаг включения-выключения прерываний IF для блокировки других действий, кроме обработки вызванного прерывания;

в) помещает в стек значение регистра CS;

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

д) обращается ко второму слову из вычисленного адреса вектора прерываний и помещает его в регистр CS;

е) помещает в стек значение указателя команд IP;

ж) загружает в IP первое слово вектора прерываний.

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

Команда INTО представляет собой команду условного прерывания. Она инициирует прерывание в том случае, когда флаг переполнения OF равен 1. Следовательно, применять эту команду надо после арифметических операций, которые могут вызвать переполнение. Однако обрабатываться прерывание будет только при наличии переполнения, при отсутствии эта команда будет игнорироваться. Команда INTО вызывает команду обработки по вектору прерывания 4, для определения выполняемых командой действий необходимо обратиться к техническому руководству для конкретной ЭВМ. Выбор действий по обработке ситуаций переполнения возлагается на пользователя, поэтому без дополнительного уточнения по руководству конкретного компьютера пользоваться этой командой не рекомендую.

Команда IRET, как было уже сказано, является командой возврата после прерывания. Она извлекает из стека значения регистров CS и IP и регистра флагов (считывает три ячейки стека), а затем микропроцессор по новому содержанию регистров команд продолжит выполнение программы пользователя.

Наиболее распространенным в программах пользователя является использование прерывания 21H, которое предназначено для вызова функций DOS. В нижеприведенной таблице 12 описываются только некоторые из видов этого прерывания.

Наиболее часто используемые виды прерывания 21Н

Дополнительные входные регистры

Источник

8. Ввод и вывод данных

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

В данном случае, рекомендуется использовать пакет операций, который хранится в модулях IO.ASM и IOPROC.ASM. Последний модуль должен быть заранее оттранслирован и виде объектного модуля записан в файл с именем IOPROC.OBJ.

Схема подключения операций ввода-вывода (ВВ) к программам приведена на рис. 40.

Рис. 40. Подключение к программе модулей

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

LINK PR.OBJ+IOPROC.OBJ, PR.EXE

В текст программы следует включить директиву INCLUDE IO.ASM, чтобы можно было использовать операции ввода-вывода.

Для выполнения программы следует создать командный файл, содержащий текст следующего вида:

8.2. Операции ввода-вывода

Ввод данных с клавиатуры реализован с использованием промежуточного буфера ввода (специальной области памяти): все набираемы на клавиатуре символы сначала попадают в этот буфер (после нажатия на клавиатуре клавиши Enter), и уже оттуда считываются командами ввода. Таким образом, можно сразу ввести много данных и они не пропадут. Если в программе осуществляется ввод по одному символу, то сразу можно набрать много символов, которые затем будут считываться по одному. При вводе допускается редактирование набираемого текста.

Команды ввода не выдают на экран никакого приглашения, поэтому в программе должен быть предусмотрен вывод символов или строки с предложение ввести данные.

Ввод символа осуществляется с помощью следующей команды:

Допустимые типы операнда: регистр 1 байт, переменная размером 1 байт (байт памяти).

По этой команде вводится очередной символ и его код записывается в байтовый регистр или байт памяти.

Ввод числа осуществляется с помощью команды:

Допустимые типы операнда: регистр (слово), переменная размером слово (2 байта).

По данной команде можно вводить число как со знаком, так и без знака. Вводимое число должно быть записано в десятичной системе. Если перед числом есть пробелы, то они игнорируются. Если число набрано без знака или со знаком «плюс», то оно вводится как число без знака и может иметь величину от 0 до 2 16 -1. Если же перед числом указан знак «минус», то оно должно вводится как отрицательное число и должно иметь величину от -2 15 до -1. Концом числа считается любой символ, отличный от цифры. Если величина числа находится вне указанных границ или оно задано неправильно, то фиксируется ошибка и программа прекращает свою работу.

Введенное число всегда записывается в регистр или ячейку размером в слово, но не в байт. Поэтому, например, команда ININT AX допустима, а команда ININT AH – нет.

Очистка буфера ввода осуществляется командой

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

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

Переход на новую строку осуществляется с помощью команды

Это аналог пустой процедуры WriteLn языка Паскаль: по этой команде курсор перемещается на начало следующей строки экрана.

Вывод символа на экран осуществляется с помощью процедуры

Допустимые типы операнда: непосредственный операнд (константа) размером 1 байт; регистр 1 байт; переменная размером 1 байт (байт памяти).

Вывод строки осуществляется по команде

В этой команде не указывается операнд. Его местонахождение определяется заранее – в регистре DX должен находиться начальный адрес выводимой строки. Сама строка должна заканчиваться символом ‘$’, по которому определяется ее конец. При вызове команды OUTSTR выводятся все символы строки, начиная с указанного адреса и до первого знака $, который уже не выводится.

AS DW S ;начальный адрес строки S

Можно упростить данный программный код воспользовавшись оператором LEA.

Ввод числа со знаком осуществляется с помощью команды

Допустимые типы первого операнда: непосредственный операнд размером слово; регистр размером слово; переменная размером слово.

Допустимые типы второго операнда: непосредственный операнд размером 1 байт; регистр размером 1 байт; переменная размером 1 байт.

Обе команды эти команды действуют аналогично – выводят в десятичном виде число, заданное первым операндом и имеющее размер слова, только команда OUTINT трактует его как знаковое число, а команда OUTWORD – как беззнаковое. Например:

OUTWORD 0FFFFh ;вывод 65535

Второй операнд, если есть, всегда трактуется как число без знака и задает ширину поля ввода – число позиций на экране, которые отводятся для вывода числа. Если ширина вывода больше, чем надо, то число прижимается к правому краю этого поля, а перед числом ставятся пробелы. Если же ширина поля меньше или вообще не указана (нет op2), тогда никакие пробелы не выводятся, а выводится только число без каких-либо усечений.

Например, по последовательности команд

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

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

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

Источник

Вывод и ввод с точки зрения ассемблера

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

Стандартная функция вывода

Для вывода данных задействуем функцию printf() . Стандартный вывод в нашем случае будет следующим:

1_gPyOhqYs0zpku8gAyxXNgQ_1-1801-b4f1aa.jpeg

Теперь смотрим на машинный код. Вот, как выглядит вывод строкового литерала:

1_Xzi7OPpeIfbbY7eHVq2edA_1-1801-45fed7.jpeg

Как вы можете видеть, строковый литерал, в первую очередь, помещается в стек для вызова в качестве параметра printf() . Теперь давайте глянем на вывод одной из переменных:

1_FgUDPM7PmhZvRYba3XrCnw_1-1801-afcda8.jpeg

Тут можно отметить, что сначала переменная intvar пермещается в регистр EAX, который записывается в стек совместно со строковым литералом %i, применяемым для обозначения целочисленного вывода. Далее эти переменные берутся из стека и задействуются в качестве параметров при вызове printf() .

Пользовательский ввод

Теперь рассмотрим ввод пользователя посредством потока сin из C++. Но сначала глянем на наш код:

1_8AN7ZPmh6VRbtX_24d6aQg_1-1801-e57fda.jpeg

В данной функции мы лишь записываем строку в переменную sentence посредством функции C++ cin, а потом выводим предложение, используя оператор printf() .

Как это выглядит в машинном коде? Смотрим функцию cin:

1_WWi1L7WYuekqAfYoPAs2Zg_1-1801-ca388c.jpeg

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

1_ftjpKAXT8ORZPzfz7JY_fg_1-1801-4e9d7e.jpeg

Итак, программа устанавливает содержимое переменной sentence в EAX, потом помещает EAX в стек, откуда значение нашей переменной станет применяться в качестве параметра для потока cin. Далее происходит вызов оператора потока >>. Его вывод помещается в ECX, который потом перемещается в стек для оператора printf() :

1_w1oN2Ebt7QobaGbnXLTpDA_1-1801-aca148.jpeg

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

Источник

Оцените статью