Как написать программу для dos

Сохраняем получившуюся дуру под именем proga_1.asm.
Далее запускаем файл tasm.exe и в качестве параметра передаем ему имя файла с исходным текстом программы. То есть командная строка у вас (в том же Windows Commander’е) вот какая должна быть:

tasm proga_1.asm

Если вы правильно набрали текст программы, то TASM должен выплюнуть вам вот что:

Turbo Assembler Version 4.1 Copyright (c) 1988, 1996 Borland International
Assembling file: proga_1.asm
Error messages: None
Warning messages: None
Remaining memory: 406k

Самое тут главное — это чтоб «Error messages» был «None». Это значит, что ошибок в программе нет.
Поехали дальше. Если ошибок у вас действительно никаких не было, то в том же каталоге, что и proga_1.asm ищите файл proga_1.OBJ. Можете даже по F3 попробовать просмотреть его содержимое. Что-нибудь поняли? Если нет — отсылаю вас к «Введению в машинный код».
А теперь запускаем хорошую программу TLINK следующим образом:

Команды в cmd для новичков

tlink /t proga_1.obj

Обратите внимание: линкуем мы именно файл с типом OBJ, а не ASM.
Что получилось? А получился файл proga_1.COM!! И этот .COM работает!
Посмотрите на его содержимое в DZEBUG’е . Отличется ли оно чем-то от той проги, что мы делали ранее?
Нет, не отличается!
Медитируем.

#3. А теперь несколько слов о том, почему не стоит писать программы так, как мы это делали раньше:
1. Эти проклятые адреса! Пойди рассчитай на какой адрес прыгнуть нужно, с какого смещения подпрограмма начинается, с какого блок данных. В принципе, как мы уже убедились, в этом нет ничего сложного. просто занятие это очень уж муторное и неинтересное.
Как абсолютно верно заметил некто Евгений Олейников в RTFM_Helpers: «Когда я пишу программу, я не знаю точного адреса начала будущей подпрограммы».
2. Очень сложно было в том случае, когда возникала необходимость ВСТАВИТЬ ту или иную команду в середину кода. Приходилось перебивать код по новой. по новой пересчитывать адреса. ужас, в общем!
Так вот: основная и самая главная функция «ассемблерного компилятора» — это как раз и есть «просчитывание адресов»!
Смотрите, как хорошо и приятно: мы готовим исходный текст в обыкновенном текстовом редакторе . Просто набиваем строчка за строчкой — нам не важны адреса (мы их вообще не видим!), не важны «точки входа» в процедуру. Спокойненько вставляем какую надо команду, спокойненько удаляем. Без лишнего напряга!
Да вы посмотрите на блок 3 программы . Там все те же хорошо знакомые команды .
Особое внимание обратите на команду CALL, которая у нас, как известно, вызывает процедуру. После нее идет не привычный адрес начала процедуры, а всего лишь ее «имя собственное»! А сама процедура находится между строчками WINDOW proс (начало процедуры) и WINDOW endp (конец процедуры).
«WINDOW» — понятно, это «имя собственное». «Proc» — потому что процедура. «Endp» — потому что конец процедуры.

Пишем тетрис на ассемблере под DOS (x86)


Тут еще один момент. подобные «словеса» КОМАНДАМИ АССЕМБЛЕРА НЕ ЯВЛЯЮТСЯ. Они называются иначе — «директивами». Это не ПРИКАЗ делать то-то и то-то, а ЦЕННОЕ УКАЗАНИЕ компилятору (не процессору!), что и как ему делать с данным куском кода.
Процедуры — вещь хорошая! Все процедуры хороши, и в большой программе их чертовски много! Это вам не языки высокого уровня, где можно длиннющие простыни кода лабать и все будет работать! («Дельфи-компилятор не даст вам выстрелить себе в ногу, но будет так удивлен попыткой сделать это, что через некоторое время сделает это сам.» (С) DZ WhiteUnicorn).
Это ASM! Тут запутаться легче простого! Исходники неимоверно длинны и сложны! Все делается ручками (хоть и с помощью компилятора), а ошибки довольно трудно отслеживаются (для не-дZенствующих это вообще занятие безнадежное)!

Вот и выкручиваются низкоуровневые программеры таким вот образом: всю программу (даже в тех случаях, когда это не обоснованно!) делят на меленькие кусочки-процедурки. Напишут процедурку, протестируют ее так и сяк. если работает — за следующую берутся.
Сии «методы проектирования» мы с вами еще не раз рассмотрим . Пока что знайте вот что: любую прогу можно/нужно рассматривать как КУЧУ ПРОЦЕДУР, которые все между собой повязаны.
Но есть среди этих процедур САМАЯ ГЛАВНАЯ! Это та, С КОТОРОЙ НАЧИНАЕТСЯ ВЫПОЛНЕНИЕ ПРОГРАММЫ! Ее никто не вызывает. Она — босс! Она всеми командует, все гребет под себя. Описывают ее те же самые директивы, что и прочие «подчиненные процедуры».

Но есть у нас еще одна директивка, которая указывает, КАКАЯ ИМЕННО процедура ИЗ ВСЕХ вроде бы «равноправных» является ГЛАВНОЙ.
Видите строчку end MAIN в конце исходного текста программы? Именно она и указывает ГЛАВНУЮ ПРОЦЕДУРУ («MAIN» — ее имя собственное). Если бы мы написали end WINDOW, то выполнение программы у нас началось бы с первой строчки процедуры WINDOW, и ни одна строчка из MAIN выполнена не была бы.
Уф. в общем, долго и упорно медитируйте.

#4. Наличие многочисленных директив — это своего рода плата за то, что компилятор избавляет нас от необходимости просчитывать адреса. Как говорит дZенская программерская мудрость «любишь кататься, люби и саночки возить».
Как и в DZEBUG’е, «в TASM’e» мы также должны четко инструктировать компилятор (дабы он в свою очередь также четко проинструктировал процессор), что у нас является кодом, а что — данными.
Посмотрите на исходник. Весь текст программы у нас хранится между директивами CODESG segment и CODESG ends. Где CODESG — это «имя собственное», «segment» — потому что «CODESG» он, собственно, и есть сегмент , и «ends» — потому что конец сегмента. (сравните с процедурными директивами).
Но тут такой вопрос:
Директива ASSUME производит связывание сегментного решистра CS с «именем собственным».
Далее у нас следует директива org 100h. Нужна она нам для того, чтобы компилятор понял, что мы хотим получить именно COM-файл, который, как известно, помещается в сегмент памяти начиная со смещения 100 (в общем-то, это необходимое, но вовсе не достаточное условие для получения COM-файл). Директивка очень интересная, о ней мы, надеюсь, еще поговорим подробнее, когда коснемся вирмейкерства.

#5. Ладно. с директивами более-менее разобрались, исходник приготовили, пора разбираться че там дальше происходит.
Дальше происходит так называемое «ассемблирование», т.е. перевод команд в соответствующие машинные коды. При этом просчитываются адреса меток, адреса начала подпрограмм, адреса начала/конца сегментов. и многое другое.
Причем ассемблирование происходит как минимум в два приема. Посудите сами: откуда компилятору знать, с какого адреса начнется процедура WINDOW, если не известно, какая еще простыня команд ПОСЛЕ этого CALL’а будет? В DZEBUG’е мы это «в уме на листике» считали.
TASM это тоже аналогичным образом делает .
При первом проходе он подсчитывает, сколько какая команда занимает места, с каких адресов начинаются процедуры и т. д., и только при втором проходе подставляет в call’ы КОНКРЕТНЫЕ АДРЕСА начала этих процедур. всего лишь. ну еще и ваши «d» и «b» в машинные «h» (которые на самом деле «b») переводит. (во завернул!).
А вообще, TASM много еще чего делает. программеры — народ ленивый.
В результате ассемблирования мы получаем так называемый «объектный файл».
«И что это за дрянь?» — спросите вы, и правильно спросите.
А вы сравните шестнадцатеричное содержимое OBJ и COM файлов. В OBJ присутствует та же последовательность байтов, что и в OBJ. Но помимо этого и еще какая-то шестнадцатеричная ерунда присутствует: имя сассемблированного файла, версия ассемблера, «имя собственное» сегмента и т. д.
Это своего рода «служебная» информация, предназначенная для тех случаев, когда ваш исполнимый файл вы хотите собрать из нескольких. При разработке больших приложений исходный текст, как правило, хранится в нескольких файлах; в каждом из них прописаны свои сегменты кода/данных/стека. А исполнимый получить нам нужно только один — с единым сегментом кода/данных/стека. Именно это TLINK и делает: завершает определение адресных ссылок и объединяет, если это требуется, несколько программных модулей в один.
И этот один у нас и является исполнимым. УРА!

Читайте также:
Программа которая печатает свои аргументы

#6. Итак, первую прогу с использованием компилятора мы написали. Теперь напишем вторую. Набиваем ее исходный текст и компилим:

Источник: wasm.in

Изучаем язык ассемблера на примере TSR программы под MS-DOS. Часть 1

Эта серия статей посвящена изучению и практике программирования на языке ассемблера.

Материал рассчитан на новичков в ассемблере, студентов, которым пришлось столкнуться с «динозавром» в виде MS-DOS, и может быть интересен тем, кто хочет немного узнать как функционировали операционные системы на заре своего существования.

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

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

  • вывод текста вниз экрана по таймеру,
  • переключение режима отображения шрифта: italic/normal,
  • русификация,
  • запрет на ввод прописных русских букв,
  • резидентные часы,
  • вывод бинарного представления символа.

Предисловие

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

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

Немного оговорок. Далее под ассемблером будет пониматься язык ассемблера, а не программа компилятор. MS-DOS часто будет заменяться на dos/дос.

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

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

  • Ассемблер он и в Африке ассемблер, основные концепции программирования на нем будут везде одинаковы, да где-то будут расширенные регисты, где-то другой интерфейс по работе с операционной системой.
  • MS-DOS очень простая операционная система, которая в начале своего существования умещалась в 50 тысяч строк кода, причем ассемблерных (Майкрософт выложила исходники 2-х версий на github). График ее изучения имеет дно, в отличие от современных операционных систем. Аналогией может служить C и C++, последний, наверное, не знает в полной мере со всеми тонкостями ни один человек в мире.
  • Операционка работает в реальном режиме процессора, то есть в 16-битном. Это означает, что нет виртуальной памяти, адреса сразу преобразуются в физические с использованием сегментной адресаци памяти. Нет защиты процессов друг от друга, можно обратиться по любому адресу, посмотреть, что там лежит, можно делать с осью все, что тебе вздумается, но могут быть последствия ;). Плюс этот режим до сих пор не вымер, при запуске системы процессор начинает работу именно в этом режиме. Так что это не просто знакомство с историей.
  • Из предыдущего пункта понятно, что систему легко сломать, например, переписать адрес аппаратного прерывания по работе с клавиатурой, но в режиме эмуляции dos очень быстро запускается, что очень удобно в таких случаях
  • Ось очень близка к железу, есть только процессор, биос и несколько небольших модулей самой операционной системы. В отличие от современных операционок нет всяких питонов, огромного количества подсистем, которые устанешь перечислять.
  • в MS-DOS мало встроенной функциональности, она работает в режиме терминала (печатной машинки), и уже первые шаги в написании ассемблерных программ позволяют видеть пользу от них.
  • Ассемблер актуален в MS-DOS, и это радует, когда работаешь в ней, потому что иных средств разработки программ не так много там. Но в настоящее время ассемблер используется только в виде вставок в языке Си или в микроконтроллерах.
  • Простой формат бинарного файла, точнее его попросту нет. Текст программы компилируется напрямую в машинный код, и получается исполняемый файл .COM, готовый к запуску. Очень удобно начинать обучение с этого, не забивая себе голову всякими разными дерективами, секции, которые необходимы в современных форматах.

Немного про компилятор. Использоваться будет NASM, хотя логичнее было бы использовать досовские компиляторы TASM, MASM, но они не поддерживают мою рабочую операционную систему Линукс, а разрабатываться хочется все-таки в удобстве, поэтому взят nasm. Он популярный, современный, кроссплатформенный (запускается везде, компилируется подо все, включая дос), более умный — позволяет опускать какие-то вещи в синтаксисе, имеет фичи в виде локальных меток, контекстов, всяких других директив.

Настройка

Для начала нам потребуется эмулятор операционной системы DOS под названием DOSBox. Скачать можно здесь, версия 0.74-3. После установки и запуска вы увидите, что-то похожее на это:

Стартовый экран DOSBox

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

Читайте также:
Лучшая программа для чтения манги на Андроид на русском

Windows: Z:> mount c: C:UsersUsernameDesktopdos

Linux: Z:> mount c: /home/username/dos

Получаем сообщение Drive C is mounted. Теперь все содержимое папочки dos будет отображаться в диске С: в эмуляторе. Перейти в диск C с диска Z можно командой Z:>c: . Это действие придется делать каждый раз при запуске эмулятора, поэтому мы можем положить эту команду в файл конфигурации в секцию autoexec. На линуксе файл находится в /home/username/.dosbox . На виндовс C:UsersUsernameAppDataLocalDOSbox . Открываем файл dosbox-0.74-3.conf и в конец прописываем команду монтирования и перехода в диск C вот таким образом:

[autoexec] # Lines in this section will be run at startup. # You can put your MOUNT lines here. mount c: /home/username/dos c:

Hello world

Напишем первую программу на ассемблере, которая будет выводить на экран избитую фразу hello world:

org 100h mov ah, 09h mov dx, message int 21h int 20h message: db ‘Hello, world!$’

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

nasm hello_world.asm -o hello_world.com

Бинарный .com файл нужно положить в нашу папочку dos, перезапустить дос или запустить в работующем эмуляторе команду rescan, чтобы дос подхватил изменения. Запустить команду можно, начав вводить первые символы имени файла и нажав Tab. Вводить название файла целиком самостоятельно не стоит, потому что долго и потому что с файлами, у которых в имени больше 8 символов, начинаются проблемы. Регистр букв не важен. После запуска, на экране можно будет увидеть фразу Hello, world!.

Теперь о том, что делает каждая строчка, 1-я строка org 100h это указание компилятору на смещение начала инстукций, будет понятно, что это означает, когда мы рассмотрим устройство .com файла и механизм работы процессора в реальном режиме.

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

Далее идет псевдо-инструкция db (define byte), она не является инструкцией процессора, служит для того, чтобы в текущее место исполняемого файла записать блок данных побайтово. db принимает сколько угодно операндов (аргументов), разделенных запятыми. В нашем случае это один операнд, являющийся строкой из 14 символов (байт), можно было бы записать строку и посимвольно. В конце строки ставится знак $, который дает понять внутренней функции доса, что наступил конец строки. В следующей части поговорим, о том почему у нас данные находятся в конце файла.

3-5 строки подготовка для вызова прерывания 21h и непосредственно сам вызов, прерывание мы обсудим в 3-ей части, в нашем случае это попросту вызов функции операционной системы. В строке 3 мы помещаем число 09h (h значит шестнадцатиричное) в регистр ah. 09h — это номер функции.

В строке 4 записываем в dx адрес начала строки, которую хотим вывести на экран. Теперь понятно зачем нужен $, начало строки дос знает, конец нет.

В строке 5 передаем управление операционной системе с помощью прерывания, по номеру функции дос понимает, что нужно сделать (вывести строку на экран).

В строке 6 используем прерывание 20h для завершения программы, этот способ не совсем корректный, но он простой и хорошо подходит для .com программ.

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

Источник: habr.com

Реализация обработчика прерывания клавиатуры в окружении DOS

Резидентный перехватчик аппаратного прерывания клавиатуры для ДОС.

Cover Image

Сегодня мы рассмотрим, как написать простейший перехватчик прерывания под ДОС. Зачем это надо в наше время? Ответ прост — для того, чтобы лучше разобраться как работает машина на низком уровне, общего развития и расширения кругозора, ну и некоторым для написания курсачей. Возможно этот материал будет полезен желающим попробовать написать свою ОС — почему бы и нет?

Интересно? Мы начинаем!

Термины и определения

Прерывание – реакция процессора на внешнее событие, при котором приостанавливается выполнения потока команд ЦП (центральный процессор) и управление передается специальному куску кода, называемому обработчиком прерывания.

Программное прерывание – прерывание, при котором обработчик вызывается не по внешнему событию, а напрямую из основной программы. Таким образом, можно реализовать набор часто используемых подпрограмм (так работает DOS ( int 21h )).

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

Вектор прерывания – адрес ячейки памяти в которой находится адрес точки входа в обработчик прерывания (аналог указателей в Си).

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

Постановка задачи

С терминами разобрались – поехали разбираться с тем, что нам предстоит сделать. А будем делать мы резидентный перехватчик аппаратного прерывания клавиатуры для ДОС. Алгоритмы обработчика могут быть разными – это и будет «домашним заданием» и полем для экспериментов. На них останавливаться не будем – нам важны сами принципы написания такого драйвера. Об этом и продолжим.

Что нужно иметь ввиду: т.к. речь идет про ДОС, нужно понимать, что это однозадачная система (что нам на руку), т.е. никакой другой процесс (поток выполнения) не может поменять значения регистров, которые мы будем использовать в нашей программе, а это очень круто! Сразу естественный вопрос: если система однозадачная – каким образом обеспечить выполнение нашей программы в фоне (именно так «обязаны» работать драйверы)? Ответ прост – пишем резидент! Для начала определимся с планом действий, т.е. что нам нужно сделать – это определит структуру нашей программы.

  1. Запомнить системный (досовский) вектор прерывания клавиатуры;
  2. Установить этот вектор на свой обработчик;
  3. Реализовать обработчик (сам алгоритм);
  4. Остаться работать в фоне и запускать обработчик по возникновению прерывания от клавиатуры.

Структура программы на ассемблере

Уточню сразу: все нижеизложенное будет касаться ассемблеров TASM и MASM (сам использую TASM). У других ассемблеров синтаксис отличается и надо читать документацию. Для начала рассмотрим шапку программы. Выглядит она следующим образом:

.model tiny ; модель памяти .data ; Здесь описываем переменные, битовые поля и т.д. и т.п. .code ; Сегмент кода – здесь будет находиться код .startup ; Точка входа в программу end ; директива ассемблера, конец исходника с программой

Здесь нас интересует модель памяти. Дело в том, что ДОС поддерживает несколько моделей памяти: tiny , small , medium , large , huge и flat (винда).

Читайте также:
Как запретить запускать программы на компьютере

Модель памяти – способ организации сегментации памяти: сколько каких сегментов используется и какие устанавливаются между ними взаимоотношения. Нас интересует tiny – когда все сегменты (кода, данных, стека и т.п.) имеют один и тот же сгментный адрес. После ключевого слова .data описываем переменные – тут у нас будет адрес системного обработчика, текстовые сообщения и переменные, используемые в алгоритме обработчика. Переменные записываются следующим образом:

Msg db ‘А у нас сегодня кошка родила вчера котят’,10,13,’$’ MyFuckingSeg dw 0 ApocalypseCountdown dw 666

Что это такое? Для начала, разберемся с «типами данных». Тут использованы два типа: db – байт и dw – слово. Как несложно догадаться, в слове у нас 16 бит, а в байте 8. Первая запись, с текстовой строкой – массив байт.

Т.е. по адресу, по которому он будет находиться, будет шутливое предложение про кошку, затем два байта – 10 и 13 (ASCII коды символов «перенос строки» и «возврат каретки») и знак доллара. Знак доллара нам нужен для функции 09h программного прерывания ДОС ( int 21h ) – это метка конца текстовой строки. Во второй строке резервируется слово в памяти для хранения сегмента (обычное число).

Ну и третья строка – обычная переменная, с инициализированым значением – типа счетчик. С основами разобрались. Теперь рассмотрим функции программного прерывания ДОС ( int 21h ), которые нам пригодятся для реализации задуманного. Поехали (тут должна быть картинка с Гагариным).

INT 21h функция 09h

Вывод текстовой строки.

ВХОД: AH – 09h DX – смещение в сегменте данных (в нашем случае совпадает с сегментом кода) текстовой строки, завершающейся символом $ . Пример:

.model tiny .code .startup mov ah, 09h mov dx, offset Msg int 21h mov ax, 4C00h ; выход из программы int 21h Msg db ‘per aspera ad astra’,10,13,’$’ еnd

Все, теперь открываем пиво (чай, молоко, кумыс – по вкусу) – мы написали свой первый «хеллоуворлд». Откладываем кумыс в сторону, идем дальше.

INT 21h функция 02h

Функция выводит один символ на экран. Можно использовать для вывода служебных кодов ASCII.

ВХОД: AH – 02h DL – выводимый символ

INT 21h функция 4Сh

Тут мы просто выходим в ДОС и сообщаем ДОСу код завершения (применяется в BAT-файлах). Аналогично с return в Си.

ВХОД: AH – 4Ch AL – код завершения программы

INT 21h функция 35h

После вызова этой функции в регистрах ES и BX окажутся, соответственно, сегмент и смещение обработчика прерывания. Это нам пригодится для корректной передачи управления в ДОС после выполнения нашего алгоритма.

ВХОД: AH – 35h AL – номер прерывания ВЫХОД: ES – сегмент обработчика прерывания BX – смещение обработчика прерывания

INT 21h функция 25h

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

ВХОД: AH – 25h AL – номер прерывания DS – сегмент обработчика прерывания DX – смещение обработчика прерывания

INT 27h

Завершиться, но остаться резидентным

ВХОД: DX – адрес первого байта за резидентным участком программы ВНИМАНИЕ, АХТУНГ, АЛЯРМ! Не 21, а 27! Да-да, именно 27. Эта функция завершает программу, оставляя резидентную часть (обработчик прерывания) в памяти. Т.е. она, по сути, информирует ДОС, что эта область памяти занята и писать туда ничего нельзя, дабы не затереть обработчик.

Теперь перейдем к коду

Напишем скелет нашего резидента.

1. .model tiny 2. .code 3. .startup 4. 5. jmp Init 6. 7. Msg db ‘Resident module installed!’,10,13,’$’ 8. Old_09h dw 0,0 9. 10. New09h: 11. mov ah, 02h 12. mov dl, ‘A’ 13. int 21h 14. jmp dword ptr cs:Old_09h 15. 16. Init: 17. mov ah, 09h 18. mov dx, offset Msg 19. int 21h 20. mov ax, 3509h 21. int 21h 22. mov Old_09h, bx 23. mov Old_09h+2, es 24. mov ax, 2509h 25. lea dx, New09h 26. int 21h 27. lea dx, Init 28. int 27h 29. 30. end

С первыми тремя строками ясно – это шапка программы.

В пятой строке управление передается на код с меткой Init . Важно отметить, что в коде обработчик прерывания в коде располагается раньше модуля инициализации резидента – это обусловлено работой программного прерывания int 27h , в противном случае ДОС затрет обработчик, что приведёт к отстрелам ног пулеметными очередями.

С 10-й по 14-ю строку – собственно сам обработчик. Мы просто выводим на экран букву А (см. выше) и перепрыгиваем на системный обработчик прерывания 09h , чтоб не нарушать работу ДОСа и других программ, вызываемых из него.

Самое интересное тут происходит в строках 17-28, это инициализация резидента. Сначала мы выводим приветственное сообщение (17-19), затем сохраняем значение вектора системного прерывания 09h (20-23), устанавливаем свой обработчик (24-26) и выходим, оставляя резидентную часть программы в памяти (27-28).

Кульбит с адресом системного обработчика прерывания 09h (22-23) обусловлен устройством памяти у Intel . Дело в том, что Intel использует организацию памяти «младшим-вперед» — это значит, что физически первым передается младший байт ( little-endian ). Т.к. мы передаем указатель в виде СЕГМЕНТ:СМЕЩЕНИЕ , то нам надо это учитывать и передавать адрес в том виде, как это принято.

Подробнее c порядком байтов можно познакомиться тут — Википедия, да-да, именно там

Ну вот и все – мы написали наш первый резидент под ДОС. Можно вновь доставать кумыс и насладиться им в полной мере – мы это заслужили.

Реализацию алгоритма отдаю на откуп читателю, намекнув лишь, что при возникновении прерывания скан-код нажатой клавиши будет находится в порту по адресу 60h (читать – in ax, 60h ).

Так же, при нажатии и отпускании клавиши возвращается 2 сканкода, т.е. прерывание будет вызвано дважды. Наш резидент, описанный в примере выведет две буквы А вместо одной.

Ну вот и все, как говорится, Enjoy!

Ссылки на софт

  • DOS — https://www.dosbox.com
  • TASM/MASM — http://old-dos.ru/index.php?page=filesdo=showПрограммирование на Ассемблере»
  • Калашников О.А. – «Ассемблер? Это просто! Учимся программировать»
  • Нортон П. –»Язык ассемблера для IBM PC»
  • Абель П. – «Ассемблер и программирование для IBM PC»

За сим откланяюсь.

  • FreeRTOS+CLI. Реализация интерфейса командной строки используя FreeRTOSPlus-CLI.
  • Немного про ARM ассемблер. Пишем многопоточную программу.

CDEblog

Блог инженера-схемотехника, конструктора и немного программиста

Последние публикации

  • Очередной драйвер SPI флэшек… Но уже с кэшем и «нормальным» api
  • Что было интересного в январе.
  • Сжимаем образ WSL
  • Включение бинарных файлов в прошивку
  • Библиотека для Altium Designed. Как использовать библиотеку в виде базы данных.

Источник: cdeblog.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru