Top Banner
Федеральное агентство по образованию Сибирская государственная автомобильно-дорожная академия (СибАДИ) Л. Е. Олейник ЯЗЫКИ ПРОГРАММИРОВАНИЯ Для специальности 075500 "Комплексное обеспечение информационной безопасности автоматизированных систем обработки информации и управления" Учебное пособие Часть 1 ОПРЕДЕЛЕНИЕ ДАННЫХ. ДВОИЧНАЯ АРИФМЕТИКА. ЭКРАННЫЕ ОПЕРАЦИИ Омск Издательство СибАДИ 2012
138

ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

Jul 19, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

Федеральное агентство по образованию Сибирская государственная автомобильно-дорожная академия

(СибАДИ)

Л. Е. Олейник

ЯЗЫКИ ПРОГРАММИРОВАНИЯ

Для специальности 075500 "Комплексное обеспечение информационной безопасности

автоматизированных систем обработки информации и управления"

Учебное пособие

Часть 1 ОПРЕДЕЛЕНИЕ ДАННЫХ. ДВОИЧНАЯ

АРИФМЕТИКА. ЭКРАННЫЕ ОПЕРАЦИИ

Омск Издательство СибАДИ

2012

Page 2: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

2

ББК 32.973.2 УДК.681.3.06 О 53

Рецензенты: зав. кафедрой кибернетики ОМГУ,

доктор физ.-мат. наук, профессор А.К.Гуц, зав. отделом программирования ЗАО «Автоматика-Э» М.И.Федосеев

Работа одобрена редакционно-издательским советом Сибирской государственной

автомобильно-дорожной академии для специальности 075500 «Комплексное обеспечение информационной безопасности автоматизированных систем обработки

информации и управления»

Олейник Л.Е. ЯЗЫКИ ПРОГРАММИРОВАНИЯ: Учебное пособие. Часть 1. Определение

данных. Двоичная арифметика. Экранные операции. Омск: Изд-во СибАДИ, 2012.– 137 с.

Учебное пособие является первой частью комплекта пособий из 15 частей по

курсу «Языки программирования», изучаемому в СибАДИ на специальности 075500 «Комплексное обеспечение информационной безопасности автоматизированных систем обработки информации и управления».

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

и бакалавр), во-первых, при выполнении лабораторных работ по дисциплине «Языки программирования» в дисплейных классах (36 часов), во-вторых, при подготовке к практическим занятиям (10 часов) и, в-третьих, при выполнении индивидуальных заданий для самостоятельной работы (60 часов) в течение двух семестров;

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

Может также использоваться студентами специальности 220200 «Автоматизированные системы обработки информации и управления» при изучении курса «Системное программное обеспечение», а также желающими самостоятельно изучить программирование на ассемблере.

Табл. 12 Ил. 8. Библиогр.: 6 назв.

ISBN 5-93204-258-3 © Олейник Л.Е., 2012

Page 3: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

3

ОГЛАВЛЕНИЕ

Введение……………………………………………………………..…..4

1. Подготовка рабочего места к занятиям………………………….….7

2. Аудиторное занятие………………………………………………..…7

3. Задание на программирование (общая часть)……………………...15

4. Сведения, необходимые для выполнения лабораторной работы…18

5. Типичные ошибки при выполнении работы……………………….77 Примеры (тексты) программ………………………….……………..90

Приложение 1.1. Варианты формул для программирования.....…116

Приложение 1.2. Структура (схема) программы ………..………..117

Приложение 1.3. Пример лабораторной работы №1 ……...…..….122

Page 4: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

4

ВВЕДЕНИЕ

Данное учебное пособие включает: описания лабораторных работ, выполняемых на языке низкого

уровня (язык ассемблера для микропроцессоров 8086 и 80386) под управлением операционных систем MS-DOS, Windows 95 (Windows 98 или Windows 2000) и Linux;

информацию для проведения практических занятий. Состоит из 15 частей, каждая из которых содержит: – демонстрационные примеры, используемые преподавателем при

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

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

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

процессора и операционной системы (ОС) оно разрабатывается, какие директивы и команды применяются, для какого режима работы процессора (реального или защищенного), какого типа (EXE- или COM-) они должны быть, сколько модулей и сегментов должны содержать и т.п.;

– описание наиболее часто встречающихся при выполнении работы ошибок программирования;

– детальные ссылки на литературу для более подробного изучения; – примеры (тексты) программ, разработанные в соответствии с

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

лабораторной работы в классе и индивидуального задания, приведено в подразделе 1.

Перечень частей: № п/п

Название части Рассматриваемые вопросы, тип программы, количество модулей и операционная система

1 Определение данных. Двоичная арифметика. Экранные операции

Арифметические операции сложения, вычитания, умножения и деления (операции двоичной арифметики; вычисление по формуле; определение данных; логика и организация программ условные и безусловные переходы и циклы; ввод с клавиатуры и вывод на экран). EXE-программа (один модуль). ОС- MS –DOS

2 Логические операции. Условные и безуслов-ные переходы, организа-ция циклов, вызов про-

Арифметические и логические операции (И, ИЛИ, НЕ, ИСКЛЮЧАЮЩЕЕ ИЛИ; вычисление по формуле; логика и организация программ – вызов процедур near и far; использование стека;

Page 5: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

5

Продолжение таблицы № п/п

Название части Рассматриваемые вопросы, тип программы, количество модулей и операционная система

цедур, использование стека

директивы extrn, public, global). EXE-программа (два модуля). ОС – MS-DOS

3 Сдвиговые операции, данные со знаком и без знака. Ввод-вывод на диск

Арифметические и логические операции и сдвиги; логика и организация программ – циклы и переходы; вызов процедур; использование стека; включаемые файлы; ввод-вывод на диск). СОМ-программа. ОС – MS-DOS

4 Использование макро-сов и макрокоманд. Строковые команды и команды манипуляции флагами

Вычисление по формулам и сдвиги. EXE-программа (один модуль, использование макросов и макрокоманд; строковые команды, команды манипуляции флагами). ОС – MS-DOS

5 Использование условных операторов ассемблиро-вания. Директива equ

Вычисление по формулам и сдвиги. EXE-программа (один модуль, использование макросов, макроко-манд и условных операторов ассемблирования; директива equ). ОС – MS-DOS

6 Способы передачи параметров процедурам в модуле и между моду-лями

Демонстрация и опробование способов передачи процедурам в модуле и между модулями: параметра(ов) и указателя – через регистр(ы), общую ячейку, стек, в потоке кода. Передача фактических параметров макросам. Сохранение регистров в вызывающей и вызываемой процедурах. EXE-программа (два модуля; модели памяти – средняя и большая). ОС – MS-DOS

7 Оптимизация программы

Минимизация объема программы (объем опера-тивной памяти, занимаемой машинными командами, данными и стеком) либо времени выполнения про-граммы. Использование таблицы переходов, команд и возможностей МП Intel 80386. СОМ- или ЕХЕ-программа. ОС – MS-DOS

8 Определение интервала времени между события-ми. Обработка прерыва-ний, команды in и out

Определение паузы (интервала времени) между событиями. Обработка прерываний, команды in и out. EXE-программа. ОС – MS-DOS

9 Графическое приложе-ние для Windows. Вы-числения, сдвиги; ввод с клавиатуры и вывод на экран.

Вычисление по формуле (операции двоичной ариф-метики и логические операции, сдвиги; определение данных; логика и организация программ – условные и безусловные переходы и циклы; вызов процедур; ввод с клавиатуры и вывод на экран; использование стека). EXE-программа для МП Intel 80386. ОС – Windows 95/98/NT. Модель памяти – простая, соответствует директиве определения модели па-мяти .flat. Режим работы процессора – защищенный

10 Связь с программами на Смешанное программирование (связь с програм-мами на языке Pascal; встроенный ассемблер;

Page 6: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

6

Окончание таблицы № п/п

Название части Рассматриваемые вопросы, тип программы, количество модулей и операционная система

языке Pascal; ассемблер-ные врезки в программу на Pascal’e

вычисление по формуле: операции двоичной арифметики и логические операции, сдвиги; определение данных; логика и организация программ – условные и безусловные переходы и циклы; вызов процедур; ввод с клавиатуры и вывод на экран; использование стека). EXE-программа для МП Intel 8086 на языке Pascal с вставками на ассемблере. ОС – MS-DOS

11 Связь с программами на языке C++; ассемблер-ные врезки в программу на языке C++

Смешанное программирование (связь с программа-ми на языке С++; ассемблер, встроенный в С++; операции двоичной арифметики и логические опера-ции, определение данных, переходы и циклы, вызов процедур; ввод с клавиатуры и вывод на экран – средствами языка С++; сдвиги – средствами ассемблера). Режим работы процессора – реальный. EXE-программа для МП Intel 80386. ОС – MS-DOS

12 Программирование на ассемблере в среде Linux. Синтаксис AT&T

Программирование на ассемблере в среде Linux (операции двоичной арифметики и логические операции, сдвиги; ввод с клавиатуры и вывод на экран). Синтаксис AT&T. EXE-программа для МП Intel 80386. ОС – Linux

13 Резидентные программы и драйверы для MS-DOS

Разработать резидентную программу или драйвер. ОС – MS-DOS

14 Работа с файлами в базовой версии MS-DOS и Windows

Одновременная работа с несколькими файлами и несколькими областями DTA. (Назначение программы: 1) работа с файлами в базовой версии MS-DOS – ввод данных, запись в файл (прямой и последовательный доступ), чтение из файла (прямой и последовательный доступ), одновременная работа с несколькими файлами; 2) одновременная работа с несколькими областями DTA; 3) шифрование; 4) дешифрация). ЕХЕ-программа (модель памяти – компактная или большая). ОС– MS-DOS и Windows

15 Дизассемблирование программ

Восстановление текста программы по ее загрузочному модулю – COM или EXE. ОС – MS-DOS. Дизассемблер IDA Pro

Page 7: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

7

1. ПОДГОТОВКА РАБОЧЕГО МЕСТА К ЗАНЯТИЯМ

Рабочее место оборудуется персональным компьютером, на котором

для первых шести лабораторных работ достаточно: – установить операционную систему Windows 95 (или выше: Windows

98, Windows XP Edition, Windows XP Proffetional, Windows 2000 – кроме Windows Millenium);

– установить Far; – создать папку C:\assebler и поместить в нее все содержимое папки

u_m_lab1: tasm.exe, tlink.exe, rtm.exe, dpmiload.exe, dpmimem.dll и примеры: lab1pr1.asm, lab1pr2.asm, lab1pr3.asm, lab1pr4.asm, lab1pr5.asm, lab1pr6.asm, lab1pr7.asm, lab1pr8.asm и включаемые файлы: as_b_bwd.asm, bin_asci.asm, vvod_bwd.asm и l_1proc7.asm.

2. АУДИТОРНОЕ ЗАНЯТИЕ 2.1. Создание и редактирование исходного текста

программы, компиляция и выполнение программы (тренинг под руководством преподавателя)

Демонстрационные примеры приведены в подразделе 6 (примеры 1.1 – 1.9). Используются преподавателем при проведении лабораторной работы №1 в дисплейном классе и могут использоваться студентами при самостоятельном изучении.

2.1.1. Включение ПК, запуск операционной системы Windows 95, Windows 98, Windows XP или Windows 2000 (не применять Windows Millenium).

2.1.2. Вызов оболочки (пакета) Far и открытие папки C:\Assembler\u_m_lab1.

2.1.3. Ассемблирование программы lab1pr1.asm, т.е. получение объектного модуля lab1pr1.obj (в командной строке набрать и выполнить команду tasm lab1pr1.asm); компоновка (в командной строке набрать и выполнить команду tlink lab1pr1.obj) и выполнение (исполнение) полученной программы lab1pr1.exe.

2.1.4. Редактирование (встроенным редактором оболочки Far) сообщения msg в сегменте данных программы lab1pr1.asm (изменить на текст: «Привет, <любое имя>») и сохранение полученного файла под другим именем: l_pr1fio.asm (здесь fio – инициалы: первые буквы фамилии, имени и отчества).

2.1.5. Ассемблирование, компоновка и выполнение полученной программы (l_1fio.asm).

Page 8: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

8

2.1.6. Демонстрация ввода с клавиатуры байта (lab1pr2.asm), слова (lab1pr3.asm) и двойного слова (lab1pr4.asm) с акцентированием внимания на списках параметров (vvod_b, vvod_w и vvod_d), вызове процедур преобразования данных из кода ASCII (сокращенное название Американского стандартного кода обмена информацией) в двоичный код (процедуры ascii_bin_b, ascii_bin_w и ascii_bin_d), на входных и выходных параметрах этих процедур и использование полученных данных (занесение в соответствующие ячейки памяти: b1, w1, d1 и т.д.).

Здесь и ниже b1, b2,…,w1, w2, …, d1, d2, … и т.д. определены директивами db, dw и dd аналогично приведенным ниже примерам:

b0 db 10 ; определение байта (директива db); w0 dw 100 ; определение слова (директива dw); d0 dd 1000 ; определение двойного слова (директива dd).

Внимание! Пункты 2.1.7 – 2.1.10 при проведении аудиторного занятия преподаватель может порекомендовать пропустить тем студентам, кто по каким-либо причинам задержался с выполнением предыдущих пунктов! Эти пункты могут быть выполнены при самостоятельной работе над программой.

2.1.7. Редактирование сообщения mas_b1 в программе lab1pr2.asm (сначала заменить только текст на «b2= », не меняя метку) и сохранение файла под другим именем (l_pr2fio.asm). Ассемблирование, компоновка, выполнение программы.

2.1.8. Редактирование метки сообщения mas_b1 (заменить на mas_b2 в сегменте данных; заменить ссылки на метку в сегменте кода). Ассемблирование, компоновка, выполнение программы.

2.1.9. Редактирование сообщения mas_w1 в программе lab1pr3.asm (заменить текст сообщения на «w2= », в сегменте данных заменить метку на mas_w2 и в сегменте кода заменить ссылки на эту метку) и сохранение файла под другим именем (l_pr3fio.asm). Ассемблирование, компоновка, выполнение программы.

2.1.10. Редактирование сообщения mas_d1 в программе lab1pr4.asm (заменить текст сообщения на «d2= », в сегменте данных заменить метку на mas_d2 и в сегменте кода заменить ссылки на метку mas_d1 ссылками на метку mas_d2) и сохранение файла под другим именем (l_pr4fio.asm). Ассемблирование, компоновка, выполнение программы. 2.1.11. Демонстрация преобразования данных (b1, w1 и d1) из

двоичного кода в код ASCII (процедура bin_ascii) и вывод преобразованных данных на экран. Ассемблирование, компоновка, выполнение программы lab1pr5.asm.

2.1.12. Редактирование программы lab1pr5.asm (убрать списки параметров vvod_b, vvod_w и vvod_d в файл vvod_bwd.asm и процедуры ascii_bin_b, ascii_bin_w и ascii_bin_d в файл as_b_bwd.asm. Т.е. вырезать из lab1pr5.asm соответствующий фрагмент, создать файл (Shift+F4) с нужным именем, вставить в созданный файл фрагмент из буфера обмена (Ctrl+Insert) и сохранить созданный файл).

Page 9: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

9

2.1.13. Редактирование программы lab1pr5.asm (убрать процедуру bin_ascii в файл bin_ascii.asm. Т.е. вырезать из lab1pr5.asm соответствующий фрагмент, создать файл (Shift+F4) с нужным именем, вставить в созданный файл хранящийся в буфере обмена фрагмент (Ctrl+Insert) и сохранить созданный файл).

2.1.14. Редактирование программы lab1pr5.asm. Вставить в соответствующих местах программы строки с директивами:

include vvod_bwd.asm include as_b_bwd.asm include bin_ascii.asm

2.1.15. Ассемблирование программы lab1pr5.asm с получением объектного модуля (lab1pr5.obj) и листинга (т.е. файла lab1pr5.lst), компоновка и выполнение программы lab1pr5.exe. Продемонстрировать по листингу lab1pr5.lst результат выполнения директив include (вставлен текст соответствующих файлов и сформированы эквивалентные им машинные команды).

2.1.16. Ассемблирование программы, компоновка и выполнение программы lab1pr6.

2.1.17. Проверка правильности решения контрольных примеров: Таблица 2.1

№п/п b1 b2 w1 w2 d1 d2 1 1 1 1 1 1 1 2 10 10 10 10 10 10 3 100 100 1000 1000 100000 100000 4 200 200 40000 40000 2000000000 2000000000

2.1.18. Ассемблирование программы, компоновка и выполнение программы lab1pr7. Проверка правильности решения контрольных примеров:

Таблица 2.2 № п/п

b1 b2 w1 w2 № п/п

b1 b2 w1 w2

1 1 1 - - 7 - - 1000 1000 2 10 10 - - 8 - - 10000 10000 3 100 100 - - 9 100 - 10000 - 4 200 200 - - 10 2 - 60000 - 5 - - 1 1 11 100 - - 10000 6 - - 10 10 12 2 - - 60000

2.1.19. Ассемблирование программы, компоновка и выполнение программы lab1pr8. Проверка правильности решения контрольных примеров:

Page 10: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

10

Таблица 2.3

№ п/п

b1 b2 w1 d1 № п/п

b1 b2 w1 d1

1 10 10 - - 8 100 - 1050 - 2 200 10 - - 9 10 10 3 1 200 - - 10 - - 10 10000 4 100 - 100 - 11 - - 1 10000 5 100 - 10000 - 12 - - 100 1000000 6 1 - 10000 - 13 - - 100 1000050 7 2 - 7 -

2.2. Редактирование, компиляция и выполнение

демонстрационных примеров (самостоятельная проверка возможностей управления выводом на экран

в базовой версии DOS) В папке C:\assebler\u_m_lab1 создать файл l_1_fio.asm, где fio – инициалы

выполняющего работу (первые буквы фамилии, имени и отчества – латинскими буквами).

2.2.1. Проверка действия кодов перевода строки (0ah) и возврата на начало строки (0dh). Редактирование (встроенным редактором оболочки Far) сообщения msg в сегменте данных программы lab1pr1.asm (вставить эти коды перед символом $) и сохранение полученного файла под другим именем: l#pr1fio.asm (здесь fio – инициалы: первые буквы фамилии, имени и отчества).

2.2.2. Ассемблирование, компоновка и выполнение полученной программы (l#pr1fio.asm).

2.2.3. Проверка действия символа $, который в базовой версии MS-DOS является признаком окончания сообщения. Редактирование программы l#pr1fio.asm (в сегменте кода убрать команды вывода сообщения msg_e, т.е. строки с 35 по 37 включительно) и сохранение полученного файла под этим же именем: l#pr1fio.asm.

2.2.4. Ассемблирование, компоновка и выполнение полученной программы (l#pr1fio.asm). Убедиться, что сообщение «Для выхода нажмите любую клавишу» на экран не выдается.

2.2.5. Редактирование сообщения msg в сегменте данных программы l#pr1fio.asm (убрать символ $ после этого сообщения) и сохранение полученного файла под этим же именем: l#pr1fio.asm.

2.2.6. Ассемблирование, компоновка и выполнение полученной программы (l#pr1fio.asm). Убедиться, что теперь сообщение «Для выхода нажмите любую клавишу» на экран выдается: идет выдача сообщения msg до тех пор, пока не встречается символ $, а он – за сообщением msg_e.

Page 11: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

11

2.2.7. Проверка действия команд очистки экрана (выполнение необязательно). Редактирование программы l#pr1fio.asm (в сегменте кода добавить команды), т.е. после строки 28 (mov ds,ax) вставить следующие строки:

mov ax,0600h ;\ | ah=06(прокрутка),al=00(весь экран) mov bh,07 ; \ | нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; / | нижняя правая позиция int 10h ;/ | передача управления в BIOS. Сохранение полученного файла под этим же именем: l#pr1fio.asm. 2.2.8. Ассемблирование, компоновка и выполнение полученной программы

(l#pr1fio.asm). Убедиться, что перед выдачей сообщений экран очищается. 2.2.9.Проверка действия команд установки курсора. Редактирование

программы l#pr1fio.asm (в сегменте кода добавить команды), т.е. перед командами вывода сообщения msg (строка 33 и далее) вставить следующие строки:

mov ah,02 ;\ | 02 = установка курсора mov bh,00 ; \ | экран 0 mov dh,01 ; управление курсором | строка 01 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS и после команд вывода сообщения msg вставить следующие строки: mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 24 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS 2.2.10. Ассемблирование, компоновка и выполнение полученной программы

(l#pr1fio.asm). Убедиться, что сообщение msg «Привет, уважаемый пользователь» выдается в первую строку экрана, а сообщение «Для выхода нажмите любую клавишу» выдается в 24-ю строку экрана.

2.2.11. Сегмент данных сформировать аналогично примерам 1.1 (файл lab1pr1.asm) – 1.8 (файл lab1pr8.asm), определив данные для заданной формулы. Например:

datasg segment para 'Data' b1 db 1 ; определение байта (директива db) b2 db 2 ; определение байта (директива db) w1 dw 10 ; определение слова (директива dw) w2 dw 20 ; определение слова (директива dw) d1 dd 100 ; определение двойного слова (директива dd) d2 dd 200 ; определение двойного слова (директива dd) s_1 db ‘Привет’,’$’ ;определение константы (db) s_2 db ‘ ’ datasg ends 2.2.12. Отредактировать lab1pr1.asm таким образом, чтобы выдавалось

сообщение «Привет», а затем две строки: s_000 db ‘Вывожу информацию, ’ s_0000 db ‘пока не встретится символ ‘$’, и прекращаю вывод’, ‘$’

Page 12: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

12

; символ $ в базовой версии DOS означает конец строки (закончить вывод). Отредактировать lab1pr1.asm таким образом, чтобы выдавалось сообщение

s_b0, а затем – val_b0, т.е. две строки, между которыми нет перевода строки: s_b0 db ‘b0= ’ val_b0 db ‘10’, ‘$’

Аналогично, чтобы выдавалось сообщение s_w0, а затем – val_w0, s_w0 db ‘w0= ’,0ah, 0dh val_w0 db ‘100’,0ah, 0dh, ‘$’

2.2.13. Добавить в сегмент кода команды вывода на экран значений символьных констант (val_b00, val_w00, val_d00 добавить в сегмент данных): val_b00 db ‘127’, 0ah, 0dh, ‘$’ val_w00 db ‘65536’,0ah, 0dh, ‘$’ val_d00 db ‘1048536’,0ah, 0dh, ‘$’

2.2.14. Добавить в сегмент кода команды вывода на экран значений символьных констант (val_b000, val_w000, val_d000 добавить в сегмент данных): val_b000 db ‘1’, 0ah, 0dh, ‘$’ val_w000 db ‘10000’,0ah, 0dh, ‘$’ val_d000 db ‘100000’,0ah, 0dh, ‘$’

2.2.15. Добавить в сегмент кода команды преобразования и вывода на экран констант, определенных директивами db, dw, dd: val_b0_d db 15 val_w0_d dw 345 val_d0_d dd 1234567

Преобразование выполнять, вызывая процедуру bin_ascii. С клавиатуры вводить только положительные числа. 2.2.16. Используя lab1pr6.asm, создать исходный текст программы

l#1fio6.asm. Для этого отредактировать сегмент данных, вставить строки: b1 db 100 b2 db 15 w1 dw 300 w2 dw 4 d1 dd 100480

2.2.17. Используя примеры lab1pr6.asm, lab1pr7.asm и lab1pr8.asm, запрограммировать вычисление по формуле y=d1-(b1+w1/b2)*w2, т.е. добавить в сегмент кода команды:

1) деления слова на байт (w1/b2): mov ax,w1 div b2 ; al := w1/b2 mov byte ptr rezult,al ;мл.байт переменной rezult := w1/b2 ____________

Т.к. результат деления не для всех наборов данных вмещается в байт, то правильно делить следующим образом:

xor dx,dx ;\ xor bx,bx ; \ mov ax,w1 ; |w1/b2

Page 13: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

13

mov bl,b2 ; / div bx ;/ mov word ptr rezult,ax Нужно учитывать, что для деления чисел со знаком ни один из этих

вариантов не годится (см. уч. пос. «Языки программирования», ч.3). ____________

2) сложения с полученным результатом (значения переменных для примера подобраны так, что результат деления (частное) вмещается в байт (т.е. оно не превышает число 127), а результат сложения вмещается в слово, т.е. не превышает число 65535):

Вариант реализации 1: xor ah,ah ; зануляет регистр ah, но сохраняет регистр al add al,b1 adc ah,0 ; ax := b1+w1/b2 mov word ptr rezult,ax ;мл.слово переменной rezult := b1+w1/b2

Вариант реализации 2: xor ax,ax ; зануляет весь регистр ax (в т.ч. и регистр al) mov al, byte ptr rezult ; al := w1/b2 add al,b1 adc ah,0 ; ax := b1+w1/b2 mov word ptr rezult,ax ;мл.слово переменной rezult := b1+w1/b2 В примере lab1pr6.asm это показано следующим образом: xor ax,ax ;\ mov al,b1 ; | b1+b2 add al,b2 ; | adc ah,0 ; ax := b1+b2 mov word ptr rezult,ax ; rezult= ax := b1+b2 В варианте 1 отступили от приведенного в примере набора команд, чтобы сохранить регистр al.

3) умножения полученного результата на слово («слова на слово»): ; ax := b1+w1/b2 mul w2 ;(dx:ax) := ax*w2 = (b1+w1/b2)*w2 mov word ptr rezult,ax ;мл.слово произведения (rezult и rezult+1) mov word ptr rezult+2,dx ;ст.слово произвед. (rezult+2 и rezult+3)

4) вычисления разности двойного слова (d1) и полученного результата (он также размещается в двойном слове – в двух регистрах):

; (dx:ax) := ax*w2 = (b1+w1/b2)*w2 mov bx,word ptr d1 mov cx,word ptr d1+2 sub bx,ax ;мл.слово разн. := bx-ax:= ; мл.слово d1 - мл.слово (b1+w1/b2)*w2 sbb cx,dx ;ст.слово разн. := bx-ax-cf:= ; ст.слово d1 - ст.слово (b1+w1/b2)*w2 – cf

Page 14: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

14

; Таким образом, y = (cx:bx) := d1-(b1+w1/b2)*w2 mov word ptr rezult,bx ;мл. слово разности (rezult и rezult+1) mov word ptr rezult+2,cx ;ст.слово разности (rezult+2 и rezult+3) ; rezult := d1-(b1+w1/b2)*w2 В примере lab1pr6.asm: mov ax,word ptr d1 mov dx,word ptr d1+2 sub ax,word ptr d2 sbb dx,word ptr d2+2 ;/ d1- d2 mov word ptr rezult,ax ; мл. слово разности (в rezult и rezult+1) mov word ptr rezult+2,dx ; ст. слово разности (в rezult+2 и rezult+3)

5) вывода на экран вычисленного значения y. Для этого использовать процедуру bin_ascii (скопировать ее из примера lab1pr5.asm в текст программы l#1fio6.asm). Ассемблирование, компоновка, выполнение программы;

6) ввода с клавиатуры значений b1, b2, w1, w2 и d1 и преобразования их из символьного вида в двоичный. Преобразование выполнять, вызывая процедуры ascii_bin_b, ascii_bin_w и ascii_bin_d. (скопировать их из примеров lab1pr2.asm, lab1pr3.asm и lab1pr4.asm в текст программы l#1fio6.asm). Копировать после «маркирования фрагмента», Ctrl+Insert (в буфер обмена), Shift+Insert (из буфера обмена).

Примечание. Для ассемблирования программы необходимо файл с исходным текстом программы (то есть файл с расширением .asm) поместить в каталог с ассемблером (то есть с файлом tasm.exe), набрать в командной строке команду:

tasm.exe <имя файла>.asm /l и нажать клавишу Enter. В результате будет получен файл с расширением .obj (полное его имя: <имя файла>.obj). Затем с помощью программы tlink.exe необходимо получить загрузочный модуль. Для этого необходимо, чтобы в каталоге с ассемблером был файл tlink.exe и нужно в командной строке набрать команду:

tlink.exe <имя файла>.obj В результате будет получен файл с расширением .exe (полное его имя: <имя

файла>.exe). Чтобы запустить программу, следует навести курсор на полученный файл и нажать клавишу Enter.

2.3. Подготовка к выполнению индивидуального задания (создание заготовки l_1_fio.asm)

До ввода команд ввести комментарий, который показывает очередность выполнения операций: выдача сообщений, ввод данных, преобразование из символьного вида в двоичный, вычисления, преобразование из двоичного вида в символьный и т.п. (прил. 1.2) и файлы lab1pr3.asm или lab1_sa_.asm (прил. 1.3).

Page 15: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

15

3. ЗАДАНИЕ НА ПРОГРАММИРОВАНИЕ (ОБЩАЯ ЧАСТЬ) 3.1. Составить EXE-программу для МП Intel 8086 для вычисления по

формуле, содержащей арифметические операции сложения, вычитания, умножения и деления. Формулы вычислений – индивидуальны; вариант (номер формулы) взять у преподавателя, а при самостоятельном изучении – в прил. 1.1.

Таблица 3.1 Варианты используемых арифметических операций

Сложение b1+b2 w1+w2 d1+d2 b1+w1 b1+d1 w1+d1

Вычитание b1-b2 w1-w2 d1-d2 b1-w1 w1-b1 b1-d1 d1-b1 w1-d1 d1-w1

Умножение b1*b2 w1*w2 d1*d2 b1*w1 w1*b1 b1*d1 d1*b1 w1*d1 d1*w1

Деление b1/b2 w1/w2 d1/d2 b1/w1 w1/b1 b1/d1 d1/b1 w1/d1 d1/w1

3.2. Требования к программному средству, в т.ч. указание, для каких

процессора и операционной системы оно разрабатывается, какие директивы и команды применяются и т.п., приведены в табл. 3.2.

Таблица 3.2 Полный текст задания к лабораторной работе №1

Ассемблер для микропроцессора – Intel 8086 Операционная система – MS-DOS [1, с.127-128] Режим работы процессора – реальный [1, с.20-60] Тип программы – EXE [2, с.37-39; 1, с.130-131; 3, с.57-58] Назначение программы – вычисление по формуле (арифметические операции,

т.е. команды двоичной арифметики) Модель памяти – малая [1, с.112], т.е. один сегмент стека, один сегмент данных

и один сегмент кода, что соответствует директиве определения модели памяти .small [1, с.112; 4, с.45-46]

Модули – lab1_fio.asm (один сегмент стека, один сегмент данных и один сегмент кода). Файл lab1_fio.asm получается из файла lab1_sa_.asm (см. прил. 1.3; в нем предусматриваются: ввод байта и слова с клавиатуры, процедуры перевода из символьного вида в двоичное представление для байта, слова и двойного слова, процедура перевода из двоичного представления в символьный вид и вывод на экран)

Директивы: определения сегментов стандартные (полные): segment, ends и assume [1,

с.110-112; 4, с.43, 47-51];

Page 16: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

16

Продолжение табл. 3.2 -- позже: упрощенные директивы определения сегментов – – в уч. пос., ч.4; определения процедур: proc и endp [2, с.43; 1, с.115; 6, с.89]; завершения программы end [1, с.115]; определения данных: байта (db), слова (dw), двойного слова (dd); -- позже: директивы dq и dt – в уч. пос., ч.2; префиксы переопределения типов byte ptr, word ptr [1, с.121] -- позже: префикс переопределения типов dword ptr [1, с.121] – в уч.

пос.,ч.7 Команды непривилегированные:

передачи данных: mov, lea [2, с.15-17; 6, с.138]; -- позже: команды lahf, lds, les, sahf, xchg, xlat – в уч. пос., ч.7; арифметические (команды двоичной арифметики): сложения (add и adc),

вычитания (sub и sbb), увеличения на единицу (inc), уменьшения на единицу (dec), умножения (mul и imul), деления (div и idiv), преобразования байта в слово (cbw) и слова в двойное слово - cwd [1, с.225; 4, с.63-67];

-- позже: команды cwde и cdq [1, с.32] –в уч. пос., ч.7; сравнения cmp [1, с.37; 2, с.19]; безусловного (jmp) и условного (jz, jnz, js, jns) перехода [2, с.27-28]; -- позже самостоятельно: jc, jnc jcxz – в уч. пос., ч.4; jp, jnp, ja, jna, jg,

jge, jl, jle, jcxz [2, с.27-28] – в уч. пос., ч.7; организации цикла loop [1, с.47-51; 2, с.28; 7, с.74]; -- позже самостоятельно: loopz, loopnz, loope, loopne [2, с.28] – в уч. пос., ч.7; передачи управления (вызова процедур пользователя (call) и функций

операционной системы DOS (int) и возврата из процедур – ret [2, с.27-31]; -- позже самостоятельно: iret - выход из обработчика прерываний [2, с.29] –

в уч. пос., ч.8; -- позже: операторы short (8), small (16), large (32) [1, с.120] – в уч. пос., ч.7;

работы со стеком: push, pop [2, с.27-31]; -- позже самостоятельно: pushf, popf [2, с.26] – в уч. пос., ч.6;

Адресация регистр-регистр: mov ax,bx ; занести (скопировать) в ax содержимое bx [4, с.34] -- позже: mov ax,[bx] ; занести в регистр ax содержимое памяти по адресу

из регистра bx [4, с.34-40] – в уч. пос., ч.6 mov ax,[25] ; занести (скопировать) в регистр ax содержимое ячейки по смещению 25

mov al,bl ; занести (скопировать) в регистр al содержимое bl mov bx,cx ; занести (скопировать) в регистр bx содержимое cx регистр-память: mov ax,worda ; занести в регистр ax значение переменной (слова) worda mov al,bytea ; занести в регистр al значение переменной (байта) bytea mov dx,worda ; занести в регистр dx значение переменной (слова) worda память-регистр: mov worda,ax ; занести в ячейку worda содержимое регистра ax (слово)

Page 17: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

17

mov bytea,al ; занести в ячейку bytea содержимое регистра al (байт) Продолжение табл. 3.2

mov worda,cx ; занести в ячейку worda содержимое регистра cx (слово) регистр-непосредственный операнд: mov ax,25 ; занести в регистр ax значение 25 mov bx,2 ; занести в регистр bx значение 2 mov al,25 ; занести в регистр al значение 25 память-непосредственный операнд: mov worda,25 ; занести в ячейку worda значение 25 mov bytea,25 ; занести в ячейку bytea значение 25

Использование процедур операционной системы: ввод с клавиатуры [2, с.57-62]; вывод на экран. [2, с.63-67].

Дополнительная информация (рассматривается на практических занятиях): - процессоры Intel в реальном режиме [1, с.20-60]; - последовательность выполнения команд [2, с.12-13]; - структура процессора 8086 [2, с.9, рис. 1.1.2]; - сегментная адресация [2, с.9, рис.1.1.3]; - представление данных в компьютерах [1, с.14-19]; - логика и организация программ; - условные и безусловные переходы [6, с.156, 162]; - дисковая память: функции базовой версии DOS [3, гл.16].

Примеры программ: lab1pr1.asm, lab1pr2.asm, lab1pr3.asm, lab1pr4.asm, lab1pr5.asm, lab1pr6.asm, lab1pr7.asm, lab1pr8.asm, lab1_sa_.asm

Используемое ПО: tasm.exe, tlink.exe, td.exe, rtm.exe, dpmiload.exe, dpmimem.dll Формируемые файлы: lab1_fio.asm, lab1_fio.obj, lab1_fio.lst, lab1_fio.exe Литература: 1. Зубков С.В. Assembler для DOS, Windows и UNIX. – 3-е изд.,

стер. – М.: ДМК Пресс; СПб.: Питер, 2005. – 608с. 2. Бурдаев О.В., Иванов М.А., Тетерин И.И. Ассемблер в задачах защиты

информации/ Под ред. И.Ю.Жукова. – М.: КУДИЦ-ОБРАЗ, 2002. – 320с. 3. Абель Питер. Язык ассемблера для IBM PC и программирования: Пер. с

англ. – М.: Высшая школа. – 1992. – 447 с. 4. Олейник Л.Е. Язык ассемблера для микропроцессора 8086: Курс лекций. –

Омск: Сибирская региональная школа бизнеса, 2000 5. Дао Л. Программирование микропроцессора 8088. – М.: Мир, 1988. – 356 с. 6. Абель Питер. Ассемблер. Язык и программирование для IBM PC: Пер. с

англ., изд.5-е стереот. – Киев.: Век; М.: Энтроп; Киев: НТИ, 2003. – 736 с. Задание (З_ЛР_1): Составить EXE–программу для МП Intel 8086 для

вычисления по формуле, содержащей арифметические операции сложения, вычитания, умножения и деления (в соответствии с заданным вариантом)

Использовать в качестве аргументов b1,b2,...,w1,w2,...,d1,d2,...– байты, слова и двойные слова

Вари-анты:

А. Все данные (b1,b2,b3,...,w1, w2,w3,...d1,d2,d3,....) вводятся c клавиатуры после запроса (прокрутка снизу вверх)

Б. Данные (b2, b4,...,w1, w3,...,d2, d4,....) вводятся c клавиатуры после запроса (прокрутка снизу вверх), все остальные – из сегмента данных

Page 18: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

18

Окончание табл. 3.2

Применяется перевод из ASCII-формата в двоичный код (для данных, введенных с клавиатуры) и перевод из двоичного кода в ASCII-формат (для данных, выдаваемых на экран)

Результат вывести на экран по формату: Вари-

анты: А. "Вычисление по формуле:____, Y=____ для b1=__;b2=__;b3=__; b4=__;w1=___и т.д." (после очистки – в свободную строку)

Б. "Вычисление по формуле:____, Y=___ (после очистки – в строку №10)

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

заданного типа для заданного микропроцессора, состоящая из одного модуля и использующая перечисленные директивы, команды (применяющие соответствующую адресацию), заданные функции операционной системы MS-DOS и сформированы файлы, предусмотренные заданием;

- в комментариях указана максимальная длина промежуточных результатов; - при ассемблировании и компоновке не обнаружено ошибок; - результат совпадает с результатом ручного просчета для контрольных примеров

(составить самостоятельно по аналогии с пп.2.1.16, 2.1.17 и 2.1.18, а также использовать произвольно заданные преподавателем. При этом разрешается подбирать исходные данные таким образом, чтобы результат получался не отрицательным)

Типичные ошибки: см. подраздел 5 Задание повышенной сложности (ЗПС_ЛР_1): Составить EXE-программу МП

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

4. СВЕДЕНИЯ, НЕОБХОДИМЫЕ ДЛЯ ВЫПОЛНЕНИЯ ЛАБОРАТОРНОЙ РАБОТЫ

4.1. Язык ассемблера и архитектура компьютера Язык ассемблера является ориентированной на человека формой

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

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

Page 19: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

19

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

Процессор Intel 8086 представляет собой основание всей ветви процессоров серии iAPx86, и язык ассемблера, используемый для его программирования, известен как язык ассемблера процессора 8086. Программы, написанные на этом языке, могут выполняться на любом процессоре серии iAPx86. В первой главе пособия не рассматриваются инструкции, выполняемые не на всех компьютерах этого семейства. Например, не рассматриваются инструкции cwde и cdq, используемые в процессоре Intel 80386, а рассматриваются только cbw и cwd.

Кроме того, рассмотрение инструкций ограничивается архитектурой процессора 8086, и в связи с этим, например, при обсуждении инструкции mov не применяются варианты с регистрами eax, ebx, ecx и т.п.

Электронно-вычислительная машина (ЭВМ), или, по-другому, компьютер система, состоящая из пяти функциональных подсистем:

1) арифметической (сложение, вычитание, умножение, деление, операции "И", "ИЛИ", "исключающее ИЛИ" и т.д.);

2) ввода (клавиатура, "мышь", диск и т.д.); 3) управления (координация всех функций); 4) памяти (с прямым доступом для чтения и записи – ОЗУ и диск и

доступной только по чтению ПЗУ); 5) вывода (дисплей, принтер, графопостроитель, диск). Из подсистемы памяти компьютера поступают исходные значения для

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

4.2. Язык ассемблера Процессор извлекает данные из памяти, и эти данные указывают ему,

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

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

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

Page 20: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

20

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

4.3. Процессоры 8086 и 80386 Процессор Intel 8086 представляет собой только один процессор из

серии процессоров, известных как серия iAPx86. Другие процессоры данной серии: Intel 80286, Intel 80386 и т.д. Все они в дальнейшем будут обозначаться как процессоры 8086, 80286, 80386 и т.п.

4.4. Возможности процессора 8086 Процессор 8086 может адресоваться к большому объему памяти,

имеет мощный набор инструкций, при соответствующем программировании может обеспечивать работу высокоэффективных программ. Его тактовая частота – 4,77…8 мегагерц (МГц).

Тактовая частота процессора 80286 – 6…16 МГц; процессора 80386 – 16…35 МГц, и современных процессоров этой серии – более 4000 МГц, т.е. 4 ГГц.

4.5. Память Основной единицей памяти компьютера является бит. В бите может

храниться значение 0 или 1. Процессоры 8086, 80386 и др. работают с байтами, которые состоят из 8 битов.

Байт – это наименьшая единица адресации процессора. В нем может храниться 1 символ, 1 беззнаковое значение от 0 до 255 или одно значение со знаком в диапазоне от -128 до +127. Байт не подходит для хранения значений с плавающей точкой и указателей на память.

Процессор 8086 может адресоваться к памяти объемом 1 мегабайт (это 1 048 576 ячеек памяти, каждая размером 8 битов). Первый байт памяти имеет адрес 0, а последний – адрес 0fffffh.

Адрес 0fffffh – это шестнадцатеричная форма записи, о чем говорит суффикс h. В десятичном виде это эквивалентно значению 1 048 575.

В любой момент программа процессора 8086 может считать или изменить содержимое любого из 1 048 576 байтов памяти (один мегабайт – Мб). Процессор 80386 может обращаться к памяти в 4 000 раз большей. Хотя процессор 8086 может адресоваться к памяти объемом 1 Мб, но доступно для общего использования только 640 Кб (килобайт). Остальное пространство предназначено для использования системными программами, а также занято памятью, используемой для работы с дисплеем (видеопамять).

Page 21: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

21

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

4.6. Регистры В процессоре 8086 имеется несколько быстрых элементов памяти на

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

Регистры разбиваются на четыре категории: регистр флагов, регистры общего назначения, указатель инструкций и сегментные регистры.

4.7. Регистр флагов Этот 16-битовый регистр (flags) содержит всю необходимую

информацию о состоянии процессора 8086 и результатах последних инструкций (рис. 4.1).

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

o d i t s z a p c Рис. 4.1

Битовые флаги: o – флаг переполнения (другое обозначение – of); d – флаг направления, другое обозначение – df); i – флаг прерывания (if); t – флаг перехвата (tf); s – флаг знака (sf); z – флаг нуля (zf); a – флаг дополнительного переноса (af); p – флаг четности (pf); c – флаг переноса (cf).

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

Другие флаги управляют режимом операций процессора 8086. Флаг направления управляет направлением, в котором строковые

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

Регистр флагов управляется с помощью специальных инструкций (stc, std, sti, clc, cld, cli и др.), а также с помощью арифметических и логических инструкций, модифицирующих отдельные флаги. Содержимое отдельных

Page 22: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

22

разрядов регистра флагов влияет на выполнение инструкций (например, jz, rcr и movsb).

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

4.8. Регистры общего назначения Восемь регистров общего назначения процессора 8086 (каждый

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

ax 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

ah al bx

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 bh bl

cx 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

ch cl dx

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 dh dl

si 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

di

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

sp 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

bp

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Рис. 4.2

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

Page 23: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

23

приведенном ниже фрагменте программы складывается содержимое регистров:

mov ax,5 ; загрузить в регистр ax число 5 mov dx,9 ; загрузить в регистр dx число 9 add ax,dx ; поместить в регистр ax сумму регистров ax и dx

результат (14) сохраняется в регистре ax. Вместо регистров ax и dx здесь можно использовать регистры cx, si или любой другой регистр общего назначения. Рассмотрим каждый из них отдельно.

4.9. Регистр ax Регистр ax называют также накопителем (аккумулятором). Он

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

Младшие 8 битов регистра ax называются также регистром al, а старшие 8 битов – регистром ah. Это удобно при работе с данными размером в байт. Таким образом, регистр ax можно использовать как два отдельных регистра:

mov ah,0 ; загрузить в регистр ah число 0 mov al,2 ; загрузить в регистр al число 2, т.е. al:=2 inc al ; нарастить содержимое al на 1, т.е. al:= al + 1 = 2+1=3 В результате в регистре al будет записано значение 3, в регистре ah

будет записано значение 0 и, следовательно, в регистре ax будет также записано значение 3. Регистры bx, cx и dx могут аналогичным образом использоваться либо как один 16-битовый регистр, либо как два 8-битовых.

4.10. Регистр bx Регистр bx может использоваться не только для выполнения

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

mov ax,0 ; загрузить в регистр ax число 0 mov ds,ax ; загрузить в регистр ds число 0 mov bx,9 ; загрузить в регистр bx число 9 mov al,[bx] ; загрузить в регистр al содержимое адреса памяти 9 Когда bx используется в качестве указателя на ячейку памяти, то по

умолчанию из-за сегментной организации памяти процессора 8086 он ссылается на нее относительно сегментного регистра ds.

Page 24: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

24

Как и регистры ax, cx и dx, регистр bx может интерпретироваться как два 8-битовых регистра – bh и bl.

4.11. Регистр cx Специализация регистра cx – использование в качестве счетчика.

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

mov cx,10 ; cx:=10 metka:

<блок инструкций, который нужно повторить> sub cx,1 ; cx:= cx – 1 и zf:=0, если cx<>0 (т.е. cx не равен нулю) jnz metka ; если zf =0, переход на metka; иначе (т.е. zf=1) ; выполняется команда, следующая за командой jnz metka Инструкции между меткой metka и инструкцией jnz будут

повторяться до тех пор, пока содержимое регистра cx не станет равным 0. Заметим, чтобы уменьшить содержимое cx и перейти на начало цикла metka, если регистр cx еще не равен 0, здесь используются две инструкции - sub и jnz.

В процессоре 8086 используется специальная инструкция loop (инструкция цикла), которая вычитает 1 из значения регистра cx и выполняет переход, если содержимое регистра cx не равно 0. Для приведенного выше примера можно записать такой эквивалент:

mov cx,10 metka:

<блок инструкций, который нужно повторить> loop metka ;cx:=cx-1 и, если cx<>0, переход на metka, ; иначе (cx=0) – на следующую команду Регистр cx особенно полезен для использования в циклах и в качестве

счетчика. Как и регистры ax, bx и dx, регистр cx можно рассматривать как два 8-битовых регистра – ch и cl.

4.12. Регистр dx Регистр dx – это единственный регистр, который может

использоваться в качестве указателя адреса ввода-вывода в инструкциях in и out (см. уч. пос., ч.8). Единственный способ адресоваться к портам ввода-вывода с 256 по 65535 – это использовать регистр dx:

mov al,62 ; al:= 62 mov dx,1000 ; dx:= 1000 out dx,al ; вывод в порт № 1000 содержимого регистра al Другие уникальные качества регистра dx относятся к операциям

деления и умножения. Когда надо разделить 32-битовое делимое или

Page 25: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

25

использовать 16-битовый делитель, старшие 16 битов делимого должны быть помещены в регистр dx. После выполнения деления остаток также сохраняется в dx. (Младшие 16 битов делимого должны быть помещены в ax. Частное от деления также будет записано в ax). Аналогично, когда перемножаются два 16-битовых сомножителя, старшие 16 битов произведения сохраняются в dx, а младшие 16 битов записываются в ax (см. п.4.65 «Деление целых чисел без знака», п.4.66 «Беззнаковое деление 16-битового значения на 8-битовое», п.4.64 «Умножение целых чисел без знака»).

Как и регистры ax, bx и сx, регистр dx можно использовать для сложения, вычитания, логических операций и операций перемещения данных и интерпретировать как два 8-битовых регистра – dh и dl.

4.13. Регистр si Как и регистр bx, регистр si может использоваться как указатель на

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

4.14. Регистр di Регистр di также можно использовать в качестве указателя ячейки

памяти. Так же, как и регистр si, полезно использовать регистр di для ссылки на память в строковых инструкциях процессора 8086 (см. уч. пос., ч.4) Когда регистры si и di используются в качестве указателей на ячейки памяти в других инструкциях (не строковых), то они всегда адресуются к памяти относительно регистра ds. Когда регистры si и di используются в качестве указателей на ячейки памяти в строковых инструкциях, то они адресуются к памяти относительно регистра ds и es, соответственно.

4.15. Регистр bp Регистр bp также может использоваться в качестве указателя на

ячейку памяти, но регистр bp адресуется к памяти относительно регистра ss (сегментный регистр стека).

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

Стек располагается в сегменте памяти, описываемом регистром ss, а текущее смещение вершины стека записано в регистре sp, причем при записи в стек значение этого смещения уменьшается, то есть стек растет вниз от максимально возможного адреса. Таким образом, стек расположен «вверх ногами» [1, с. 22-23, п.2.1.3].

Page 26: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

26

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

push bp ; сохранить содержимое регистра bp в стек mov bp,sp ; загрузка в ax первого параметра, передаваемого mov ax,[bp+4] ; при вызове подпрограммы на ассемблере.

4.16. Регистр sp Регистр sp называется также указателем стека, он в каждый момент

времени указывает на вершину стека. Вершина стека – это то место, в котором в стеке сохраняется помещаемое туда значение. Занесение значений в стек выполняется инструкцией push. Извлечение значений из стека выполняется инструкцией pop.

Рассмотрим, как изменяются регистры sp, ax и bp по мере выполнения следующего кода:

mov ax,1 ; ax:=1 push ax ; в стек заносится 1, и sp уменьшается на 2; mov bx,2 ; bx := 2 push bx ; в стек заносится 2, и sp уменьшается на 2 pop ax ; ax := 2, и sp увеличивается на 2 pop bx ; bx := 1, и sp увеличивается на 2 Хотя процессор 8086 и позволяет записывать значения в sp или

складывать и вычитать хранящиеся в регистре sp значения (как с регистрами общего назначения), лучше этого не делать!

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

4.17. Указатель инструкций (регистр ip) Регистр ip всегда содержит смещение в памяти, по которому хранится

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

Рис. 4.3 После выполнения инструкции указатель обычно перемещается на

следующую за ней инструкцию, но некоторые инструкции (к ним

cs

Команда

ip

Сегмент кода

Page 27: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

27

относятся вызовы процедур – call, переходы – jmp и jcc, циклы – loop, возврат из процедур – ret) могут привести к тому, что в ip будет загружено новое значение и выполнен переход на другой участок программы.

Значение регистра ip нельзя прочитать или записать непосредственно. Базовый адрес хранится в регистре cs, при этом указатель инструкций

задает смещение относительно этого базового адреса. 4.18. Сегментные регистры

Наиболее необычный аспект процессора 8086 – сегментация памяти. Предпосылкой сегментации является то, что процессор 8086 может адресоваться к 1 мегабайту памяти, а для этого необходимы 20-разрядные сегментные регистры.

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

Для этого значение сегмента сдвигается влево на 4 (то есть умножается на 16), а затем складывается со смещением.

Рассмотрим, например, следующий фрагмент программы: mov ax,1000h mov ds,ax ; загрузка в ds значения 1000h mov si,201h ; загрузка в si значения 201h mov dl,[si] Регистры ds и si можно представить в виде "сегмент:смещение" –

1000:201h. Адрес, из которого загружаются данные, представляет собой ((ds * 16) + si ) или ((1000h * 16) + 201h)

Программа получает доступ к полному адресному пространству в 1Мб только при использовании пары "сегмент:смещение".

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

Рис. 4.4

Сегмент данных ds

Данные

si

Page 28: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

28

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

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

Только блок памяти размером в 64 Кб может адресоваться через сегментный регистр, так как это максимальный объем памяти, к которой можно адресоваться с помощью 16-битового смещения. Это может оказаться неудобным при работе с большим (более 64 Кб) объемом памяти, так как и значение сегментного регистра, и смещение придется часто изменять.

Кроме того, единственная операция, которую можно выполнять с сегментными регистрами, состоит в копировании значений между сегментным регистром и каким-либо общим регистром или стеком (п. 4.72). Например, чтобы добавить значение 100 к регистру es, требуется следующее:

mov ax,es add ax,100 mov es,ax Второй момент: каждая ячейка памяти адресуется через многие

сочетания "сегмент:смещение". Например, адрес памяти 100h образуется с помощью следующих значений "сегмент:смещение": 0:100h, 1:f0h, 2:e0h и т.д., так как при вычислении всех этих пар "сегмент:смещение" получается значение адреса 100h.

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

4.19. Регистр cs Регистр cs указывает сегмент кода, в котором находится следующая

выполняемая инструкция. Она находится (рис. 4.5) по смещению, определяемому в сегменте кода регистром ip, на нее указывает адрес cs:ip. 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 cs 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ip

Рис. 4.5

Page 29: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

29

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

Никакие другие режимы адресации и никакие указатели памяти, отличные от ip, не могут нормально работать относительно регистра cs.

4.20. Регистр ds Регистр ds указывает на начало сегмента данных, в котором находится

большинство размещенных в памяти операндов. Обычно для ссылки на адреса памяти используются смещения, предполагающие использование регистров bx, si или di. Сегмент данных – это сегмент, в котором находится текущий набор данных.

4.21. Регистр es Регистр es указывает на начало блока памяти объемом 64 Кб, который

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

необходимость. Иногда он используется для выделения дополнительного

Данные

Данные

Данные

ds

si Сегмент данных

di

bx

Рис. 4.6

Рис. 4.7

Дополнительный сегмент данных es

Данные

di

Page 30: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

30

блока памяти объемом 64 Кб для данных. Однако доступ к памяти в дополнительном сегменте менее эффективен, чем доступ к памяти в сегменте данных.

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

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

4.22. Регистр ss Регистр ss указывает на начало сегмента стека, т.е. на блок памяти

объемом до 64 Кб, в котором находится стек. Все инструкции, которые неявно используют регистр sp (включая занесение в стек, извлечение из стека, вызовы и возвраты управления), работают с сегментом стека, так как только регистр sp может использоваться для адресации памяти в сегменте стека.

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

4.23. Директивы определения сегментов В ассемблере предусмотрены два набора директив управления

сегментами: 1) из упрощенных директив определения сегментов (делает

управление сегментами относительно легким и идеально подходит для компоновки модулей ассемблера с языками высокого уровня, но поддерживает только некоторые из сегментных средств, имеющихся в ассемблере);

Рис. 4.8

bp

ss Сегмент стека

Данные

sp

Данные

Page 31: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

31

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

В зависимости от того, сколько и каких сегментов предусматривается в программе, различают следующие модели памяти.

Сверхмалая (tiny) – код программы и ее данные должны размещаться внутри одного и того же сегмента размером 64 Кб. Код и данные имеют ближний тип (см. уч. пос., ч.3 и 7).

Малая (small) – код программы должен размещаться внутри одного сегмента данных размером 64 Кб, а данные – в отдельном сегменте данных (размером 64 Кб). И код, и данные должны быть ближнего типа (см. уч. пос., ч.4 и 5).

Средняя (medium) – код программы может превышать 64 Кб, но данные должны помещаться в один сегмент размером 64 Кб. Код имеет дальний тип, а данные – ближний (см. уч. пос., ч.2 и 6).

Компактная (compact) – код программы должен помещаться в один сегмент размером 64 Кб, а данные могут превышать по размеру 64 Кб. Код имеет ближний тип, а данные должны быть дальнего типа (см. уч.пос., ч.14).

Большая (large) – код и данные программы могут превышать 64 Кб, но один массив данных не может превышать 64 Кб. И код и данные имеют дальний тип (см. уч. пос., ч.14).

Сверхбольшая (huge) – код и данные могут превышать по размеру 64 Кб. Массивы данных также могут превышать 64 Кб. Код и данные имеют дальний тип. Указатели на элементы массива также дальнего типа (см.п.4.58; уч. пос., ч.14; 1, с. 112).

4.24. Стандартные директивы определения сегментов Приведем пример программы, использующей стандартные директивы

определения сегментов segment, ends и assume. stacksg segment para stack 'stack'

db 200h dup (?) stacksg ends datasg segment para 'data' HelloMessage db 'Привет!',13,10,'$' datasg ends codesg segment para 'code'

assume cs:codesg, ds:datasg, ss:stacksg ProgramStart:

mov ax,datasg

Page 32: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

32

mov ds,ax ; установить ds в значение сегмента данных mov dx,offset HelloMessage ;ds:dx указывает на сообщение 'Привет!' mov ah,9 ; функция DOS вывода строки int 21h ; вывести строку на экран mov ah,4ch ; функция DOS завершения программы int 21h ; завершить программу

codesg ends end ProgramStart

4.25. Директива segment Директива segment определяет начало сегмента. Метка, которая

указывается в данной директиве, определяет начало сегмента. Например, директива:

codesg segment определяет начало сегмента с именем codesg. Директива segment может также (необязательно) определять атрибуты сегмента, включая выравнивание в памяти на границу байта, слова, двойного слова, параграфа (16 байтов) или страницы (256 байтов). Другие атрибуты включают в себя способ, с помощью которого сегмент будет комбинироваться с другими сегментами с тем же именем и классом сегмента.

4.26. Директива ends Директива ends определяет конец сегмента. Например: codesg ends

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

4.27. Директива assume Директива assume указывает, в значение какого сегмента установлен

данный сегментный регистр. Директиву assume cs: требуется указывать в каждой программе, в которой используются стандартные сегментные директивы, так как ассемблеру необходимо знать о сегменте кода для того, чтобы установить выполняемую программу. Кроме того, обычно используются директивы assume ds: и assume es:, благодаря которым ассемблер знает, к каким ячейкам памяти можно адресоваться в данный момент.

Директива assume позволяет ассемблеру проверить допустимость каждого обращения к именованной ячейке памяти с учетом значения текущего сегментного регистра. Рассмотрим следующий пример:

Data1 segment para 'Data' Var1 dw 0

Page 33: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

33

Data1 ends Data2 segment para 'Data' Var2 dw 0 Data2 ends Codesg segment para 'Code'

assume cs:Codesg ProgramStart:

mov ax,Data1 mov ds,ax ; установить ds в Data1 assume ds:Data1 mov ax,[Var2] ; попытаться загрузить Var2 в ax (это приведет к

; ошибке, так как Var2 недоступна в сегменте Data1) mov ah,4ch ; номер функции dos для завершения программы int 21h ; завершить программу

Codesg ends end ProgramStart

Ассемблер отмечает в данной программе ошибку, так как в ней делается попытка получить доступ к переменной памяти Var2, когда регистр ds установлен в значение сегмента Data1 (к Var2 нельзя адресоваться, пока ds не будет установлен в значение сегмента Data2).

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

Например: mov ax,0b800h mov ds,ax assume ds:nothing

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

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

Data1 segment para 'Data' Var1 dw 0 Data1 ends Data2 segment para 'Data' Var2 dw 0 Data2 ends Codesg segment para 'Code'

Page 34: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

34

assume cs:Codesg ProgramStart:

mov ax,Data1 mov ds,ax ; установить ds в Data1 assume ds:Data1 mov ax,Data2 mov es,ax ; установить es в Data2 assume es:Data2 mov ax,[Var2] ; загрузить Var2 в ax

; ассемблер укажет процессору 8086, что загрузку нужно выполнять ; относительно es, т.к. к Var2 нельзя получить доступ относительно ds

mov ah,4ch ; функция dos завершения работы программы int 21h ; завершить программу

Codesg ends end ProgramStart

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

mov ax,[Var2] для доступа к Var2 относительно сегментного регистра es, а не ds.

Это происходит потому что регистр ds установлен в значение сегмента Data1, а es установлен в значение сегмента Data2. Ассемблер совершенно правильно заключает, что к Var2 нельзя получить доступ относительно регистра ds, однако Var2 доступно относительно сегментного регистра es. В итоге ассемблер включает перед инструкцией mov специальный код (префикс переопределения сегмента), чтобы указать процессору 8086, что вместо сегментного регистра ds нужно использовать регистр es.

Таким образом, если вы корректно используете директивы assume, позволяя ассемблеру узнать о текущих установленных для регистров ds и es значениях, то он в некоторых случаях даже может выполнить автоматическую корректировку сегмента.

4.28. Директива end Директива end отмечает конец исходного кода программы. Все

строки, которые следуют за нею, ассемблером игнорируются. Например: stacksg segment para ‘Stack’

db 200h ; стек объемом 512 байтов stacksg ends datasg segment para ‘Data’ ; начало сегмента данных datasg ends codesg segment para ‘Code’ ; начало сегмента кода

Page 35: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

35

main proc far assume cs:codesg, ds:datasg, ss:stacksg

mov ax,datasg mov ds,ax ; ds указывает на сегмент данных datasg mov ah,4ch int 21h

main endp codesg ends

end main Это простейшая программа на ассемблере. Она ничего не делает,

просто немедленно возвращает управление DOS. Кроме завершения программы, директива end может указывать, где

должно начинаться выполнение при запуске программы (с метки main). Иногда требуется начать выполнение программы в файле .exe не с первой инструкции. Директива end предусматривает такие случаи. Например:

stacksg segment para ‘Stack’ db 200h ; стек объемом 512 байтов

stacksg ends datasg segment para ‘Data’ ; начало сегмента данных datasg ends codesg segment para ‘Code’ ; начало сегмента кода Delay proc

mov cx,60000 DelayLoop:

loop DelayLoop ret

Delay endp main proc far

assume cs:codesg, ds:datasg, ss:stacksg ProgramStart:

mov ax,datasg mov ds,ax ; ds указывает на сегмент данных datasg call Delay ; пауза на время, необходимое для выполнения 64

циклов mov ah,4ch int 21h

main endp codesg ends

end ProgramStart Выполнение здесь начинается не на первой инструкции исходного

кода (mov cx,60000) по метке Delay. Вместо этого выполнение начинается

Page 36: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

36

с инструкции mov ax,datasg по метке ProgramStart, как определено в директиве end. И уже в процессе выполнения этой процедуры вызывается процедура, обеспечивающая временну'ю задержку call Delay.

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

4.29. Основные элементы программы на языке ассемблера Теперь можно назвать детали программирования:

– основные компоненты программы; – минимальные требования к программе; – способы, с помощью которых программа может получить доступ к

памяти; – определение и использование сегментов; – выделение и использование переменных в памяти; – наиболее общеупотребительные инструкции. 4.30. Элементы и структура программы на языке ассемблера

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

stacksg segment para ‘Stack’ db 200h ; стек объемом 512 байтов (200h)

stacksg ends datasg segment para ‘Data’ ; начало сегмента данных DisplayString db 13,10 ; символы "возврат каретки/перевод строки" ThreeChars db 3 dup (?) ; память для трех введенных символов

db '$' ; символ $, указывающий DOS, где ; завершить вывод строки DisplayString

datasg ends codesg segment para ‘Code’ ; начало сегмента кода main proc far

assume cs:codesg, ds:datasg, ss:stacksg mov ax,datasg mov ds,ax ; ds указывает на сегмент данных datasg mov bx,offset ThreeChars ; указывает на ячейку с первым символом mov ah,1 ; функция DOS ввода с клавиатуры int 21h ; получить следующую нажатую клавишу

Page 37: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

37

dec al ; вычесть из символа 1 mov [bx],al ; сохранить измененный символ inc bx ; указать на ячейку памяти, где содержится следующий символ inc 21h ; получить следующую нажатую клавишу dec al ; вычесть из символа 1 mov [bx],al ; сохранить измененный символ inc bx ; ссылка на ячейку памяти со следующим символом int 21h ; получить следующую нажатую клавишу dec al ; вычесть из символа 1 mov [bx],al ; сохранить измененный символ mov dx,offset DisplayString ; ссылка на строку измененных символов mov ah,9 ; функция DOS вывода строки int 21h ; вывести измененные символы mov ah,4ch ; функция DOS завершения int 21h ; программы ret

main endp codesg ends

end main ; конец кода и указание на входную точку Данная программа содержит стандартные директивы определения

сегментов стека, данных и кода, а также директиву end. В каждой программе на ассемблере, чтобы обеспечить определение сегментов и управление ими, необходимы директивы определения сегментов (стандартные, как в приведенном выше примере, или упрощенные – см. уч. пос., ч.4), а завершать программу на ассемблере всегда должна директива end. Директивы представляют собой только "рамки" программы на ассемблере. В самой программе необходимы также строки исходного кода, выполняющие какие-либо действия. Что делает программа, приведенная в примере? Введите ее, получите объектный файл и выполняемую программу, запустите, наберите “IBM”, после чего программа ответит Вам: “hal”

4.31. Формат строки Строки исходного кода на языке ассемблера имеют следующий

формат:

[<метка>] <инструкция/директива> [<операнды>] [<;комментарий>]

где <метка> представляет собой необязательное имя идентификатора; <инструкция/директива> – мнемоника инструкции или директивы;

Page 38: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

38

<операнды> – содержат сочетание 0, 1 или 2 (иногда более) констант, ссылок на регистры, или на память, или на текстовые строки, как это требуется в каждой конкретной инструкции или директиве;

<;комментарий> – необязательный комментарий. Рассмотрим каждый из этих элементов более подробно.

4.32. Метки Метки – это имена, используемые в программе для ссылки на числа и

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

A – Z a – z _ @ $ ? 0 – 9 Цифры 0 – 9 не могут использоваться в качестве первых символов

метки. Символы $ и ? имеют специальное значение, поэтому их не следует использовать в идентификаторах.

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

Метка может занимать всю строку, то есть на этой строке, кроме метки, может отсутствовать инструкция или директива. В этом случае значением метки является адрес инструкции или директивы, расположенной на следующей строке программы. Например, во фрагментах программы 1) и 2):

1) jmp formula1 2) jmp formula1 . . . . . .

formula1: formula1: add ax, dx add ax,dx . . .

следующей инструкцией, выполняемой после инструкции jmp, которая выполняет переход на метку formula1, является инструкция add ax,dx.

Преимущества размещения метки на своей собственной строке: 1) удается использовать длинные метки без нарушения формата

программы; 2) легче добавить новую инструкцию (не надо разделять строку). Метка не может совпадать с любым из используемых в выражениях

встроенных символов, включая имена регистров (ax, bx и т.д.) и операторы, используемые в выражениях (ptr, byte, word и т.д.). В качестве меток нельзя также использовать любую из директив .ifxxx или .errxxx. Несколько других зарезервированных в ассемблере идентификаторов могут использоваться только в определенных контекстах. Эти идентификаторы включают в себя name, include и comment.

Page 39: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

39

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

cmp al,'a' jb NotALowerCaseLetter ; не строчная буква cmp al,'z' ja NotALowerCaseLetter sub al,20h ; преобразовать в верхний регистр (прописную букву)

NotALowerCaseLetter: . . .

метка NotALowerCaseLetter определена с двоеточием, но в ссылках на эту метку двоеточие не указывается.

Могут быть метки, которые не должны завершаться двоеточием. В примерах программы (пп.4.30, 4.45 и 4.56) содержатся несколько меток без двоеточий (DisplayString и ThreeChars в п.4.30, vvod_b в п.4.45 и KeyBuffer в п.4.56).

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

cmp al,'a' jb P1 cmp al,'z' ja P1 sub al,20h ; преобразовать в верхний регистр

P1: . . . Вариант с описательной меткой гораздо более понятен. Метки могут

содержать символы подчеркивания. Можно использовать метки типа not_a_lower_case_letter, или Not_A_Lower_Case_Letter, или NotA_LowerCaseLetter.

4.33. Мнемоники инструкций и директивы Основным полем в строке программы на ассемблере является поле

<инструкция/директива>. Это поле может содержать мнемонику инструкции или директиву.

Мнемоники инструкций представляют собой удобные для чтения имена инструкций, непосредственно выполняемых процессором 8086. Например, mov, add, mul и jmp – это мнемоники инструкций, соответствующие инструкциям процессора 8086 перемещения данных, сложения, умножения и перехода соответственно. Ассемблер преобразует

Page 40: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

40

каждую мнемонику инструкции непосредственно в соответствующую инструкцию на машинном языке.

В отличие от мнемоник инструкций, директивы совсем не генерируют выполняемого кода. Вместо этого они управляют различными аспектами работы ассемблера – от типа ассемблируемого кода (процессоры 8086, 80286, 80386 и т.д.) до используемых сегментов и формата создаваемых файлов листингов. Имеется несколько директив, которые необходимы в любой программе на ассемблере (segment, ends, assume и end; см.пп.4.25–4.28).

4.34. Операнды Мнемоники инструкций и директивы сообщают ассемблеру, что

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

Для инструкций требуются 0, 1, 2 или более операндов. Возможные операнды включают в себя регистры, константы, метки, переменные в памяти и текстовые строки. Инструкция с одним операндом выполняет операции с этим операндом. Например:

push ax заносит регистр ax в стек. Инструкции без операндов еще более очевидны. В случае инструкции с двумя операндами один является источником, а другой – приемником. Когда процессор выполняет инструкцию

mov ax,bx то содержимое регистра bx помещается (копируется) в регистр ax.

4.35. Регистровые операнды Наиболее часто используются регистровые операнды. Регистры могут

использоваться в качестве источника (исходный операнд) или приемника (целевой операнд) и могут даже содержать адрес, на который нужно выполнить переход. С регистрами можно делать много того, чего нельзя делать с константами, метками или переменными в памяти. Имеются некоторые инструкции, в которых можно использовать только регистровые операнды. Примеры регистровых операндов:

1) mov bx,ax ;bx:=ax 2) push ds ; занести в стек содержимое регистра ds 3) xchg al,dl ;al:=dl и dl:=al 4) mov cl,5 ror dx,cl ; циклический сдвиг регистра dx на 5 битов вправо

5) in al,dx ; из порта с номером в dx ввод байта в регистр al 6) inc si ;si:=si+1

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

Page 41: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

41

mov al,1 ; al := 1 add BaseCount,cx ; BaseCount := cx cmp si,[bx] ; сравнение (из содержимого регистра si вычесть

; значение слова по адресу, взятому из регистра bx, и установить флаги). Если имеется два операнда и регистровым операндом является правый

операнд, то он будет исходным регистром (источником), а если регистровым операндом является левый операнд – то это целевой регистр (приемник). Если в инструкции требуется два источника, то один из регистров является и источником и приемником (левый операнд). Например, во фрагменте программы:

mov cx,1 ; загрузить в сх значение 1 mov dx,2 ; загрузить в dх значение 2 sub dx,cx ; dx:=dx-cx= 2-1= 1

из регистра dx вычитается cx, и результат (1) снова записывается в регистр dx. В инструкции sub регистр cx является правым операндом (источник), dx – левый операнд (второй источник и приемник). Действие данной инструкции – "вычесть cx из dx".

4.36. Операнды-константы Часто в операндах требуется использовать постоянное значение.

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

met1: sub si,4 ; si := si - 4 jnz met1 В качестве постоянных операндов (операндов-констант) можно

использовать также символы, поскольку символ представляет собой определенное значение. Например, так как символ a имеет десятичное значение 65, то инструкция sub al,’a’ и инструкция sub al,65 эквивалентны.

Постоянные значения можно задавать в двоичном, восьмеричном или шестнадцатеричном представлении, а также в десятичном виде.

При использовании двух операндов операнды-константы никогда не могут располагаться слева, так как невозможно использовать константу в качестве операнда-приемника. Ограничение: невозможно занести константу (например, 5) непосредственно в стек – можно только через регистр (это ограничение касается только процессоров 8086/8088):

mov ax,5 ; ax := 5 push ax ;занести содержимое ax в стек

4.37. Операнды-метки

Page 42: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

42

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

; сегмент данных MemWord dw 1 ; директива определения слова ; сегмент кода

. . . mov al, size MemWord ; al:=2 Здесь метка используется в операции size, в результате значение 2

(размер в байтах переменной MemWord) помещается в al. Метки могут также использоваться в качестве целевых операндов в

операциях call, jmp. Например, во фрагменте программы: cmp ax,100 ; zf:=1, если (ax-100) =0 ; zf:=0, если (ax-100) <> 0, т.е.не равно нулю jz met2 . . .<какие-либо команды>

met2: . . .

инструкция jz используется для перехода по адресу, заданному операндом met2, если значение ax равно 100. Здесь метка задает адрес перехода.

Наконец, метки можно использовать в качестве операндов почти так же, как используются регистры, то есть как операнд-источник (TempVar в инструкции sub) или операнд-приемник (TempVar в инструкции mov):

; сегмент данных TempVar dw ? ; сегмент кода . . .

mov TempVar,ax ; ячейке TempVar присвоить значение регистра ax sub ax,TempVar ; ax:= ax–TempVar (обнуление регистра) Как задать ячейку памяти, с которой хотите работать? Очевидно,

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

; сегмент данных Assets dw ? Debts dw ? ; сегмент кода

. . . mov ax,Debts sub Assets,ax

Page 43: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

43

Предположим, имеется строка CharString, содержащая буквы abcdefghijklm, которые начинаются в сегменте данных со смещения 100. Как прочитать девятый символ (i), который расположен по адресу 108?

Язык ассемблера обеспечивает несколько способов адресации к строкам символов, массивам и буферам данных. Наиболее простой способ:

datasg segment para ‘Data’ ; начало сегмента данных CharString db 'abcdefghijklm' datasg ends codesg segment para ‘Code’ ; начало сегмента кода main proc far

. . . mov ax,datasg mov ds,ax mov al,CharString+8 Смещение CharString и 8 складываются, а полученное значение

используется в качестве адреса памяти. Непосредственная адресация (когда ячейка памяти задается ее именем

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

Имеется другой, более гибкий путь адресации памяти. Например: mov bx, offset CharString+8 ; bx := смещение CharString плюс 8 mov al,[bx] ; процессор обращается по адресу из регистра bx. Здесь для ссылки на девятый символ используется регистр bx.

(Вычисление offset и сложение с константой 8 выполняется во время ассемблирования). Затем в al загружается содержимое ячейки памяти, на которую указывает bx.

Квадратные скобки показывают, что в качестве операнда-источника должна использоваться ячейка, на которую указывает регистр bx, а не сам регистр bx. Например:

mov ax,[bx] ;а) ax:= содержимое ячейки, на которую указывает bx mov ax,bx ;б) ax:= содержимое регистра bx

это две совершенно различные инструкции. А зачем сначала загружать в регистр bx смещение ячейки памяти и

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

Если требуется определить последний символ строки CharString, необходимо, начиная с первого символа строки CharString, найти

Page 44: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

44

завершающий строку нулевой байт, затем вернуться назад на один символ и считать этот символ. Это невозможно с непосредственной адресацией. Использование bx значительно облегчает задачу:

mov bx,offset CharString ; указывает на строку Char String FindLastCharLoop:

mov al,[bx] ; получить следующий символ строки cmp al,0 ; это нулевой байт? jz FoundEndOfString ; да, bx указывает на ноль в конце строки inc bx ; bx:= bx+1 jmp FindLastCharLoop ; проверить следующий символ

FoundEndOfString: dec bx ; bx:= bx-1 снова указывает на последний символ mov al,[bx] ; получить последний символ строки (перед нулем) Это очень удобно для поиска символов или слов в строке, при работе с

элементами массивов, при копировании блоков данных. Регистр bx – это не единственный регистр, который можно

использовать для ссылки на память. Допускается также использовать регистры bp, si и di вместе с необязательным значением – константой или меткой. Общий вид операндов в памяти выглядит следующим образом:

[базовый регистр + индексный регистр + смещение] где базовый регистр – это bx или bp, индексный регистр – si или di, а

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

Таблица 4.1 (bx или bp) + (si или di) база индекс + смещение

Существует 16 способов задания адреса в памяти: Таблица 4.2

№ п/п

Задание адреса № п/п

Задание адреса № п/п

Задание адреса

1 [смещение] 7 [di] 13 [bp+si] 2 [bp+смещение] 8 [di+смещение] 14 [bp+si+смещение] 3 [bx] 9 [bx+si] 15 [bp+di] 4 [bx+смещение] 10 [bx+si+смещение] 16 [bp+di+смещение] 5 [si] 11 [bx+di] 6 [si+смещение] 12 [bx+di+смещение]

Смещение – это то, что можно свести к 16-битовому постоянному значению.

Page 45: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

45

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

datasg segment para ‘Data’ ; начало сегмента данных CharString db 'abcdefghijklm',0 datasg ends codesg segment para ‘Code’ ; начало сегмента кода main proc far

mov ax,datasg mov ds,ax . . . А затем идет набор инструкций по одному из вариантов (табл.4.3).

Таблица 4.3 mov bx,8 ; способ 1 mov bx, offset CharString ; способ 5 mov al,[Charstring+bx] mov di,8 mov al,[bx+di] mov si,8 ; способ 2 mov bx, offset CharString ; способ 6 mov al,[CharString+si] mov si,7 mov al,[bx+si+1] mov bx,3 ; способ 3 mov si,offset CharString+8 ; способ 7 mov si,5 mov al,[si] mov al,[bx+CharString+si] mov bx,8 ; способ 4 mov bx, offset CharString ; способ 8 mov si, offset CharString mov al,[bx+8] mov al,[si+bx]

Все эти инструкции ссылаются на одну и ту же ячейку памяти [CharString]+8.

Во время ассемблирования ассемблер складывает все константы внутри квадратных скобок, поэтому инструкция mov [10+bx+si+100],cl принимает вид mov [bx+si+110],cl

При реальном выполнении инструкции операнды в памяти складываются процессором. Если bx содержит значение 25, а si содержит 52, то при выполнении содержимое cl записывается по адресу памяти 25 + 52 + 110 = 187. Ассемблер складывает константы во время ассемблирования, а процессор 8086 складывает содержимое базового регистра bx, индексного регистра si и смещения 110 во время действительного выполнения инструкции.

Заметим, что регистр bx используется как смещение внутри сегмента данных, а регистр bp используется как смещение в сегменте стека. Т.е. регистр bp не может использоваться для адресации к строке CharString, которая находится в сегменте данных.

Page 46: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

46

Регистр bp можно использовать так же, как использовался bx, только адресуемые данные должны находиться в стеке.

4.38. Комментарии Один из способов включения в код ассемблера комментариев состоит

в том, чтобы справа от каждой инструкции помещать комментарий, в котором содержится ее краткое пояснение. Например:

mov [bx],al ; сохранить измененный символ Не обязательно комментировать каждую строку. Например:

mov ah,1 int 21h ; получить следующую клавишу Целью комментариев является не объяснение каждого элемента

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

блоков кода строк-комментариев. Такие комментарии могут описывать работу программы на более высоком уровне, чем комментарии отдельных строк. Например:

; Сгенерировать для буфера передачи байт контрольной суммы mov bx,offset TransferBuffer mov cx,transfer_buffer_length sub al,al ; очистить аккумулятор контрольной суммы CheckSum: add al,[bx] ; добавить в него текущее значение байта inc bx ; указать на следующий байт В комментарии к этому блоку кратко суммируется его работа, поэтому

тот, кто будет просматривать программу, больше полезного извлечет из комментариев к блокам, чем из комментариев к строкам.

Третий метод состоит во включении перед каждой подпрограммой описательного заголовка-комментария ("шапки" программы). Такой заголовок может содержать описание подпрограммы, ее входные и выходные значения и различные замечания по ее работе. Например: ; Функция, возвращающая контрольную сумму (один байт) буфера данных ; Входные данные ds: bx – указатель на начало буфера ; cx – длина буфера ; Выходные данные: al – контрольная сумма буфера ; Используемые регистры (содержимое не сохраняется): bx, cx ; Примечание: буфер не должен превышать 64 Кб ; и не должен пересекать границу сегментов. CheckSum proc near

sub al,al ; очистить аккумулятор контрольной суммы

Page 47: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

47

add al,[bx] ; прибавить текущее значение байта inc bx ; ссылка на следующее значение loop CheckSum ret

CheckSum endp Если подпрограмма написана и отлажена, то редко приходится снова

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

4.39. Набор инструкций процессоров семейства iAPx86 Набор инструкций включает в себя все действия, которые

программист может заставить выполнить процессор. Перечень используемых в первой лабораторной работе инструкций (команд) ассемблера приведен в табл.3.2, а полный набор имеется в [6, с.134-138]. Эти инструкции выполняют множество действий – от пустой операции, которая не выполняет никаких функций (nop), до копирования 65 535 слов (rep movsw).

4.40. Системное программное обеспечение для семейства IBM PC СПО используется в качестве промежуточного уровня между

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

несколько сотен строк на ассемблере, однако ваша программа может получить символ (код) клавиши с помощью только одной системной функции.

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

4.41. Операционная система DOS В операционной системе (ОС) предусмотрено также большое число

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

mov ah,2 ; функция DOS вывода символа mov dl,'A' ; A – это символ, который нужно вывести на экран int 21h

вызывает функцию DOS вывода на экран, чтобы вывести символ A в текущей позиции курсора.

Page 48: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

48

Функции DOS следует вызывать для ввода с клавиатуры или из файла, вывода на экран или в файл и на печать.

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

Рассмотрим функции DOS, используемые в лабораторной работе №1. 4.42. Получение символов с клавиатуры

Ввод информации с клавиатуры – один из основных способов взаимодействия с компьютером IBM PC. Одним из наиболее простых способов получения символов клавиш является функция "Ввод с клавиатуры", то есть функция DOS номер 1. Функции DOS вызываются путем помещения номера функции в регистр ah и выполнения затем инструкции int 21h. Набранный на клавиатуре символ возвращается в регистре al. Например, когда выполняется код

mov ah,1 ; ah:=1 (функция ввода одного символа с клавиатуры) int 21h

DOS помещает следующий набранный на клавиатуре символ в регистр al. Если клавиша не нажата, DOS будет ждать, когда она будет нажата, поэтому для выполнения данной функции может потребоваться неопределенное время.

4.43. Вывод символов на экран Функция DOS с номером 2 обеспечивает наиболее непосредственный

путь вывода символа на экран. Для этого нужно просто поместить 2 в регистр ah и выводимый символ в регистр dl, а затем вызвать DOS с помощью int 21h. Следующий код отображает каждый введенный символ на экране:

mov ah,1 ; ah:=1 (функция ввода одного символа с клавиатуры) int 21h ; т.е. получить код следующей нажатой клавиши (в al) mov dl,al ; скопировать считанный символ из al в dl (dl:=al) mov ah,2 int 21h ; вывести его на экран.

4.44. Вывод сообщения на экран в базовой версии DOS Вывод на экран в базовой версии DOS требует определения

текстового сообщения в области данных, установки в регистре ah значения 09 (вызов функциии DOS) и указания команды DOS int 21h. В процессе

Page 49: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

49

выполнения операции конец сообщения определяется по oграничителю ($), как это показано ниже:

; сегмент данных msg db 'Имя покупателя?','$' ; сегмент кода mov ah,09h ;запрос вывода на экран lea dx, msg ;загрузка адреса сообщения int 21h ;вызов DOS Знак ограничителя $ можно кодировать:

– непосредственно после cимвольной строки (показано выше); – внутри строки: 'Имя покупателя?$'; – или в следующем операторе db '$'.

Используя данную операцию, нельзя вывести на экран символ доллара $. Кроме того, если знак доллара будет отсутствовать в конце строки, то на экран будут выводиться все последующие символы, пока знак $ не встретится в памяти.

Команда lea загружает адрес области msg в регистр dx для передачи в DOS адреса выводимой информации. Этот адрес является oтносительным, поэтому для вычисления абсолютного адреса данных DOS «складывает» (см. п.4.18) значения регистров ds и dx (ds:dx).

4.45. Ввод данных с клавиатуры в базовой версии DOS Для ввода, использующего базовую DOS, область ввода требует

наличия cписка параметров, содержащего поля, необходимые при выполнении команды int. Пример.

vvod_b label byte ; Список параметров: maxlen_b db 4 ; максимальная длина fact_b db 0 ; реальная длина simv_b db "0000" ; введенные символы Первый байт содержит максимальную длину вводимых данных. Это

необходимо для предупреждения пользователя звуковым сигналом, если набран слишком длинный текст; символы, превышающие максимальную длину, не принимаются. Максимальное значение поля – 999#. Символ # использован здесь для индикации конца данных, так как шестнадцатеричный код клавиши Enter (0dh) не имеет отображаемого символа

Второй байт необходим DOS для занесения в него действительного числа введенных символов.

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

Page 50: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

50

Так как директива label не занимает места, то vvod_b и maxlen указывают на один и тот же aдрес памяти. Атрибут byte – один из возможных атрибутов этой директивы (см. п.4.56.)

Для запроса на ввод необходимо поместить в регистр ah номер функции – 10 (шестнадцатеричное 0ah), загрузить адрес списка параметров (vvod_b в нашем примере) в регистр dx и выполнить int 21h:

mov ah,0ah ;запрос функции ввода lea dx, vvod_b ;загрузить адреса списка параметров int 21h ;вызвать DOS Команда int ожидает, пока пользователь не введет с клавиатуры текст,

проверяя при этом, чтобы число введенных cимволов не превышало максимального значения, указанного в списке параметров (4 в нашем примере). Для указания конца ввода пользователь нажимает клавишу Enter. Код этой клавиши (шестнадцатеричное 0d) также заносится в поле ввода (у нас – simv_b).

Пример. Пусть требуется вводить список имен, длина которых не превышает десяти символов. Тогда список параметров для ввода может иметь вид:

Datasg segment para ‘Data’ spisok label byte ;Список параметров maxlen db 11 ; максимальная длина fact db 0 ; реальная длина simv_sp db "00000000000" ; введенные символы Допустим, пользователь ввел имя BROWN и нажал клавишу Enter.

Список параметров в этом случае будет содержать информацию: Значение spisok simv_sp +1 +2 +3 +4 +5 +6 Десятичное 11 6 В R O W N # 0 0 0 0 0 Шестнадцатеричное 0B 06 42 52 4F 57 4E 0d 30 30 30 30 30

Во второй байт списка параметров (fact в нашем примере) команда заносит длину введенного имени – 6. Код Enter находится по адресу simv_sp+5. Т.к. максимальная длина в 11 символов включает шестнадцатеричное 0d, то можно ввести текст не более 10 символов. Подробнее о функциях DOS в [1, с.131 – 192].

В DOS не предусмотрен форматный ввод и вывод. DOS выполняет только посимвольный или построчный ввод-вывод.

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

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

Page 51: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

51

предпочтительным методом является выполнение функции с номером 4Ch. Именно эта функция и используется в приведенном примере.

stacksg segment para ‘Stack’ db 100h ; стек объемом 256 байтов

stacksg ends datasg segment para ‘Data’ ; начало сегмента данных datasg ends codesg segment para ‘Code’ ; начало сегмента кода

. . . EhcoLoop:

mov ah,1 ; функция DOS ввода с клавиатуры int 21h ; получить следующую клавишу cmp al,13 ; это клавиша enter? jz EchoDone ; да, выполняем эхоотображение mov dl,al ; поместить символ в dl mov ah,2 ; функция DOS вывода на экран int 21h ; вывести на экран символ jmp EchoLoop ; отобразить следующий символ

EchoDone: mov ah,4ch ; функция DOS завершения программы int 21h ; завершить программу . . .

codesg ends end

4.46. Базовая система ввода-вывода Если нет нужной функции DOS, обратитесь к базовой системе ввода-

вывода IBM PC BIOS. В отличие от DOS и прикладных программ BIOS хранится в памяти, доступной только по чтению (ROM или ПЗУ).

BIOS является программным обеспечением нижнего уровня. Даже DOS использует для управления аппаратурой функции BIOS. Аналогично DOS BIOS позволяет "скрыть" различия между различными компьютерами и устройствами. С помощью функций BIOS можно установить режим экрана, управлять цветами, получить информацию о дисплейном адаптере и т.д. [1, с. 151- 165].

Программное обеспечение коммуникаций управляет портом IBM PC с помощью инструкций in и out, поскольку ни DOS, ни BIOS не предусматривают адекватной поддержки. Подробнее см. уч. пос., ч.8.

4.47. Выражения

Page 52: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

52

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

MemVar db 0 dw 0 dw 0 dw 0 NextVar db ? . . . mov ax,seg MemVar ;загрузки в ds постоянного значения mov ds,ax ; сегмента, в котором находится MemVar mov bx,offset MemVar +(1+ (3*2)) mov byte ptr [bx],1

В этой программе используется сложное выражение, включающее в себя операции *, +, и offset, при вычислении которого получается значение offset MemVar+7, которое представляет собой адрес NextVar. Наконец, для выбора байтовой операции при сохранении константы 1 в ячейке, на которую указывает регистр bx (что представляет собой NextVar), используется операция byte ptr.

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

Здесь offset MemVar – это значение-константа, представляющее собой смещение переменной MemVar в ее сегменте (например, смещение этой переменной от начала сегмента данных может быть равным 5000). Сохраненное в переменной MemVar значение (в приведенном выше примере оно равно нулю) может изменяться, сама переменная MemVar, конечно, никуда не перемещается.

Так как значения-константы точно известны, ассемблер может вычислять состоящие из постоянных значений выражения так же, как он ассемблирует исходный текст программы (т.е. исходный код). Для ассемблера выражение offset MemVar + 7 совершенно аналогично выражению 5000 + 7. Поскольку все элементы выражения неизменяемы и определены во время ассемблирования, выражение можно свести к одному значению - константе.

В выражениях могут использоваться следующие операции: (), size, offset, ptr, *, /, +, - (бинарные) Другие операции, которые могут использоваться в выражениях

(LENGTH, MASK, WIDTH, . (селектор элемента структуры), HIGH,

Page 53: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

53

LOW, : (переопределение сегмента), SEG, THIS, .TYPE, LARGE, SHORT, SMALL) *, /, shl, shr, +, - (бинарные), eq, ge, gt, le, lt, ne, not, and, or, xor (см. уч. пос., ч.6).

Page 54: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

54

4.48. Биты, байты, слова, двойные и учетверенные слова Как было отмечено выше (см. п. 4.5), основной единицей памяти

компьютера является бит. В бите может храниться значение 0 или 1. Байт состоит из 8 битов. В каждом из 8-разрядных регистров процессора (al, ah, bl, cl, ch, dl и dh) и в каждой из более чем 1 000 000 адресуемых ячеек памяти хранится ровно 1 байт. (Если быть точным, то количество адресуемых ячеек равно 220, т.е. 1 048 576).

Набор символов компьютера включает в себя строчные и прописные символы, цифры от 0 до 9, специальные графические символы, научные и специальные символы, а также различные знаки пунктуации и прочие символы – всего 256 символов. Набор символов построен таким образом, что в 1 байте хранится 1 символ.

Байт – это наименьшая единица адресации процессора. В нем может храниться один символ, одно беззнаковое значение от 0 до 255 или одно значение со знаком в диапазоне от -128 до +127. Байт не подходит для хранения значений с плавающей точкой и указателей на память.

Следующая по величине единица памяти процессора – это слово. Оно вдвое превосходит по размеру байт (содержит 16 битов). Фактически слово хранится в памяти в виде двух последовательных байтовых ячеек. Адресное пространство процессора можно рассматривать как немногим более 500 000 слов. В каждом из 16-разрядных регистров (регистр ax, bx, cx, dx и др.) также хранится одно слово.

Число 65 535 представляет собой максимальную величину целого без знака, хранящегося в слове. Целые со знаком могут принимать значения в диапазоне от -32 768 до +32 767.

Слова могут адресоваться по любому смещению в данном сегменте, значения размером в слово можно использовать в качестве указателей памяти. Например, регистры bx, bp, si и di размером в слово используются как указатели на память.

Значения, хранимые в виде 32-битовых (4-байтовых) элементов, называются двойными словами. Процессор 8086 не может непосредственно работать с 32-битовыми целыми значениями, но выполнять 32-разрядные арифметические операции (с помощью двух последовательных 16-разрядных операций) можно с помощью таких инструкций, как adc и sbb. В двойных словах беззнаковые целые могут принимать значения в диапазоне от 0 до 4 294 967 295, а целые со знаком – в диапазоне от -2 147 483 648 до +2 147 483 647.

Учетверенными словами называются 64-битовые значения (восемь байтов). В процессоре 8086 встроенная поддержка учетверенных слов отсутствует. Процессор 8086 не может непосредственно работать с 64-

Page 55: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

55

битовыми целыми значениями, но выполнять 64-разрядные арифметические операции (с помощью четырех последовательных 16-разрядных операций) можно с помощью таких инструкций, как adc и sbb.

Ассемблер поддерживает еще один тип данных – элемент данных длиной 10 байтов. Этот 10-байтовый элемент данных может, например, использоваться для хранения суммы учетверенных слов.

Значения размером в слово, двойное или учетверенное слово в памяти хранятся таким образом, что младший байт следует первым. То есть если значение размером в слово хранится по адресу 0, то биты 7-0 значения записаны по адресу 0, а биты 15-8 – по адресу 1.

Аналогично, если значение размером в двойное слово хранится по адресу 5, то биты 7-0 хранятся по адресу 5, биты 15-8 хранятся по адресу 6, биты 23-16 – по адресу 7, а биты 31-24 – по адресу 8.

4.49. Представление числовых значений Легче всего пользоваться десятичными значениями: mov cx,100 ; установить счетчик в значение 100. Ассемблер считает значения десятичными, если не указано противное.

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

Можно указать ассемблеру, что число выражено в двоичном виде, если поместить в конце числа букву b (при этом число должно состоять только из 0 и 1, поскольку это единственные две цифры, допустимые в двоичном представлении). Например, десятичное значение 100 выражается в двоичном виде как 1100100b.

Последняя инструкция с операндами в двоичном представлении будет иметь вид:

mov cx,1100100b ; установить счетчик в значение 100 В восьмеричном виде последний пример принимает вид:

mov cx,144o ; установить счетчик в значение 100 mov cx,144q ; установить счетчик в значение 100

Суффиксы o и q указывают на восьмеричную запись. В шестнадцатеричном виде последний пример принимает вид:

mov cx,64h ; установить счетчик в значение 100 Шестнадцатеричные числа обозначаются суффиксом h. Кроме того,

шестнадцатеричные числа должны начинаться с одной из цифр 0-9, так как шестнадцатеричное число типа bad4h может ошибочно интерпретироваться как метка. Пример, в котором используется как число 0bad4h, так и метка bad4h:

datasg segment para ‘Data’ bad4h dw 0 ;метка bad4h

Page 56: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

56

datasg ends codesg segment para ‘Code’

mov ax,0bad4h ; загрузить в ax шестнадцатеричную константу . . . ; (первый 0 показывает, что это константа) mov ax,bad4h ; загрузить ax из переменной в памяти bad4h

; (отсутствие 0 в качестве первого символа показывает, что это метка) . . .

codesg ends В общем случае постоянным числовым значением может быть только

операнд, начинающийся с цифр 0-9. Числа с плавающей точкой могут обозначаться двумя способами (см.

уч. пос., ч.4). Чтобы показать, что число является десятичным, в качестве суффикса

можно использовать букву d. Наконец, могут использоваться символьные константы, при этом символы заключаются в одиночные или двойные кавычки. Значением символа является его значение кода ASCII. Например, все следующие строки загружают в регистр al значение кода ASCII символа А [1, с. 559].

mov al,65 ; 65 = 41h mov al,41h mov al,'A' ; ASCII код символа А = 41h mov al,"A" ; ASCII код символа А = 41h Двоичные, восьмеричные, десятичные и шестнадцатеричные значения

могут использоваться там же, где можно использовать константы. 4.50. Инициализированные данные

Директивы определения данных db, dw, dd, dq и dt позволяют определить переменные в памяти различного размера: один байт (db), два байта, т.е. одно слово (dw), четыре байта, т.е. двойное слово (dd), восемь байтов, т.е. одно учетверенное слово (dq) и десять байтов (dt).

Например: datasg segment para ‘Data’ ByteVar db 'Z' ; 1 байт WordVar dw 101b ; 2 байта (1 слово) DwordVar dd 2BFh ; 4 байта (1 двойное слово) QwordVar dq 307o ; 8 байтов (1 учетверенное слово) TwordVar dt 100 ; 10 байтов datasg ends codesg segment para ‘Code’

. . . mov ah,2 ; функция DOS вывода на дисплей

Page 57: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

57

mov dl,ByteVar ; символ, который нужно вывести на экран int 21h mov ax,WordVar . . . add word ptr DwordVar,ax adc word ptr DwordVar+2,dx . . .

codesg ends Здесь определяются пять переменных памяти и показывается, как

некоторые из таких переменных можно использовать. 4.51. Инициализация массивов

В одной директиве определения данных может указываться несколько значений. Например, директива:

SampleArrray dw 0, 1, 2, 3, 4 создает массив из пяти элементов с именем SampleArray, элементы которого имеют размер в слово. В директивах определения данных можно использовать любое число значений, умещающееся на строке.

Если нужно определить массив, который слишком велик и не вмещается на одной строке, нужно добавить несколько строк. Метку в директиве определения данных указывать необязательно. Например, по директивам:

SquareArray dd 0, 1, 4, 9, 16 dd 25, 36, 49, 64, 81 dd 100, 121, 144, 169, 196 создается массив элементов размером в двойное слово с именем

SquareArray, состоящий из квадратов первых 15 целых чисел. Ассемблер позволяет определить блок памяти, инициализированный

указанным значением, с помощью операции dup. Например, BlankArray dw 100h dup (0) Здесь создается массив BlankArray, состоящий из 256 слов (по-

другому: 100h), инициализированных значением 0. Аналогично директива: ArrayOf_A db 92 dup ('A')

создает массив из 92 байтов, и каждый инициализирован символом A. 4.52. Инициализация строк символов

Строку символов можно определить следующим образом: String db 'A', 'B', 'C', 'D'

Предусмотрена также удобная сокращенная форма: String db 'ABCD'

Чтобы переместиться к левому краю следующей строки, нужно вывести символы "возврат каретки/перевод строки". Например:

Page 58: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

58

stacksg segment para ‘Stack’ db 256 dup (0)

stacksg ends datasg segment para ‘Data’ String1 db 'Line1','$' String2 db 'Line2','$' String3 db 'Line3','$' datasg ends codesg segment para ‘Code’ ProgramStart:

mov ax,datasg mov ds,ax mov ah,9 ; функция DOS печати строки mov dx,offset String1 ; печатаемая строка int 21h ; вызвать DOS для печати строки mov dx, offset String2 ; печатаемая строка int 21h ; вызвать DOS для печати строки mov dx, offset String3 ; печатаемая строка int 21h ; вызвать DOS для печати строки mov ah,4ch ; функция DOS завершения программы int 21h

codesg ends end ProgramStart Программа печатает следующее: Line1Line2Line3 Однако если в конце каждой строки добавить символы "возврат

каретки/перевод строки": String1 db 'Line1',0dh,0ah,'$' String2 db 'Line2',0dh,0ah,'$' String3 db 'Line3',0dh,0ah,'$'

то вывод будет выглядеть следующим образом: Line1 Line2 Line3

4.53. Инициализация выражений и меток Начальное значение инициализированной переменной должно

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

Page 59: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

59

Можно также использовать: выражения:

TestVar dw ((924/2)+1) ; TestVar инициализируется значением 463

и метки: datasg segment para ‘Data’

db 1,2,3,4,5,6,7,8,9,10,10,9,8,7,6,5,4,3,2,1 Buffer dw 16 dup (0) ; область памяти из 16-ти нулевых слов BufferPointer dw Buffer datasg ends

Начальное значение BufferPointer представляет собой смещение Buffer в сегменте datasg, а не значение 0, которое хранится в переменной Buffer. В результате этого и инструкция:

mov ax,offset Buffer и инструкция:

mov ax,BufferPointer загрузят в регистр ax одно и то же значение (смещение переменной Buffer, которое в приведенном выше примере равно 20, т.к. в сегменте данных перед областью данных с меткой Buffer располагается 20 байтов данных).

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

datasg segment para ‘Data’ WordArray dw 50 dup (0) ; массив из 50-ти нулевых слов WordArrayEnd label word WordArrayLength dw (WordArrayEnd - WordArray) ;длина = 100 datasg ends

Если требуется вычислить длину переменной WordArray в словах, а не в байтах, это можно сделать, просто разделив длину в байтах на 2:

WordArrayLength dw (WordArrayEnd - WordArray) / 2 4.54. Неинициализированные данные

Иногда нет смысла присваивать переменной памяти начальное значение. Тогда применяют знак вопроса (?). Например:

KeyBuffer db 10 dup (?) В данной строке резервируется 10 байтов памяти, начиная с метки

KeyBuffer, но этим байтам не присваивается никакого конкретного значения.

Конечно, при использовании неинициализированной переменной ее нужно инициализировать в своей программе перед тем, как использовать. Например, было бы ошибочным использовать содержимое KeyBuffer до

Page 60: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

60

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

4.55. Именованные ячейки памяти Кроме присвоения имени ячейке памяти с помощью метки,

предшествующей директиве определения данных (например, db), можно присваивать имя ячейке директивой label, которая позволяет определить имя метки и ее тип, не определяя при этом данные. Например, в предыдущем примере массив KeyBuffer можно определить так:

KeyBuffer label byte db 10 dup (?) Типы меток, которые можно определить с помощью label, включают в

себя: byte, word, dword, qword, tbyte, proc, near, far, unknown и др. Типы byte (байт), word (слово), dword (двойное слово), qword

(учетверенное слово) и tbyte (десять байтов) говорят сами за себя, определяя, соответственно, 1-, 2-, 4-, 8- и 10-байтовые элементы данных. Приведем пример инициализации переменной, как пары байтов, но обращения к ней, как к слову:

datasg segment para ‘Data’ WordVar label word

db 1,2 datasg ends codesg segment para ‘Code’

. . . mov ax,[WordVar] . . . Когда эта программа выполняется, в регистр al загружается 1 (первый

байт WordVar), а в регистр ah – значение 2. Ключевые слова near и far используются в программе для выбора

типа вызова или перехода, необходимого для достижения определенной метки. Например, в программе:

codesg segment para ‘Code’ . . . FarLabel label far NearLabel label near

mov ax,1 . . . jmp FarLabel . . . jmp NearLabel . . .

Page 61: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

61

первая инструкция jmp представляет собой переход дальнего типа (загружаются оба регистра cs и ip), так как это переход на метку типа far, а второй переход имеет ближний тип (загружается только регистр ip), так как это переход на метку типа near. Заметим, что обе метки FarLabel и NearLabel описывают один и тот же адрес (адрес инструкции mov), но позволяют переходить на него различными способами.

Примечание. Когда используются упрощенные директивы определения сегментов (см. уч.пос., ч.4), то директива proc – это удобный способ определить метку нужного типа (ближнюю или дальнюю) для текущей модели кода.

4.56. Перемещение данных Данные в процессоре 8086 перемещаются с помощью инструкции

mov, которая записывает копию операнда-источника в операнд-приемник. Например, инструкции:

mov ax,0 ; ax := 0 mov bx,9 ; bx := 9 mov ax,bx ; ax := bx = 9

сначала записывают в регистр ax константу 0, затем в регистр bx записывается константа 9, и, наконец, содержимое bx копируется в ax.

Значение 9 не перемещается, а копируется из bx в ax. В инструкции mov можно использовать почти любую пару операндов,

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

В качестве операнда-источника (правого операнда) инструкции mov можно использовать:

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

В качестве операнда-приемника (левого операнда) инструкции mov может использоваться:

– общий регистр; – ячейка памяти.

Кроме того, в качестве операнда-приемника этой инструкции можно использовать сегментный регистр, но в этом случае операндом-источником может быть только общий регистр!

4.57. Арифметические операции Процессор 8086 не может выполнять арифметические операции с

плавающей точкой (действия с такими числами, как 5.2 и 1.03Е17), не

Page 62: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

62

говоря уже о тригонометрических функциях. Эти операции может выполнять арифметический сопроцессор 8087, но если он отсутствует, процессор 8086 выполняет программно-арифметические операции (последовательности инструкций сдвигов, сложений и проверок) и выполняет существенно медленнее.

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

4.58. Арифметические операции над целыми двоичными числами К арифметическим операциям над целыми двоичными числами

относятся: 1) сложение двоичных чисел без знака; 2) вычитание двоичных чисел без знака; 3) умножение чисел без знака; 4) деление чисел без знака; 5) вычитание и сложение операндов большой размерности; 6) сложение двоичных чисел со знаком; 7) вычитание двоичных чисел со знаком; 8) умножение чисел со знаком; 9) деление чисел со знаком. Здесь рассматриваются первые пять операций: четыре основных

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

4.59. Сложение целых двоичных чисел без знака Микропроцессор выполняет сложение операндов по правилам

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

К примеру, выполним сложение: 254 + 5 = 259 в двоичном виде: 11111110 + 0000101 = 1 00000011. Результат вышел за пределы восьми битов и правильное его значение укладывается в 9 битов, а в 8-битовом поле операнда осталось значение 00000011, что, конечно, неверно.

Page 63: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

63

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

Естественно, что программист должен предусматривать возможность такого исхода операции сложения и средства для корректировки. Это предполагает включение участков кода после операции сложения, в которых анализируется флаг cf. Анализ этого флага можно провести различными способами. Самый простой и доступный — использовать команду условного перехода jcc. Эта команда в качестве операнда имеет имя метки в текущем сегменте кода. Переход на эту метку осуществляется в случае, если в результате работы предыдущей команды флаг cf установился в 1.

В системе команд микропроцессора имеются три команды двоичного сложения:

inc операнд ; операнд := операнд+1; add операнд_1,операнд_2 ;операнд_1 := операнд_1 + операнд_2; adc операнд_1,операнд_2 ; сложение с учетом флага переноса cf.

; операнд_1 = операнд_1 + операнд_2 + значение_cf Инструкция add выполняет сложение операнда-источника (правого

операнда) с содержимым операнда-приемника и записывает результат в операнд-приемник.

Например, инструкции: datasg segment para ‘Data’ BaseVal dw 99 Adjust dw 10 datasg ends codesg segment para ‘Code’

. . . mov dx,BaseVal add dx,11 sub dx,Adjust . . .

codesg ends сначала загружают значение, записанное в BaseVal, в регистр dx, затем прибавляют к нему константу 11 (в результате в dx получается значение 110) и, наконец, вычитают из dx значение 10, записанное в переменной Adjust. Полученное в результате значение 100 сохраняется в регистре dx.

Page 64: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

64

Рассмотрим пример вычисления суммы чисел stacksg segment para ‘Stack’

db 256 dup (0) stacksg ends datasg segment para ‘Data’ a db 254 datasg ends codesg segment para ‘Code’ ;сегмент кода main:

mov ax,datasg mov ds,ax . . . xor ax,ax add al,17 add al,a jnc m1 ;если нет переноса, то перейти на m1 adc ah,0 ;в ax сумма с учетом переноса

m1: . . . exit:

mov ax,4c00h ;стандартный выход int 21h

codesg ends end main ;конец программы В примере создана ситуация, когда результат сложения выходит за

границы операнда. Эта возможность учитывается командой jnc, которая проверяет состояние флага cf (хотя можно было обойтись и без нее, всегда прибавляя значение флага, которое после операции add может быть равно как нулю, так и единице). Если он установлен в 1, то это признак того, что результат операции получился больше по размеру, чем размер операнда, и для его корректировки необходимо выполнить некоторые действия. В данном случае мы просто полагаем, что границы операнда расширяются до размера ax, для чего учитываем перенос в старший разряд командой adc.

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

Команды сложения чисел со знаком те же, что и для чисел без знака (подробнее см. уч.пос., ч.4).

Page 65: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

65

4.60. Вычитание целых двоичных чисел без знака Инструкция sub вычитает операнд-источник из операнда-приемника.

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

05 = 00000000 00000101 - - 10 = 00000000 00001010 Для того чтобы произвести вычитание, произведем воображаемый

заем из старшего разряда: 1 00000000 00000101 00000000 00001010 11111111 11111011

Тем самым по сути выполняется действие (65 536 + 5) - 10 = 65 531,

0 здесь как бы эквивалентен числу 65 536. Результат, конечно, неверен, но микропроцессор считает, что все нормально, хотя факт заема единицы он фиксирует установкой флага переноса cf. Но посмотрите еще раз внимательно на результат операции вычитания. Это же –5 в дополнительном коде! Если представить разность в виде суммы 5 + (–10).

5 = 00000000 00000101 + + (-10)= 11111111 11110110 , 11111111 11111011

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

анализировать состояние флага cf. Если он установлен в 1, то это говорит о том, что произошел заем из старшего разряда и результат получился в дополнительном коде.

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

dec операнд ; операнд := операнд - 1; sub операнд_1,операнд_2 ; операнд_1 := операнд_1 – операнд_2;

Page 66: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

66

sbb операнд_1,операнд_2 ; вычитание с учетом заема (флаг cf ): ; операнд_1 := операнд_1 – операнд_2 – значение_cf

Таким образом, среди команд вычитания есть команда sbb, учитывающая флаг переноса cf. Эта команда подобна adc, но теперь уже флаг cf выполняет роль индикатора заема 1 из старшего разряда при вычитании чисел.

Рассмотрим пример проверки заема при вычитании чисел без знака codesg segment para ‘Code’ ;сегмент кода main: ;точка входа в программу

. . . xor ax,ax mov al,5 sub al,10 jnc m1 ;нет переноса? neg al ;в al модуль результата

m1: . . .

exit: mov ax,4c00h ;стандартный выход int 21h

codesg ends end main ;конец программы В этом примере командой sub al,10 выполняется вычитание. С

исходными данными, указанными для этой команды вычитания, результат получается в дополнительном коде (отрицательный). Чтобы получить модуль отрицательного результата, применяется команда neg. Тот факт, что на самом деле число отрицательное, отражен в состоянии флага cf.

4.61. Тридцатидвухразрядные операнды Операции add и sub работают с 8- или 16-битовыми операндами. Чтобы сложить или вычесть 32-разрядные операнды, надо разбить

операцию на ряд операций со значениями размером в слово и использовать инструкции adc и sbb.

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

f f f f +0001 10000

Младшее слово результата равно нулю, перенос равен 1, поскольку результат (10000h) не вмещается в 16 битов.

Page 67: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

67

Инструкция adc аналогична инструкции add, но в ней учитывается флаг переноса, предварительно установленный предыдущим сложением. Когда складываются два значения, превышающие по размеру слово, то младшие (менее значащие) слова нужно сложить с помощью инструкции add, а остальные слова этих значений – с помощью одной или нескольких инструкций adc. Например, следующие инструкции складывают значение в регистрах cx:bx размером в двойное слово, со значением, записанным в регистрах dx:ax:

add ax,bx ; ax:= ax + bx adc dx,cx ; dx := dx+ cx+<значение cf>,

а в следующей группе инструкций выполняется сложение учетверенного слова в переменной DoubleLong1 с учетверенным словом в переменной DoubleLong2:

mov ax, word ptr DoubleLong1 mov bx,word ptr DoubleLong1+2 mov cx,word ptr DoubleLong1+4 ; (dx:cx:bx:ax) := учетверенное mov dx,word ptr DoubleLong1+6 ; слово DoubleLong1 add ax,word ptr DoubleLong2 adc bx,word ptr DoubleLong2+2 adc cx,word ptr DoubleLong1+4 ; (dx:cx:bx:ax) := adc dx,word ptr DoubleLong2+6 ; := DoubleLong1 + DoubleLong2

Инструкция sbb работает по тому же принципу, что и инструкция adc. Когда инструкция sbb выполняет вычитание, в ней учитывается заем, произошедший в предыдущем вычитании. Например, следующие инструкции вычитают значение, записанное в регистрах cx:bx, из значения размером в двойное слово, записанного в регистрах dx:ax:

sub ax,bx ; ax:= ax - bx sbb dx,cx ; dx := dx- cx-<значение cf>

4.62. Технология сложения и вычитания длинных чисел Команды сложения и вычитания работают с операндами

фиксированной размерности: 8 и 16 битов (процессор 8086) или 8, 16 и 32 бита (процессор 80386). А что делать, если нужно сложить числа большей размерности, например 48 или 64 бита, используя 16-разрядные операнды?

Процесс сложения многобайтных чисел происходит так же, как и при сложении двух чисел “в столбик”, — с осуществлением, при необходимости, переноса 1 в старший разряд. Т.к. удается запрограммировать этот процесс, то значительно расширяется диапазон двоичных чисел, над которыми можно выполнять операции сложения и вычитания.

Page 68: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

68

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

В завершение обсуждения команд сложения и вычитания отметим, что кроме флагов cf и of в регистре flags есть еще несколько флагов, которые можно использовать с двоичными арифметическими командами. Речь идет о следующих флагах:

zf — флаг нуля, который устанавливается в 1, если результат операции равен нулю, и в 0, если результат не равен нулю;

sf — флаг знака, значение которого после арифметических операций (и не только) совпадает со значением старшего бита результата, то есть с битом 7, 15 или 31. Таким образом, этот флаг можно использовать для операций над числами со знаком.

4.63. Увеличение и уменьшение на единицу Иногда в программе на ассемблере требуется выполнить сложение,

которое состоит просто в прибавлении к операнду значения 1. Например, заполним 10-байтовый массив TempArray числами 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:

datasg segment para ‘Data’ TempArray db 10 dup (?) FillCount dw ? datasg ends codesg segment para ‘Code’

. . . mov al,0 ; первое значение, записываемое в TempArray mov bx,offset TempArray ; bx указывает на TempArray mov FillCount,10 ; число эл-тов, которыми нужно заполнить массив

FillTempArrayLoop: mov [bx],al ; установить текущий элемент TempArray inc bx ; ссылка на следующий элемент массива TempArray inc al ; следующее записываемое значение dec FillCount ; уменьшить счетчик числа заполняемых эл-тов jnz FillTempArrayLoop ;обработать следующий эл-нт, если не все . . .

codesg ends Так как инструкция add занимает три байта, а инструкция inc

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

inc bx ; bx:= bx+1,

Page 69: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

69

а не инструкцию: add bx,1 ; bx:= bx+1

Фактически более экономно выполнить две операции inc, чем прибавить к регистру размером в слово значение 2.

Аналогично иногда из содержимого регистров и переменных в памяти нужно вычесть значение 1. Тогда применяется инструкция dec.

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

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

умножения: знаковое и беззнаковое (8-разрядное и 16-разрядное). Инструкция mul перемножает беззнаковые сомножители. При 8-битовом (8-разрядном) умножении один из операндов должен

храниться в регистре al, а другой может представлять собой любой 8-битовый общий регистр или переменную памяти соответствующего размера. Инструкция mul всегда сохраняет 16-битовое произведение в регистре ax. Например, во фрагменте программы:

mov al,25 mov dh,40 mul dh

al умножается на dh, а результат (1000) помещается в регистр ax. Другой вариант использования этой инструкции, когда один из сомножителей хранится в ячейке памяти (например, в сегменте данных переменная b1 определена как байт: b1 db 40):

mov al,25 mul b1 ; ax :=al*b1=25*40=1000

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

Инструкция перемножения 16-битовых сомножителей работает аналогично. Один из сомножителей должен храниться в регистре ax, а другой может находиться в 16-разрядном общем регистре или в переменной памяти. 32-битовое произведение инструкция mul помещает в этом случае в регистры dx:ax, при этом младшие (менее значащие) 16 битов произведения записываются в регистр ax, а старшие (более значащие) 16 битов – в регистр dx. Например, инструкции

mov ax,1000 mul ax ; (dx:ax):=ax*ax

Page 70: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

70

загружают в регистр ax значение 1000, а затем возводят его в квадрат, помещая результат (значение 1 000 000) в регистры dx:ax.

Таким образом, для умножения чисел без знака предназначена команда

mul сомножитель_1 Как видите, в команде указан всего лишь один операнд-сомножитель.

Второй операнд — сомножитель_2 задан неявно. Его местоположение фиксировано и зависит от размера сомножителей. Так как в общем случае результат умножения больше, чем любой из его сомножителей, то его размер и местоположение должны быть тоже определены однозначно. Варианты размеров сомножителей и размещения второго операнда и результата умножения для микропроцессора 8086 приведены в табл. 4.4.

Таблица 4.4 Сомножитель_1 Сомножитель_2 Результат

Байт al 16 битов в ax: al — младшая часть результата; ah — старшая часть результата

Слово ax 32 бита в паре dx:ax: ax — младшая часть результата; dx — старшая часть результата

Из таблицы видно, что произведение состоит из двух частей и в зависимости от размера операндов размещается в двух местах — на месте сомножитель_2 (младшая часть) и в дополнительном регистре ah, dx (старшая часть). Как же динамически (то есть во время выполнения программы) узнать, что результат достаточно мал и уместился в одном регистре или что он превысил размерность регистра и старшая часть оказалась в другом регистре? Для этого привлекаются уже известные нам флаги переноса cf и переполнения of:

– если старшая часть результата нулевая, то после операции произведения флаги cf = 0 и of = 0;

– если же эти флаги ненулевые, то это означает, что результат вышел за пределы младшей части произведения и состоит из двух частей, что и нужно учитывать при дальнейшей работе. Пример программы умножения:

stacksg segment para ‘Stack’ db 256 dup (0)

stacksg ends datasg segment para ‘Data’ ;сегмент данных rez label word rez_l db 45 rez_h db 0 datasg ends codesg segment para ‘Code’ ;сегмент кода

Page 71: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

71

main: ;точка входа в программу . . .

xor ax,ax mov al,25 mul rez_l jnc m1 ;если переполнение, то на m1 mov rez_h,ah ;старшую часть результата в rez_h

m1: mov rez_l,al

exit: mov ax,4c00h ;стандартный выход int 21h end main ;конец программы

Здесь производится умножение значения в rez_l на число в регистре al. Согласно табл. 4.4, результат умножения будет располагаться в регистре al (младшая часть) и регистре ah (старшая часть). Для выяснения размера результата командой условного перехода jnc анализируется состояние флага cf, и если оно не равно 1, то результат остался в рамках регистра al. Если же cf = 1, то выполняется команда, которая формирует в поле rez_h старшее слово результата. Команда mov rez_l,al формирует младшую часть результата. Теперь обратите внимание на строку с директивой label в сегменте данных. Мы еще не раз будем сталкиваться с этой директивой. В данном случае она назначает еще одно символическое имя rez адресу, на который уже указывает другой идентификатор rez_l. Отличие заключается в типах этих идентификаторов — имя rez имеет тип слова, который ему назначается директивой label (имя типа указано в качестве операнда label). Введя эту директиву в программу, мы подготовились к тому, что, возможно, результат операции умножения будет занимать слово в памяти. Обратите внимание, что мы не нарушили принципа: младший байт по младшему адресу. Далее, используя имя rez, можно обращаться к значению в этой области как к слову.

Примечание. Для умножения сомножителей со знаком используется инструкция imul (см. уч. пос., ч.4).

4.65. Деление целых чисел без знака Процессор 8086 может выполнять отдельные типы операций деления:

– 16-битового значения на 8-битовое (знаковое и беззнаковое); – 32-битового операнда на 16-битовый операнд (знаковое и

беззнаковое).

Page 72: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

72

Здесь рассматриваются только варианты беззнакового деления (инструкция div). Для деления со знаком используется инструкция idiv (см. уч. пос., ч.4).

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

div делитель Делитель может находиться в памяти или в регистре и иметь размер 8

или 16 битов (для МП 8086) или размер 8, 16 или 32 бита (для МП 80386). Местонахождение делимого фиксировано и так же, как в команде умножения, зависит от размера операнда. Результатом команды деления являются значения частного и остатка.

Варианты местоположения и размеров операндов операции деления и результатов деления (МП 8086) показаны в табл. 4.5.

Таблица 4.5 Делимое Делитель Частное Остаток

Слово (16 битов) в регистре ax

Байт в регистре или ячейке

памяти

Байт в регистре al

Байт в регистре ah

Двойное слово (32 бита) dx — старшая часть ax — младшая часть

Слово (16 битов) в регистре или ячейке

памяти

Слово (16 битов) в регистре ax

Слово (16 битов) в регистре dx

После выполнения команды деления возможно возникновение прерывания с номером 0, называемого “деление на ноль”. Этот вид прерывания относится к так называемым исключениям. Данная разновидность прерываний возникает внутри микропроцессора из-за некоторых аномалий во время вычислительного процесса. Прерывание 0, т.е. “деление на ноль”, при выполнении команды div может возникнуть по одной из следующих причин:

1) делитель равен нулю; 2) частное не входит в отведенную под него разрядную сетку, что

может случиться в следующих случаях: - при делении слова на байт, если значение делимого более чем в 256

раз больше значения делителя; - при делении двойного слова на слово, если значение делимого более

чем в 65 536 раз больше значения делителя; - при делении учетверенного слова на двойное слово, если значение

делимого более чем в 4 294 967 296 раз больше значения делителя.

Page 73: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

73

4.66. Беззнаковое деление 16-битового значения на 8-битовое При беззнаковом делении 16-битового значения на 8-битовое значение

делимое должно быть записано в регистре ax. 8-битовый делитель может храниться в любом 8-битовом общем регистре или переменной в памяти соответствующего размера. Инструкция div всегда записывает 8-битовое частное в регистр al, а 8-битовый остаток – в ah. Например:

mov ax,51 ; делимое mov dl,10 ; делитель div dl ; после выполнения деления в al – частное, в ah – остаток Заметим, что частное представляет собой 8-битовое значение. Это

означает, что результат деления 16-битового операнда на 8-битовый операнд не должен превышать 255. Если частное слишком велико, то генерируется прерывание 0 (прерывание по делению на 0). Инструкции:

mov ax,0fffh mov bl,1 div bl

генерируют прерывание по делению на 0 (как можно ожидать, прерывание по делению на 0 генерируется также, если 0 используется в качестве делителя).

Пример деления значения del (20 001) на значение delt (200): stacksg segment para ‘Stack’

db 256 dup (0) stacksg ends datasg segment para ‘Data’ del_b label byte del dw 20001 delt db 200 datasg ends codesg segment para ‘Code’ ;сегмент кода main: ;точка входа в программу

. . . xor ax,ax ;последующие две команды эквивалентны одной mov ax,del, но копируют слово побайтно mov ah,del_b ;старший байт делимого в ah mov al,del_b+1 ;младший байт делимого в al div delt ;в al — частное (здесь 100), в ah — остаток (здесь 1)

. . . end main ;конец программы

Page 74: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

74

4.67. Беззнаковое деление 32-битового значения на 16-битовое При делении 32-битового операнда на 16-битовый операнд делимое

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

mov ax,2 mov dx,1 ; в (dx:ax) загрузить 10002h mov bx,10h div bx

частное 1000h (результат деления 10002h на 10h) будет записано в регистре ax, а 2 (остаток от деления) – в регистре dx.

Как и при умножении, при делении имеет значение, используются операнды со знаком или без знака. Для деления беззнаковых операндов используется операция div, а для деления операндов со знаком – idiv (см. уч. пос., ч.4).

4.68. Изменение знака Фактически инструкция neg операнд выполняет одно действие:

операнд = 0 – операнд, то есть вычитает операнд из нуля. Команду neg операнд можно применять:

– для смены знака; – для выполнения вычитания из константы.

Смена знака. Инструкция neg позволяет изменить (инвертировать) знак содержимого общего регистра или переменной в памяти. Например, после выполнения инструкций:

mov ax,1 ; установить в регистр ax значение 1 neg ax ; отрицание ax, он становится равным -1 mov bx,ax ; скопировать содержимое ax в bx, т.е. bx :=ax=-1 neg bx ; отрицание bx, он становится равным 1

в регистре ax будет содержаться значение -1, а в регистре bx – значение 1. Вычитание из константы. В связи с тем, что команды sub и sbb не

позволяют вычесть что-либо из константы, так как константа не может служить операндом-приемником в этих операциях, данную операцию выполняют с помощью двух команд: neg ax ;смена знака содержимого регисра ax (т.е. ax:=-ax) add ax,340 ;фактически вычитание: ax := 340-ax

4.69. Преобразование размеров беззнаковых данных Что делать, если размеры операндов, участвующих в арифметических

операциях, разные? Например, предположим, что в операции сложения

Page 75: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

75

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

Аналогично преобразование беззнакового байтового значения в слово заключается просто в обнулении старшего байта слова. Например:

mov cl,12 mov al,cl mov ah,0

преобразуют беззнаковое значение 12 в регистре cl в значение 12 размером в слово в регистре ax.

Обратные преобразования двойного слова в слово или слова в байт тоже возможны (при определенных значениях!) Рассмотрим преобразование слова в байт. Например:

mov ax,5 mov bl,al

Здесь значение 5 размером в слово в регистре ax преобразуется в байтовое значение 5 в регистре bl. Естественно, что преобразуемое значение вместится в байт. Попытка преобразовать в байт значение 100h с помощью инструкций:

mov dx,100h mov al,dl

была бы безуспешной, так как в регистр al был бы записан только младший (нулевой) байт.

Для преобразования байтового значения со знаком в регистре al в слово со знаком существует инструкция cbw. Для преобразования слова со знаком в регистре ax в двойное слово со знаком в регистрах dx: ax (старшее слово содержится в регистре dx) предусмотрена специальная инструкция cwd (см. уч. пос., ч.4). Там же – про cdq (двойное из eax – в учетверенное в edx:eax) и cwde (слово из ax в двойное слово в eax).

4.70. Доступ к сегментным регистрам Если одним из операндов инструкции mov является сегментный

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

Вот, например, два способа установки регистра es в значение сегмента данных с именем datasg segment para ‘Data’ ;сегмент данных

DataSeg dw datasg

Page 76: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

76

datasg ends codesg segment para ‘Code’ ;сегмент кода

. . . mov ax,datasg ; первый способ mov es,ax

. . . mov ex,[DataSeg] ; второй способ

. . . codesg ends

Чтобы скопировать содержимое одного сегментного регистра (например, cs) в другой сегментный регистр (например, ds), придется передать значение через регистр общего назначения или стек:

mov ax,cs ; способ 1 (передача через регистр общего назначения) mov ds,ax ; ds := ax = cs

или push cs ; способ 2 (передача через стек) pop ds ; ds := cs

копируют содержимое регистра в ds. Первый метод работает быстрее, но при втором методе требуется меньший объем кода.

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

4.71. Перемещение данных в стек и из стека На вершину стека всегда указывает регистр sp. Для обращения к

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

mov ax,[bp+4] загружает регистр ax содержимым слова в сегменте стека со смещением bp+4.

Однако чаще к стеку обращаются с помощью инструкций push и pop. Инструкция push сохраняет операнд в вершине стека, а инструкция pop извлекает значение из вершины стека и сохраняет его в операнде. Например, инструкции:

mov ax,1 push ax pop bx

Page 77: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

77

заносят значение (равное 1) из регистра ax в вершину стека, затем извлекают 1 из вершины стека и сохраняют ее в bx.

5. ТИПИЧНЫЕ ОШИБКИ ПРИ ВЫПОЛНЕНИИ РАБОТЫ

5.1. Перечень часто встречающихся ошибок В перечень таких ошибок входят:

- открытая процедура или открытый сегмент; - программист забывает о возврате в DOS; - программист забывает о стеке или резервирует маленький стек; - вызывает процедуру, которая портит содержимое нужных регистров; - неопределенные символические имена; - повторное определение символического имени; - неправильный порядок операндов; - неправильное использование операндов; - потеря содержимого регистра при умножении; - не подготовлены регистры при делении; - неправильное использование регистра после деления; - потеря содержимого регистра при делении; - неправильное использование регистров при преобразовании байта в

слово и слова в двойное слово в командах cbw и cwd; - применение команд преобразования cbw и cwd к беззнаковым

данным; - изменение отдельными инструкциями флага переноса; - программист долго не использует состояние флагов; - ошибки при использовании регистров:

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

вычислениях, логических операциях или для непосредственной передачи данных;

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

- выход из диапазона адресов. В каждом языке имеется свое множество ошибок, которые обычно

очень легко сделать, но не всегда просто обнаружить. Не является исключением и язык ассемблера. Типичные ошибки, которые допускаются при программировании на ассемблере, и рекомендации, как можно их избежать, приведены ниже. Источники данной информации: [1], [4], [5], [6].

Page 78: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

78

5.2. Открытая процедура или открытый сегмент [5, с.120-121] Для каждой директивы proc должна быть записана соответствующая

директива endp. Если директива endp пропущена или имя процедуры в записи endp записано неверно, ассемблер генерирует предупреждающее сообщение, что процедура не закрыта надлежащим образом. Точно так же директива ends должна быть задана для каждой директивы segment. Если утверждение ends пропущено или имя сегмента в нем указано неверно, генерируется предупреждающее сообщение, что сегмент открыт. Наиболее вероятной причиной ошибки является неверная запись имени сегмента или процедуры.

sample segment ; Неверные записи proc1 proc near

and al,00 ; а) нет соответствующей директивы endp для ret ; процедуры proc1

; (имя proc1 в записи endp указано неверно) proc endp proc2 proc near ; б) нет соответствующей директивы ends

or al,0ffh ret

proc2 endp end

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

sample segment proc1 proc near

and al,00 ret

proc1 endp proc2 proc near

or al,0ffh ret

proc2 endp sample ends

end 5.3. Программист забывает о возврате в DOS

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

Page 79: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

79

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

codesg segment para ‘Code’ ;сегмент кода DoNothing proc near

nop DoNothing endp codesg ends

end DoNothing Выполняемый код, сгенерированный при ассемблировании и

компоновке данной программы, состоит только из отдельной инструкции nop. В ассемблере директива endp (как и все другие директивы) не генерирует кода, она просто уведомляет ассемблер, что код для процедуры DoNothing закончился, директива ends просто уведомляет ассемблер об окончании сегмента codesg, а директива end DoNothing – о том, что код данного модуля закончился и программа должна начать выполнение с метки DoNothing. Нигде в выполняемом коде не содержится инструкции для передачи управления обратно в операционную систему DOS, когда программа закончится. В результате, когда программа будет запущена, после инструкции nop будут выполняться инструкции, которые случайно окажутся в памяти непосредственно за nop. В этой точке управление будет потеряно, и для возврата в операционную систему DOS может потребоваться программная или аппаратная перезагрузка. Имеется несколько вариантов возврата в DOS. Правильно завершать работу будет, например, следующая версия предыдущей программы, использующая функцию 4Ch:

codesg segment para ‘Code’ ;сегмент кода DoNothing proc near

nop mov ah,4Ch ; функция DOS завершения процесса int 21h ; вызвать DOS для завершения программы

DoNothing endp codesg ends

end DoNothing 5.4. Программист забывает о стеке или резервирует маленький стек

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

Page 80: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

80

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

Не требуется выделять стек в программах, которые предполагается преобразовать в файлы типа .com. Файлы .com выполняются со стеком, расположенным в самой вершине программного сегмента (который имеет размер 64 Кб или меньше, если доступно меньше 64 Кб), поэтому максимальный размер стека в этом случае просто равен объему памяти, оставшейся в программном сегменте. При написании программ в формате .com следует иметь это в виду, так как при увеличении программы соответственно уменьшается стек. Нужно также учитывать, что при работе больших программ в формате .com, выполняемых на компьютерах с небольшой доступной памятью или запущенных из операционной среды DOS наряду с другими программами, могут возникнуть проблемы со стеком. Простейший способ избежать этих потенциальных проблем состоит в написании программ не в формате .com, а в формате .exe с резервированием стека большого объема.

5.5. Вызов подпрограммы, которая портит содержимое нужных регистров

При разработке программы на ассемблере нередко подразумевают, что при обращении к другим процедурам регистры остаются неизмененными. На самом деле это не так. Каждая процедура может сохранить или уничтожить содержимое любого из регистров. Рассмотрим следующий пример. Пусть требуется произвести вычисление по формуле 1000 + w1/10.

datasg segment para ‘Data’ ;сегмент данных w1 dw 200 datasg ends codesg segment para ‘Code’ ;сегмент кода

. . . mov bx,1000 ; bx :=1000 mov ax,w1 ; ax:=w1=200 call DivideBy10 ; разделить элемент на 10 add bx,ax ; вычисление суммы

; (в данном случае получится bx:=bx+ax=10+w1/10), т.е. не правильно ; правильный результат должен быть1000 + w1/10.

Page 81: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

81

. . . ; Подпрограмма для деления значения на 10. ; Ввод: ax – значение, которое требуется разделить на 10 ; Вывод: ax – значение, разделенное на 10 ; dx – остаток значения, деленного на 10 DivideBy10 proc near

mov dx,0 ; подготовить dx:ax как 32-битовое делимое mov bx,10 ; bx – 16-битовый делитель (именно здесь bx:=10)! div bx ret

DivideBy10 endp codesg ends

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

Например, способ 1 – сохранение регистра bx в вызывающей программе до вызова процедуры DivideBy10 и восстановление его тоже в вызывающей программе после вызова процедуры DivideBy10:

mov bx,1000 ; bx :=1000 mov ax,w1 ; ax:=w1=200 push bx ; сохранить bx call DivideBy10 ; разделить элемент на 10 pop bx ; восстановить bx add bx,ax ; вычисление суммы bx:=bx+ax=1000+w1/10 . . . ; (в данном случае получится правильно)

либо регистр bx можно загрузить после вызова процедуры (способ 2): mov ax,w1 ; ax:=w1=200 call DivideBy10 ; разделить элемент на 10 mov bx,1000 ; bx :=1000 add bx,ax ; вычисление суммы

или в начале процедуры DivideBy10 bx заносить содержимое регистра в стек, а при выходе из процедуры извлекать из стека (способ 3):

mov bx,1000 ; bx :=1000 mov ax,w1 ; ax:=w1=200 call DivideBy10 ; разделить элемент на 10 add bx,ax ; вычисление суммы . . .

; Подпрограмма для деления значения на 10. ; Ввод: ax – значение, которое требуется разделить на 10 ; Вывод: ax – значение, разделенное на 10

Page 82: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

82

; dx – остаток значения, деленного на 10 DivideBy10 proc near

push bx ; сохранить bx в стеке mov dx,0 ; подготовить dx: ax как 32-битовое делимое mov bx,10 ; bx –- 16-битовый делитель div bx pop bx ; восстановить bx (извлечь из стека ret

DivideBy10 endp Первый подход к решению проблемы: все подпрограммы, которые

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

5.6. Неопределенные символические имена [5, с.121-122] Ассемблер генерирует сообщение о неопределенном символическом

имени, если имя не определено в поле метки какой-либо строки ассемблерной программы. Если имя определено в другой программе (см. уч. пос., ч.2), то его следует определить как внешнее имя директивой extrn (external — внешний). Неправильная запись имени является наиболее вероятной причиной такой ошибки, особенно в тех случаях, когда используемые шестнадцатеричные константы записываются без начальной цифры.

second proc near mov ax,cs mov ds,ax mov es,ax

; Неверные записи ; а) неопределенное имя value

mov ax,value ; б) некорректная шестнадцатеричная запись

mov bx,ffe2h ; число ffe2h воспринимается как имя: нет нуля впереди ; в) неопределенное имя code

mov cx,code1 mov dx,code2 mov si,code

Page 83: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

83

ret code1 dw 100 code2 dw 200 code3 dw 300 second endp

Ниже приведен образец правильной записи предыдущего примера. Символическое имя value представлено 16-битовым внешним именем. Шестнадцатеричная запись числа начинается с цифры, и неправильно записанное имя code заменено на правильное code3.

second proc near extrn value:word mov ax,cs mov ds,ax mov es,ax mov ax,value mov bx,0ffe2h ; т.к. первый символ– цифра,

; воспринимается как число mov cx,code1 mov dx,code2 mov si,code3 ret

code1 dw 100 code2 dw 200 code3 dw 300 second endp

5.7. Повторное определение символического имени [5, с.122-123] Ассемблер формирует сообщение об ошибке, если одно и то же имя или

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

case1: dec ax ; ax:=ax-1 loop case1 and dx,bx cmp dx,0 jz case3

; Неверные записи case1: ;имя case1 уже было определено

. . . jz case3

Page 84: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

84

Правильная запись предыдущего примера: case1:

dec ax ; ax:=ax-1 ; Неверные записи

loop case1 and dx,bx cmp dx,0 jz case3

case2: . . . jz case3

5.8. Неправильный порядок операндов

Многие программисты ошибаются и изменяют порядок операндов в инструкциях процессора 8086 на обратный. Это, вероятно, связано с тем, что строка

mov ax,bx которая означает "поместить bx в ax", читается слева направо, и это иногда приводит к путанице. Чтобы запомнить порядок операндов в языке ассемблера процессора 8086, нужно строку

mov ax,bx рассматривать как ax := bx

5.9. Неправильное использование операндов В языке ассемблера первый операнд всегда используется в качестве

приемника (кроме синтаксиса АТ&T для UNIX и Linux, см. уч. пос., ч.12). Операнд может быть записан в регистре общего назначения, регистре сегмента или ячейке памяти. При использовании непосредственных данных в качестве операнда-приемника генерируется сообщение об ошибке: 1) неправильная запись 2) правильная запись cmp З,al cmp al,3

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

может изменить состояние процессора, достаточно непосредственны и очевидны. Например, инструкция:

add bx,w1 прибавляет 16-битовое значение по адресу w1 к bx и, чтобы отразить результат сложения, изменяет флаги переполнения, знака, нуля,

Page 85: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

85

дополнительного переноса, четности и переноса. Однако некоторые инструкции изменяют состояние процессора менее очевидным образом, и если программист забывает о необычных побочных эффектах, то возникает ошибка. Одной из таких ошибок является потеря содержимого регистра при умножении. Другие – такие как использование регистров ah, dx и edx (в МП 80386) после операции div и idiv в качестве старших разрядов частного, хотя содержат остаток и т.п., рассмотрены ниже (п.5.12-5.13).

В синтаксисе инструкций mul и imul явно указываются только один из операндов и размер, а регистры, используемые в качестве операнда-приемника, просто подразумеваются. Это приводит к тому, что легко можно упустить из виду использование какого-либо неявного регистра. Есть много случаев, в которых, скажем, программист знает, что результат перемножения 16-разрядного значения на 16-разрядную величину, поместится в регистр ax. При этом часто забывают, что теряется содержимое регистра dx. Поэтому всегда нужно помнить о том, что при использовании инструкций mul и imul уничтожается содержимое не только регистров al, ax или eax (в МП 80386), но также и ah, dx или edx (в МП 80386).

5.11. Не подготовлены регистры при делении Распространенной ошибкой для случаев, когда делимое по размеру

совпадает с делителем и размещено в al или ax, является то, что программист не обнуляет регистры ah, dx.

Пример 1. Не очищается ah при делении байта на байт: ; нет обнуления ah или ax, т.е. пропущена команда xor ah,ah или xor ax,ax

mov al,b1 ; al:=b1 div b2 ; ax используется как делимое (но ah не подготовлен) mov byte ptr rezult,al

Пример 2. Не очищается dx при делении слова на слово. ; пропущена команда зануления dx, т.е. команда xor dx,dx

mov ax,w1 ;ax:=w1 div w2 ; dx:ax используется как делимое (но dx не подготовлен) mov word ptr rezult,ax

5.12. Неправильное использование регистра после деления Не учитывается, что регистры ah и dx содержат остаток и используют

в качестве старших разрядов частного. Пример 1. Ошибочно используется ah после деления байта на байт: mov al,b1 ; b1/b2 div b2 mov word ptr rezult,ax ;ошибка: в ah содержится остаток,

Page 86: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

86

; а не старшие разряды частного (правильно будет mov byte ptr result,al). Пример 2. Ошибочно используется регистр dx после деления слова на

слово: xor dx,dx ;\ mov ax,w1 ; |w1/w2 div w2 ;/ mov word ptr rezult,ax mov word ptr result+2,dx ; ошибка: в dx содержится остаток, а не

; старшие разряды частного. Правильно будет mov word ptr result+2,0 Пример 3. Ошибочно используется регистр dx после деления двойно-

го слова на слово: mov ax,word ptr d1 mov dx,word ptr d1+2 div w1 mov word ptr rezult,ax ; результат деления d1/w1 mov word ptr rezult+2,dx ;ошибка: в регистре dx содержится ; остаток, а не старшие разряды частного ; (правильно будет mov word ptr result+2,0)

Пример ошибочного использования регистра edx после деления учетверенного слова на двойное слово приведен в уч. пос., ч.7.

5.13. Потеря содержимого регистра при делении Потеря содержимого регистра при делении заключается в том, что

теряется значение, помещенное в регистр до операции деления (значение регистров al, ah, ax, dx теряется, т.к. туда заносится частное (в регистры al, ax) или остаток от деления (в регистры ah , dx).

Пример 1. Теряется содержимое ah после деления байта на байт: mov ah,b3 ; ah:=b3 mov al,b1 ; b1/b2 div b2 mov byte ptr rezult,al add al,ah ; ошибка: в регистре ah содержится остаток, а не b3

; (правильно будет команду mov ah,b3 выполнять не до деления, а после). Пример 2. Теряется содержимое dx после деления слова на слово: mov dx,w3 mov ax,w1 ; w1/w2 div w2 mov word ptr rezult,ax mov word ptr result+2,0 ; ошибка: в регистре dx содержится

; остаток, а не w3 (правильно будет команду mov dx,w3 ; выполнять после деления, а не до него).

Page 87: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

87

5.14. Неправильное использование регистров в командах cbw и cwd Неправильное использование регистров при преобразовании байта в

слово и слова в двойное слово заключается либо в ошибочном размещении исходного значения, либо в использовании в качестве результата не регистров ax (dx:ax). Для cbw и cwd исходные значения должны быть размещены в регистрах al и ax, соответственно. Программисты же иногда ошибочно помещают исходное значение в какой-нибудь другой регистр (например, в bl или bx).

Пример 1. mov bl,b3 ; bl := b3 cbw ; ошибка: результат, получившийся в ax, не имеет никакого ; отношения к регистру bl (а значит, и к b3) Пример 2. mov al,b3 ; al := b3 cbw ; результат получился в регистре ax mov rez_w,bx ; ошибка: в bx не содержится результат выполнения ; команды cbw

5.15. Применение команд преобразования cbw и cwd к беззнаковым данным

При применении команд cbw и cwd к беззнаковым данным может возникнуть ошибка. Когда знаковый бит равен единице, старший байт или слово соответственно заполняется единицами, а не нулями, как это требуется в данном случае. Это надо учитывать при выполнении логических операций и операций сдвига и вместо инструкций cbw и cwd применять зануление старшего байта или слова командой xor. Например, если al= 128 (т.е. 100000002), то после выполнения команды cbw в регистре ax будет число 65408 (т.е. 11111111100000002), а должно остаться равным 128, но расширенным на 16 битов (т.е. 00000000100000002).

5.16. Изменение отдельными инструкциями флага переноса В то время как некоторые инструкции "непредвиденным" образом

изменяют содержимое регистров или флагов, другие инструкции не влияют на все те флаги, изменения которых вы ожидаете. Например, инструкция

inc ah выглядит логически эквивалентной инструкции

add ah,1 и это действительно так, но инструкция add в случае слишком большого для операнда-приемника результата устанавливает флаг переноса, а инструкция inc на флаг cf не влияет. В результате инструкции

add ax,1 ; ax := ax+1 (и cf:=1, если возник перенос)

Page 88: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

88

adc dx,0 ; dx := dx+0+<значение cf> можно использовать для увеличения 32-битового значения, хранящегося в регистрах dx: ax, а инструкции

inc ax ; ax:=ax+1 (cf не меняется, даже если возник перенос) adc dx,0

нельзя. То же самое имеет место для инструкции dec. Инструкции loop, loopz и loopnz также не влияют на состояние флагов (см. уч. пос., ч.6 и 7). Это можно использовать, например, в тех случаях, когда нужно организовать цикл и при этом не изменять значения флагов, в т.ч. и флага переноса.

5.17. Программист долго не использует состояние флагов Состояние флагов сохраняется до тех пор, пока следующая

инструкция их не изменит. Обычно это не слишком долгий интервал времени. Хорошей практикой программирования является возможно скорейшее использование флагов их установки, что позволяет избежать многих потенциальных ошибок. Например, часто хочется проверить условие, задать содержимое одного-двух регистров и только после этого в соответствии с результатом проверки выполнить переход. Инструкции:

cmp ax,1 ;вычисление (ax-1) без присвоения полученного значения ; ах и присвоение значений (0 или 1 – зависит от результата) флагам: ; нуля (zf), знака (sf), переноса (cf) и других (of , af и pf)

mov ax,0 ;ax:=0 значения флагов не изменяет jg Positive ; если больше (т.е если zf=0 и sf=of), переход на Positive

представляют собой допустимый способ проверки состояния регистра ax, установки его в значение 0 и обработки результата. А инструкции:

cmp ax,1 sub ax,ax ; присвоение значений (0 или 1 – зависит от результата)

; флагам:нуля (zf), знака (sf), переноса (cf) и других (of , af и pf) jg Positive

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

5.18. Ошибки при использовании регистров При использовании регистров для записи операндов в ассемблерной

программе необходимо соблюдать следующие правила: 1. Нельзя задавать 8- и 16-разрядный (а для процессора 80386 также 8-

и 32-разрядный или 16- и 32-разрядный) регистры для записи двух

Page 89: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

89

операндов одной команды (это правило не распространяется на команды movsx и movzx, см. уч. пос., ч.7).

2. Операции со стеком должны осуществляться только в 16-битовых кодах. Если 8-разрядный регистр указывают для работы со стеком (push/pop), то выдается сообщение об ошибке.

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

add ax,dl ; а) одновременное использование ; 8-битового регистра (dl) и 16-битового регистра (ax) push bl ; б) 8-разрядный регистр указывают для работы со стеком add ds,100 ; в) сегментный регистр ds используется при сложении mov es,200 ; г) непосредственный операнд передается в регистр es mov ss,cs ; д) оба операнда являются сегментными регистрами

Ниже приведена правильная запись предыдущих примеров xor dh,dh add ax,dx ; а) xor bh,bh push bx ; б) add cx,100 ; в) mov cx,200 ; г) mov es,cx mov cx,cs ; д) mov ss,cx

Page 90: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

90

5.19. Выход из диапазона адресов [5, с.124-125] Все команды условного перехода используют режим относительной

адресации с 8-битовым смещением. Если относительный адрес символа, используемого в качестве операнда-адреса перехода, выходит за диапазон + 127 байтов -128 байтов от конца команды условного перехода, выдается сообщение об ошибке.

Неверные записи and al,7fh je next_proc ;между символическим адресом end_proc и next_proc

; более 127 байтов (это важно, т .к. при выполнении end_proc: ; команды je указатель команды (ip) показывает ; на end_proc, а перейти надо на next_proc)

ret data dw 300 dup(?) next_proc:

clc

Ниже приведена правильная запись предыдущего примера: and al,7fh jne end_proc jmp next_proc

end_proc: ret

data dw 300 dup(?) next_proc:

clc Библиографический список

1. Зубков С.В. Assembler для DOS, Windows и UNIX.–3-е изд., стер.– М.: ДМК Пресс; СПб.: Питер, 2005.– 608 с.

2. Бурдаев О.В., Иванов М.А., Тетерин И.И. Ассемблер в задачах защиты информации/ Под ред. И.Ю.Жукова. – М.: КУДИЦ-ОБРАЗ, 2002. – 320 с.

3. Абель Питер. Ассемблер и программирование для IBM PC. Британская Колумбия. Технологический институт.

4. Олейник Л.Е. Язык ассемблера для микропроцессора 8086: Курс лекций. – Омск: Сибирская региональная школа бизнеса, 2000.

5. Дао. Л. Программирование микропроцессора 8088. – М.: Мир, 1988. – 356 с.

6. Абель Питер. Язык и программирование для IBM PC: Пер. с англ.– Киев: Век; М.: Энтроп; Киев: НТИ, 2003. – 736 с.

Page 91: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

91

ПРИМЕРЫ (ТЕКСТЫ) ПРОГРАММ Пример 1.1

;lab1pr1.asm ред. 03_11_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) выводит на экран сообщение "Привет, уважаемый ; пользователь!" + ожидает нажатия клавиши пользователем ;Компиляция: tasm.exe lab1pr1.asm ; tlink.exe lab1pr1.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' ; segment – директива, показывающая начало

db 32 dup(?) ; сегмента с именем stacksg stacksg ends ; ends – директива, показывающая конец этого сегмента ;-сегмент данных---------------------------------- datasg segment para 'Data' ; segment – директива, показывающая начало ; сегмента с именем datasg msg db "Привет, уважаемый пользователь!","$" msg_e db "Для выхода нажмите любую клавишу!","$" datasg ends ; ends – директива, показывающая конец этого сегмента ;- сегмент кода---------------------------------- codesg segment para 'Code' ; директива, показывающая начало сегмента codesg main proc far ; proc– директива, показывающая начало процедуры с именем main

assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая ; соответствие сегментных регистров (cs, ds, ss) сегментам ; следующие пять строк должны быть в любой EXE-программе

push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax push ax mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных)

;--------- вывод на экран сообщения mov ah,09h ; функция вывода на экран (регистр ah:=09h) lea dx,msg ; загрузить в регистр dx адрес начала строки ; «Привет, уважаемый пользователь» int 21h ; передача управления DOS ;--------- вывод на экран сообщения mov ah,09h ; функция вывода на экран (регистр ah:=09h) lea dx,msg_e ; загрузить в регистр dx адрес начала строки int 21h ; "Для выхода нажмите любую клавишу!" mov ah,0 ; ожидание нажатия клавиши int 16h ret ; возврат в DOS main endp ; ends – директива, показывающая конец процедуры main codesg ends ; ends – директива, показывающая конец сегмента codesg end main ; end – директива, показывающая конец программы и определяющая ; входную точку программы, с которой начинается выполнение программы, т.е. main – первая цифра в номере примера (до точки) обозначает номер части учебного пособия «Языки программирования»

Page 92: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

92

Пример 1.2 ;lab1pr2.asm ред. 02_06_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) обеспечивает ввод с клавиатуры байта + ;перевод из кодов ASCII (символы) в bin (двоичное число). ;Компиляция: tasm.exe lab1pr2.asm ; tlink.exe lab1pr2.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) db 32 dup(?) ;стек состоит из 32 байтов stacksg ends ; конец сегмента ;-сегмент данных---------------------------------- datasg segment para 'Data' ;сегмент данных тоже должен начинаться на границе ; параграфа msg_b1 db "b1=",0dh,0ah, "$" msg_e db "Для выхода нажмите любую клавишу!",0dh,0ah,"$" msg_err1 db "Ошибка#1: ошибка ввода!",0dh,0ah,"$" ; Список параметров для ввода переменной, значение которой вмещается в один байт vvod_b label byte maxlen_b db 4 ;максимальное кол-во символов, вводимых с клавиатуры, вкл. ENTER fact_b db 0 ;фактическое кол-во символов, вводимых с клавиатуры, вкл. код ENTER simv_b db "0000" ;сюда вводятся символы в ASCII-(1 как 31h, 2 как 32h и т.д.) b1 db 0 ; двоичное значение переменной b1 (сюда оно заносится после

; преобразования процедурой ASCII_bin-b) prom dw 0 ; рабочие ячейки процедуры ASCII_bin_b osh_v db 0 datasg ends ; конец сегмента данных ;- сегмент кода---------------------------------- codesg segment para 'Code' main proc far ; начало процедуры assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных) snova: mov ah,09h ; функция вывода на экран сообщения (регистр ah=09) lea dx,msg_b1 ; загрузить в dx адрес начала строки «b1= » int 21h ; передача управления DOS mov ah,0ah ; функция ввода с клавиатуры (ah=0ah) lea dx,vvod_b ; загрузить адреса списка параметров int 21h ; передача управления в DOS call ASCII_bin_b ; вызов процедуры преобразования из кодов ASCII в двоичный ; (bin) для переменной, помещающейся в байт

Page 93: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

93

mov b1,al ;занесение полученного значения из al в ячейку памяти b1 ; проверка признака ошибки (osh_v=0 – во введенных данных нет ошибки; ; osh_v не равна (<>) нулю, означает ошибку). cmp osh_v, 0 ; сравнение и присвоение zf:=1, если операнды равны, т.е. osh_v =0 ; или zf:=0, если операнды не равны, т.е. osh_v <> 0(есть ошибка) jz s1 ; переход на метку s1, если флаг нуля (zf) =1 ; иначе переход к следующей команде (jmp snova) jmp snova ;безусловный переход на метку snova s1: mov ah,09h lea dx,msg_e ; вывод на экран сообщения “Для выхода нажмите любую клавишу!" int 21h mov ah,0 ; ожидание нажатия клавиши int 16h ret ;возврат в DOS main endp ;-процедуры----------------------------- ASCII_bin_b proc ;процедура перевода из ASCII в bin для байта ;(Вход: в ячейке simv_b списка параметров введенные символы (цифры!) вASCII-кодах; ; в ячейке fact_b – количество введенных символов, включая код клавиши ENTER ; выход: al= двоичное число; при вводе не цифры - osh_v :=1) xor ax,ax xor cx,cx mov prom,0 mov osh_v,0 mov al,fact_b mov cl,al dec al mov si,ax mov bx,1 met1_b: mov al,simv_b[si] cbw ; преобразование байта в слово (ax:=al). Способ – распространение ; знака (в регистре al) на старший байт слова (в регистре ax) cmp ax,30h ; сравнение и zf:=1, если операнды равны, т.е. ax=30h (т.е. 0011 0000), ; и sf:=1, если ax<30h jb error_b ; переход на error_b, если sf=1, т.е. если ax <30h cmp ax,39h ; сравнение и zf:=0, если операнды не равны (ax<>39h, т.е. 0011 1001), ; и sf:=0, если ax>39h ja error_b ; переход на error_b, если sf=0 и zf=0, т.е. если ax >39h and al,0fh ; зануление четырех старших битов в байте (т.е. в регистре al) mul bx add prom,ax mov ax,bx mov bx,10 mul bx mov bx,ax

Page 94: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

94

dec si loop met1_b mov ax,prom jmp end_error_b ;безусловный переход на метку end_error_b error_b: mov ah,09h ; вывод на экран сообщения lea dx,msg_err1 ; "Ошибка#1: ошибка ввода int 21h mov osh_v,1 ; osh_v := 1 end_error_b: ret ; возврат в DOS ASCII_bin_b endp ; endp – директива, показывающая конец процедуры ASCII_bin_b codesg ends ; ends – директива, показывающая конец сегмента codesg end main ; end – директива, показывающая конец программы и определяющая ; входную точку программы (точку, с которой начинается выполнение программы) ==================================================================

Пример 1.3 ;lab1pr3.asm ред. 17_12_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) обеспечивает ввод с клавиатуры слова ; + перевод из кодов ASCII (символы) в bin (двоичное число). ;Компиляция: tasm.exe lab1pr3.asm ; tlink.exe lab1pr3.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' ; segment – директива, показывающая начало db 128 dup(?) ; сегмента с именем stacksg stacksg ends ; ends – директива, показывающая конец этого сегмента ;-сегмент данных---------------------------------- datasg segment para 'Data' ; segment – директива, показывающая начало ; сегмента с именем datasg msg_b1 db "b1=",0dh,0ah,"$" msg_w1 db "w1=",0dh,0ah,"$" msg_e db "Для выхода нажмите любую клавишу!", 0dh,0ah,"$" msg_err1 db "Ошибка#1: ошибка ввода!", 0dh,0ah,"$" ascval db "00000000000000000000",0dh,0ah,"$" perevod_cursora db 0dh,0ah,"$" ; строки от директивы COMMENT @ до символа @ не используются (закомментированы) COMMENT @ vvod_b label byte maxlen_b db 4 fact_b db 0 simv_b db "0000" @ ; Список параметров для ввода переменной, значение которой вмещается в одно слово vvod_w label byte maxlen_w db 6 ;максимальное кол-во символов, вводимых с клавиатуры, вкл. ENTER fact_w db 0 ;фактическое кол-во символов, вводимых с клавиатуры, вкл. код ENTER

Page 95: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

95

simv_w db "000000" ;сюда вводятся символы в ASCII-(‘1’ как 31h, ‘2’ как 32h и т.д.) b1 db 0 ; в данном примере не используется w1 dw 0 ; двоичное значение переменной w1 (сюда оно заносится после

; преобразования процедурой ASCII_bin_w) prom dw 0 ; рабочие ячейки процедуры ASCII_bin_w osh_v db 0 datasg ends ; конец сегмента данных ;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с дреса, ; кратного шестнадцати, т.е. на границе параграфа) main proc far ; начало процедуры (main–имя процедуры; far– дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds mov ds,ax ; (заносится адрес начала сегмента данных) mov ax,0600h ; ah=06(прокрутка), al=00(весь экран) mov bh,07 ; нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана верхняя левая позиция mov dx,314fh ; нижняя правая позиция int 10h ; передача управления в BIOS mov ah,02 ; установка курсора mov bh,00 ; экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; столбец 00 int 10h ; передача упр. в BIOS snova: mov ah,09h ; функция вывода на экран сообщения (ah=09) lea dx,msg_w1 ; загрузить адрес начала строковой переменной в dx int 21h ; передача управления DOS mov ah,0ah ; функция ввода с клавиатуры (ah=0ah) lea dx,vvod_w ; загрузить адреса списка параметров int 21h ; передача управления в DOS call ASCII_bin_w ;вызов процедуры перевода из ASCII в двоичный ; (bin) для переменной, помещающейся в слово mov w1,ax ;занесение полученного значения из ax в ячейку памяти w1 ; проверка признака ошибки (osh_v=0 – во введенных данных нет ошибки; ; osh_v не равна (<>)нулю, означает ошибку). cmp osh_v,0 ;сравнение и присвоение zf:=1, если операнды равны, т.е. если osh_v =0, ; если же операнды не равны, т.е. если osh_v <> 0(есть ошибка), то zf:=0 jz s1 ; переход на метку s1, если установлен флаг нуля (zf) =1 ; иначе переход к следующей команде (jmp snova) jmp snova ;безусловный переход на метку snova s1: mov ah,02 ; установка курсора

Page 96: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

96

mov bh,00 ; экран 0 mov dh,24 ; управление курсором | строка 24 mov dl,00 ; столбец 00 int 10h ; передача упр. в BIOS mov ah,09h lea dx,msg_e ; вывод на экран сообщения int 21h ; "Для выхода нажмите любую клавишу!" mov ah,0 ; ожидание нажатия клавиши int 16h ret ; возврат в DOS main endp ;-процедуры----------------------------- ; Процедура в данном примере не используется COMMENT @ ASCII_bin_b proc ;процедура перевода из ASCII в bin для байта ;(Вход: в ячейке simv_b списка параметров введенные символы (цифры!) вASCII-кодах; ; в ячейке fact_b – количество введенных символов, включая код клавиши ENTER ; выход: al= двоичное число; при вводе не цифры - osh_v :=1) xor ax,ax xor cx,cx mov prom,0 mov osh_v,0 mov al,fact_b ; количество введенных символов, включая код клавиши ENTER mov cl,al dec al ; количество введенных символов, без кода клавиши ENTER mov si,ax mov bx,1 met1_b: mov al,simv_b[si] cbw ; преобразование байта в слово (ax:=al). Способ – распространение ; знака (в регистре al) на старший байт слова (в регистре ax) cmp ax,30h ; сравнение и zf:=1, если операнды равны, т.е. ax=30h (т.е. 0011 0000), ; и sf:=1, если ax<30h jb error_b ; переход на error_b, если sf=1, т.е. если ax <30h cmp ax,39h ; сравнение и zf:=0, если операнды не равны (ax<>39h, т.е. 0011 1001), ; и sf:=0, если ax>39h ja error_b ; переход на error_b, если sf=0 и zf=0, т.е. если ax >39h and al,0fh ; зануление четырех старших битов в байте (т.е. в регистре al) mul bx add prom,ax mov ax,bx mov bx,10 mul bx mov bx,ax dec si loop met1_b mov ax,prom jmp end_error_b

Page 97: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

97

error_b: mov ah,09h ; вывод на экран сообщения lea dx,msg_err1 ; "Ошибка#1: ошибка ввода int 21h mov osh_v,1 ; osh_v := 1 end_error_b: ret ; возврат в DOS ASCII_bin_b endp ; конец процедуры @ ASCII_bin_w proc ;процедура перевода из ASCII в bin для слова ;(Вход: в ячейке simv_w списка параметров введенные символы (цифры) вASCII-кодах; ; в ячейке fact_w – количество введенных символов, включая код клавиши ENTER ; выход: ax= двоичное число; при вводе не цифры – osh_v :=1) xor ax,ax xor cx,cx mov prom,0 mov osh_v,al mov al,fact_w mov cl,al dec al mov si,ax mov bx,1 met1_w: mov al,simv_w[si] cbw ; преобразование байта в слово (ax:=al). Способ – распространение ; знака (в регистре al) на старший байт слова (в регистре ax) cmp ax,30h ; сравнение и zf:=1, если операнды равны, т.е. ax=30h (т.е. 0011 0000), ; и sf:=1, если ax<30h jb error_w ; переход на error_b, если sf=1, т.е. если ax <30h cmp ax,39h ; сравнение и zf:=0, если операнды не равны (ax<>39h, т.е. 0011 1001), ; и sf:=0, если ax>39h ja error_w ; переход на error_b, если sf=0 и zf=0, т.е. если ax >39h and al,0fh ; зануление четырех старших битов в байте (т.е. в регистре al) mul bx add prom,ax mov ax,bx mov bx,10 mul bx mov bx,ax dec si loop met1_w mov ax,prom jmp end_error_w ; безусловный переход на метку end_error_b error_w: mov ah,09h ; вывод на экран сообщения lea dx,msg_err1 ; "Ошибка#1: ошибка ввода int 21h mov osh_v,1 ; osh_v := 1

Page 98: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

98

end_error_w: ret ; возврат в DOS ASCII_bin_w endp ; конец процедуры ; Процедура в данном примере не используется COMMENT @ cursor proc ;процедура перевода курсора на след. строку mov ah,09 lea dx,perevod_cursora int 21h ret cursor endp @ codesg ends ; ends – директива, показывающая конец сегмента end main ; end – директива, показывающая конец программы и определяющая ; входную точку программы (точку, с которой начинается выполнение программы) ==================================================================

Пример 1.4 ;lab1pr4.asm ред. 17_12_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) обеспечивает ввод с клавиатуры дв. слова ; + перевод из кодов ASCII (символы) в bin (двоичное число). ;Компиляция: tasm.exe lab1pr4.asm ; tlink.exe lab1pr4.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) db 128 dup(?) ;стек состоит из 128 байтов stacksg ends ; конец сегмента ;-сегмент данных---------------------------------- datasg segment para 'Data' ;сегмент данных тоже должен начинаться на ; границе параграфа msg_b1 db "b1=",0dh,0ah,"$" msg_w1 db "w1=",0dh,0ah,"$" msg_d1 db "d1=","$" msg_e db "Для выхода нажмите любую клавишу!", 0dh,0ah,"$" msg_err1 db "Ошибка#1: ошибка ввода!", 0dh,0ah,"$" ; ascval db "00000000000000000000",0dh,0ah,"$" ;perevod_cursora db 0dh,0ah,"$" ; строки от директивы COMMENT @ до символа @ не используются COMMENT @ ; (закомментированы) vvod_b label byte maxlen_b db 4 fact_b db 0 simv_b db "0000" vvod_w label byte maxlen_w db 6 fact_w db 0 simv_w db "000000"

Page 99: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

99

@ ; Список параметров для ввода переменной, значение которой вмещается в дв. слово vvod_d label byte maxlen_d db 11 ;максимальное кол-во символов, вводимых с клавиатуры, вкл. ENTER fact_d db 0 ;факт. кол-во сим-лов, вв. с клавиатуры, вкл. ENTER (заполняет MS-DOS) simv_d db "00000000000" b1 db 0 ; в данном примере не используется w1 dw 0 ; в данном примере не используется prom dw 0 ; в данном примере не используется d1 dd 0 ; двоичное значение переменной d1 (сюда оно заносится ; после преобразования процедурой ASCII_bin_d) promd dd 0 ; рабочие ячейки процедуры ASCII_bin_d fml dd 0 osh_v db 0 datasg ends ; конец сегмента данных ;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) main proc far ; начало процедуры (main – имя процедуры; far – дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных) ;--------- mov ax,0600h ;ah=06(прокрутка), al=00(весь экран) mov bh,07 ; нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; нижняя правая позиция int 10h ; передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS snova: mov ah,09h ; функция вывода на экран сообщения (ah=09) lea dx,msg_d1 ; загрузить в dx адрес начала строки «d1= » int 21h ; передача управления в DOS mov ah,0ah ; функция ввода с клавиатуры (ah=0ah) lea dx,vvod_d ; загрузить адреса списка параметров int 21h ; передача управления в DOS call ASCII_bin_d ;вызов процедуры перевода из ASCII в двоичный ; (bin) для переменной, помещающейся в двойное слово

Page 100: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

100

mov word ptr d1,ax ;занесение полученного значения из ax в d1 и d1+1 mov word ptr d1+2,dx ; и из dx в d1+2 и d1+3 ; проверка признака ошибки (osh_v=0 – во введенных данных нет ошибки; ; osh_v не равна (<>)нулю, означает ошибку). cmp osh_v,0 ; сравнение и присвоение zf:=1, если операнды равны, т.е. osh_v =0, ; если же операнды не равны, т.е. osh_v <> 0(есть ошибка), то zf:=0 jz s1 ; переход на метку s1, если флаг нуля (zf) =1, ; иначе переход к следующей команде (jmp snova) jmp snova ;безусловный переход на метку snova s1: ;------- mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 24 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS mov ah,09h lea dx,msg_e ; вывод на экран сообщения int 21h ; "Для выхода нажмите любую клавишу!" mov ah,0 ;ожидание нажатия клавиши int 16h ; ret ; возврат в DOS main endp ;-процедуры----------------------------- ; Процедуры, которые в данном примере не используются COMMENT @ ASCII_bin_b proc ;процедура перевода из ASCII в bin для байта ASCII_bin_w proc ;процедура перевода из ASCII в bin для слова @ ASCII_bin_d proc ;процедура перевода из ASCII в bin для дв. слова для МП 8086 ; выход: =число в bin) ;(Вход: в ячейке simv_d списка пар-ров введенные символы (цифры!) в ASCII-кодах; ; в ячейке fact_d – количество введенных символов, включая код клавиши ENTER ; выход: dx:ax = двоичное число; при вводе не цифры – osh_v :=1) xor ax,ax xor bx,bx xor cx,cx mov word ptr promd,0 mov word ptr promd+2,0 mov word ptr fml+2,0 mov word ptr fml,1 mov osh_v,0 mov al,fact_d mov cl,al dec al mov si,ax met1_d: mov bl,simv_d[si]

Page 101: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

101

cmp ax,30h ; сравнение и zf:=1, если операнды равны, т.е. ax=30h (т.е. 0011 0000), ; и sf:=1, если ax<30h jb error_b ; переход на error_b, если sf=1, т.е. если ax <30h cmp ax,39h ; сравнение и zf:=0, если операнды не равны (ax<>39h, т.е. 0011 1001), ; и sf:=0, если ax>39h ja error_b ; переход на error_b, если sf=0 и zf=0, т.е. если ax >39h and al,0fh ; зануление четырех старших битов в байте (т.е. в регистре al) and bl,0fh mov dx,0 mov ax,0 abd1: cmp bl,0 jz abd2 add ax,word ptr fml adc dx,word ptr fml+2 dec bl jmp abd1 abd2: add word ptr promd,ax adc word ptr promd+2,dx mov bl,9 mov dx,word ptr fml+2 mov ax, word ptr fml abd3: cmp bl,0 jz abd4 add word ptr fml,ax adc word ptr fml+2,dx dec bl jmp abd3 abd4: dec si loop met1_d mov dx,word ptr promd+2 mov ax,word ptr promd jmp end_error_d error_d: mov ah,09h ; вывод на экран сообщения lea dx,msg_err1 ; "Ошибка#1: ошибка ввода int 21h mov osh_v,1 ; osh_v := 1 end_error_d: ret ; возврат в DOS ASCII_bin_d endp ; конец процедуры ; Процедура в данном примере не используется COMMENT @ cursor proc ;процедура перевода курсора на след. строку @ codesg ends ; ends – директива, показывающая конец сегмента end main ; конец программы ==================================================================

Page 102: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

102

Пример 1.5

;lab1pr5.asm ред. 17_12_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) осуществляет перевод из bin (двоичное число) в ASCII ; (значения берутся из ячеек памяти) + вывод на экран результата. ;Компиляция: tasm.exe lab1pr5.asm ; tlink.exe lab1pr5.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' db 128 dup(?) stacksg ends ;-сегмент данных---------------------------------- datasg segment para 'Data' msg_b1 db "b1=",0dh,0ah,"$" msg_w1 db "w1=",0dh,0ah,"$" msg_d1 db "d1=",0dh,0ah,"$" msg_err1 db "Ошибка#1: ошибка ввода!", 0dh,0ah,"$" msg_e db "Для выхода нажмите любую клавишу!", 0dh,0ah,"$" ascval db "000000000000",0dh,0ah,"$" ; 12 нулей (под дв. слово в символьном виде) perevod_cursora db 0dh,0ah,"$" COMMENT @ vvod_b label byte maxlen_b db 4 fact_b db 0 simv_b db "0000" vvod_w label byte maxlen_w db 6 fact_w db 0 simv_w db "000000" vvod_d label byte maxlen_d db 11 fact_d db 0 simv_d db "00000000000" @ b1 db 255 w1 dw 65535 d1 dd 2147483647 COMMENT @ prom dw 0 promd dd 0 fml dd 0 osh_v db 0 @ rezult dq 0 kol dq 0 datasg ends ; конец сегмента данных

Page 103: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

103

;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) main proc far ; начало процедуры (main – имя процедуры; far – дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных) mov ax,0600h ; ah=06(прокрутка), al=00(весь экран) mov bh,07 ; нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; нижняя правая позиция int 10h ; передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS snova: mov ah,09h ; функция вывода на экран сообщения lea dx,msg_b1 ; "b1=" int 21h ; передача управления в DOS xor ax,ax mov al,b1 mov word ptr rezult,ax call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; функция вывода на экран сообщения lea dx,ascval ; число 255, т.е. значение b1 (в кодах ASCII) int 21h mov ah,09h ; функция вывода на экран lea dx,msg_w1 ; "w1=" int 21h mov ax,w1 mov word ptr rezult,ax call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран содержимого ячейки ascval lea dx,ascval ; т.е. значение w1, равное 65535 (в кодах ASCII) int 21h mov ah,09h ; вывод на экран сообщения lea dx,msg_d1 ; "d1=" int 21h mov ax,word ptr d1 ; мл.слово d1 в регистр ax

Page 104: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

104

mov dx,word ptr d1+2 ; ст.слово d1 в регистр dx mov word ptr rezult,ax mov word ptr rezult+2,dx ; rezult:= d1 call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx,ascval ; число 2 147 483 647, т.е. значение d1 (в кодах ASCII) int 21h mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 23 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS mov ah,09h ; вывод на экран сообщения lea dx,msg_e ; "Для выхода нажмите любую клавишу!" int 21h mov ah,0 ;-ожидание нажатия клавиши int 16h ret ;возврат в DOS main endp ;-процедуры-----------------------------

; Процедуры в данном примере не используются COMMENT @ ASCII_bin_b proc ;процедура перевода из ASCII в bin для байта

(Вход: список параметров vvod_b должен быть заполнен; выход: al=число в bin) ASCII_bin_w proc ;процедура перевода из ASCII в bin для слова

(Вход: список параметров vvod_w должен быть заполнен; выход: ax=число в bin) ASCII_bin_d proc ;процедура перевода из ASCII в bin для дв. слова для МП 8086

(Вход: список параметров vvod_d должен быть заполнен; выход: dx:ax=число в bin) @ bin_ASCII proc ;процедура перевода из bin (двоичное) в ASCII ;( Вход: rezult=число двоичное); ; выход: ascval= число в ASCII) call clrascval ;вызов процедуры очистки строковой переменной ascval lea si,ascval+11 ; изменено на 11 (в связи с изменением кол-ва символов в ascval) m1: cmp word ptr rezult+6,0 ;сравнение слова с нулем и zf:=1, если операнды равны jnz m2 ; переход на m2, если zf=0 cmp word ptr rezult+4,0 ; rezult+4 равен нулю? и zf:=1, если операнды равны jnz m2 ; переход на m2, если zf=0 cmp word ptr rezult+2,0 jnz m2 cmp word ptr rezult,10 ; слово rezult равно десяти? и zf:=1, если равно ; cf:=0, если слово rezult больше или равно десяти jnb m2 ; переход на m2, если cf=0 mov ax,word ptr rezult or al,30h

Page 105: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

105

mov [si],al dec si jmp m3 m2: sub word ptr rezult,10 sbb word ptr rezult+2,0 sbb word ptr rezult+4,0 sbb word ptr rezult+6,0 ; result := result – 10

add word ptr kol,1 adc word ptr kol+2,0 adc word ptr kol+4,0 adc word ptr kol+6,0 ; kol := kol + 1 jmp m1 m3: cmp word ptr kol+6,0 jne m4 cmp word ptr kol+4,0 jne m4 cmp word ptr kol+2,0 jne m4 cmp word ptr kol,0 jne m4 ret m4: mov ax,word ptr kol mov word ptr rezult,ax

mov ax,word ptr kol+2 mov word ptr rezult+2,ax

mov ax,word ptr kol+4 mov word ptr rezult+4,ax

mov ax,word ptr kol+6 mov word ptr rezult+6,ax ; result (учетверенное слово) := kol (учетверенное слово)

mov word ptr kol,0 mov word ptr kol+2,0 mov word ptr kol+4,0 mov word ptr kol+6,0 ; kol (учетверенное слово) := 0 jmp m1 bin_ASCII endp ; конец процедуры clrascval proc ; процедура ‘ближняя’, т.е. типа near (по умолчанию) mov cx,12 ; изменено на 12 (в связи с изменением к-ва символов в ascval); было 20 mov si,11 ; изменено на 11 (в связи с изменением к-ва символов в ascval); было 19 clr1: and ascval [si],30h dec si

Page 106: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

106

loop clr1 ret clrascval endp ; конец процедуры cursor proc ;процедура перевода курсора на след. строку mov ah,09 lea dx,perevod_cursora int 21h ret cursor endp codesg ends ; ends – директива, показывающая конец сегмента end main ; конец программы ===================================================================

Пример 1.6 ;lab1pr6.asm ред. 17_12_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (МП 8086) вычисляет по формулам: b1+b2; w1+w2; w1-b1; d1+d2 ;Компиляция: tasm.exe lab1pr6.asm ; tlink.exe lab1pr6.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' db 1024 dup(?) stacksg ends ;-сегмент данных------------------------------- datasg segment para 'Data' msg_b1 db "b1=",0dh,0ah,"$" msg_w1 db "w1=",0dh,0ah,"$" msg_d1 db "d1=",0dh,0ah,"$" msg_b1b2 db "b1+b2=",0dh,0ah,"$" msg_w1w2 db "w1+w2=",0dh,0ah,"$" msg_d1d2 db "d1+d2=",0dh,0ah,"$" msgd1_d3 db "d1-d3=",0dh,0ah,"$" msg_w1b1 db "w1-b1=",0dh,0ah,"$" msg_e db "Для выхода нажмите любую клавишу!", 0dh,0ah,"$" msg_err1 db "Ошибка#1: ошибка ввода!", 0dh,0ah,"$" ascval db "000000000000",0dh,0ah,"$" ; 12 нулей (под дв. слово в символьном виде) perevod_cursora db 0dh,0ah,"$" ; сюда вставляются списки параметров (из файла vvod_bwd.asm) include vvod_bwd.asm ; include – директива, вставляющая в текст программы текст ; файла (в данном ; случае вставляется текст файла vvod_bwd.asm ) b1 db 255 b2 db 10 w1 dw 65535 w2 dw 1000 d1 dd 2147483647 d2 dd 3000000000 d3 dd 147483647 prom dw 0 promd dd 0

Page 107: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

107

fml dd 0 osh_v db 0 rezult dq 0 kol dq 0 datasg ends ; конец сегмента данных ;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) main proc far ; начало процедуры (main – имя процедуры; far– дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных) ;--------- mov ax,0600h ;\ | ah=06(прокрутка),al=00(весь экран) mov bh,07 ; \ | нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; / | нижняя правая позиция int 10h ;/ | передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS snova: xor ax,ax ;\ mov al,b1 ; | b1+b2 add al,b2 ; | adc ah,0 ;/ mov word ptr rezult,ax ; result := b1+b2 call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx,msg_b1b2 ; "b1+b2=" int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного результата (265=255+10) int 21h call cursor xor dx,dx ;\ mov ax,w1 ; | w1+w2 add ax,w2 ; | adc dx,0 ;/ mov word ptr rezult,ax

Page 108: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

108

mov word ptr rezult+2,dx call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx,msg_w1w2 ; "w1+w2=" int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного результата (66535=65535+1000) int 21h call cursor mov ax,w1 ;\ sub al,b1 ; | w1-b1 sbb ah,0 ;/ ; др. вариант разности: ; xor ax,ax ; mov al,b1 ; sub w1,ax ; mov ax,w1 mov word ptr rezult,ax call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx,msg_w1b1 ; "w1-b1=" int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного результата (65280=65535-255) int 21h call cursor ; В примере lab1pr6.asm: ; mov ax,word ptr d1 ; ; mov dx,word ptr d1+2 ; ; sbb ax,word ptr d2 ; ; sbb dx,word ptr d2+2 ;/ d1- d2 ; mov word ptr rezult,ax ; младшее слово разности (в rezult и rezult+1) ; mov word ptr rezult+2,dx ; старшее слово разности (в rezult+2 и rezult+3) xor cx,cx mov ax,word ptr d1 mov dx,word ptr d1+2 add ax,word ptr d2 adc dx,word ptr d2+2 ;Т.к. сумма двух двойных слов не помещается в двойном слове, надо учесть перенос в ; старшее (третье) слово: adc cx,0 ;cx:=cx+0+cf=0+0+(cf=1, если перенос был, или cf=0, если его не было) ; Сумма d1+d2 получается в трех регистрах: ax, bx и cx ; подготовка к вызову процедуры call bin_ASCII (она получает данные в ячейке rezult)

mov word ptr rezult,ax mov word ptr rezult+2,dx mov word ptr rezult+4,cx ; rezult := d1+d2

Page 109: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

109

call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx,msg_d1d2 ; "d1+d2=" int 21h

mov ah,09h ; вывод на экран полученного lea dx,ascval ; результата (5147483647 =2147483647+3000000000) int 21h call cursor

mov ax,word ptr d1 ; mov dx,word ptr d1+2 ; sbb ax,word ptr d3 ; sbb dx,word ptr d3+2 ;/ d1- d3 mov word ptr rezult,ax ; младшее слово разности (в rezult и rezult+1) mov word ptr rezult+2,dx ; старшее слово разности (в rezult+2 и rezult+3) call bin_ASCII ;вызов процедуры перевода из bin (двоичное) в ASCII ; результат – число в кодах ASCII – в ячейке ascval mov ah,09h ; вывод на экран сообщения lea dx, msgd1_d3 ; "d1-d2=" int 21h

mov ah,09h ; вывод на экран полученного lea dx,ascval ; результата (2000000000 =2147483647- 147483647) int 21h call cursor mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 24 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS mov ah,09h ; вывод на экран сообщения lea dx,msg_e ; "Для выхода нажмите любую клавишу!" int 21h mov ah,0 ;-ожидание нажатия клавиши int 16h ;/ ret ;выход в DOS main endp ;-процедуры----------------------------- ; сюда вставляются процедуры ASCII_bin_b, ASCII_bin_w ; и ASCII_bin_d из файла as_b_bwd.asm include as_b_bwd.asm ; сюда вставляется процедура bin_ASCII из файла bin_asci.asm include bin_asci.asm clrascval proc mov cx,12 ; было 20 mov si,11 ; было 19 clr1: and ascval[si],30h dec si

Page 110: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

110

loop clr1 ret clrascval endp cursor proc ;процедура перевода курсора на след. строку mov ah,09 lea dx,perevod_cursora int 21h ret cursor endp codesg ends ; конец сегмента end main ; конец программы ===================================================================

Пример 1.7 ;lab1pr7.asm ред. 11_07_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (МП 8086) вычисляет по формулам: b1*b2; w1*w2; w1*b1; b1*w2. ;Компиляция: ; tasm.exe lab1pr7.asm ; tlink.exe lab1pr7.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' db 1024 dup(?) stacksg ends ;-сегмент данных------------------------------- datasg segment para 'Data' msg_b1 db "b1=","$" msg_w1 db "w1=","$" msg_d1 db "d1=","$" msg_b1b2 db "b1*b2=","$" msg_w1w2 db "w1*w2=","$" msg_b1w2 db "b1*w2=","$" msg_w1b1 db "w1*b1=","$" msg_e db "Для выхода нажмите любую клавишу!","$" msg_err1 db "Ошибка#1: ошибка ввода!","$" ascval db "00000000000000000000","$" perevod_cursora db 0dh,0ah,"$" ; сюда вставляются списки параметров (из файла vvod_bwd.asm) include vvod_bwd.asm ; директива, вставляющая в текст программы содержимое ; указанного файла vvod_bwd.asm ) b1 db 255 b2 db 10 w1 dw 65535 w2 dw 1000 d1 dd 2147483647 d2 dd 3000000000 prom dw 0 promd dd 0 fml dd 0

Page 111: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

111

osh_v db 0 rezult dq 0 kol dq 0 datasg ends ; конец сегмента данных ;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) begin proc far ; начало процедуры (begin – имя процедуры; far – дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds ; сохранение содержимого регистра ds в стеке (для возврата в DOS) xor ax,ax ; ax:=0 push ax ; ячейка в стеке для MS-DOS (требование – д.б. равна нулю) mov ax,datasg ; инициализация регистра ds (заносится адрес mov ds,ax ; начала сегмента данных) ;--------- mov ax,0600h ;\ | ah=06(прокрутка),al=00(весь экран) mov bh,07 ; \ | нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; / | нижняя правая позиция int 10h ;/ | передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS snova: xor ax,ax ;\ mov al,b1 ; | b1*b2 mul b2 ;/ mov word ptr rezult,ax ; занесение одного слова в байты rezalt и rezalt+1, т.е. в ; мл. слово учетверенного слова rezalt (байты с rezalt+2 по rezalt+7 не изменяются) call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ;вывод на экран lea dx,msg_b1b2 ; сообщения «b1*b2=» int 21h mov ah,09h ;вывод на экран lea dx,ascval ; полученного значения int 21h call cursor mov ax,w1 mul w2 ; w1*w2 mov word ptr rezult,ax ; занесение одного слова в байты rezalt и rezalt+1 mov word ptr rezult[2],dx ; занесение одного слова в байты rezalt+2 и rezalt+3 ; (байты с rezalt+4 по rezalt+7 не изменяются) call bin_ASCII ;вызов процедуры перевода из bin в ASCII (результат -> в ascval) mov ah,09h ; вывод на экран

Page 112: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

112

lea dx,msg_w1w2 ; сообщения « w1*w2= » int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного значения int 21h call cursor xor bx,bx ;\ mov ax,w1 ; | w1*b1 mov bl,b1 ; | mul bx ;/ mov word ptr rezult,ax ; занесение одного слова в байты rezalt и rezalt+1 mov word ptr rezult+2,dx ; занесение одного слова в байты rezalt+2 и rezalt+3 ; (байты с rezalt+4 по rezalt+7 не изменяются) call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ; вывод на экран lea dx,msg_w1b1 ; сообщения « w1*b1= » int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного значения int 21h call cursor xor ax,ax mov al,b1 mul w2 mov word ptr rezult,ax ; занесение одного слова в байты rezalt и rezalt+1 mov word ptr rezult+2,dx ; занесение одного слова в байты rezalt+2 и rezalt+3 ; (байты с rezalt+4 по rezalt+7 не изменяются) call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ; вывод на экран lea dx,msg_b1w2 ; сообщения «b1* w2= » int 21h mov ah,09h ;вывод на экран lea dx,ascval ; полученного значения int 21h call cursor mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 24 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS mov ah,09h ;\ lea dx,msg_e ; вывод на экран сообщения «Для вывода нажмите любую клавишу» int 21h ;/ mov ah,0 ; ожидание нажатия клавиши int 16h ret ;выход в DOS begin endp ; процедуры-----------------------------

Page 113: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

113

; сюда вставляется текст процедуры l_1proc7.asm из файла с таким же именем include l_1proc7.asm ; сюда вставляется текст процедуры bin_ASCII из файла bin_asci.asm include bin_asci.asm codesg ends end begin ==================================================================

Пример 1.8 ;lab1pr8.asm ред. 17_12_05 ;РАЗРАБОТАЛ МИШУРИН А.О., СТУДЕНТ ГРУППЫ 11БИ, ИЮЛЬ 2003 ГОДА. ;Программа (работает с МП 8086) вычисляет по формулам: w1/b1; b1/b2; d1/w1. ;Компиляция (clab1pr8.bat): ; tasm.exe lab1pr8.asm ; tlink.exe lab1pr8.obj ;-сегмент стека--------------------------------- stacksg segment para stack 'Stack' db 1024 dup(?) stacksg ends ;-сегмент данных---------------------------------- datasg segment para 'Data' msg_b1 db "b1=","$" msg_w1 db "w1=","$" msg_d1 db "d1=","$" msg_b1b2 db "b1/b2=","$" msg_w1w2 db "w1*w2=","$" msg_d1w1 db "d1/w1=","$" msg_w1b1 db "w1/b1=","$" msg_e db "Для выхода нажмите любую клавишу!","$" msg_err1 db "Ошибка#1: ошибка ввода!","$" msg_err2 db "Ошибка#2: деление на нуль!","$" ascval db "00000000000000000000","$" perevod_cursora db 0dh,0ah,"$" ; сюда вставляются списки параметров (из файла vvod_bwd.asm) include vvod_bwd.asm ; include – директива, вставляющая в текст программы текст ; файла (в данном случае вставляется текст файла vvod_bwd.asm) b1 db 255 b2 db 10 w1 dw 65535 w2 dw 1000 d1 dd 2147483647 d2 dd 3000000000 prom dw 0 promd dd 0 fml dd 0 osh_v db 0 rezult dq 0 kol dq 0 datasg ends ; конец сегмента данных

Page 114: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

114

;- сегмент кода---------------------------------- codesg segment para 'Code' ; para – параграф (сегмент должен начинаться с ; адреса, кратного шестнадцати, т.е. на границе параграфа) begin proc far ; начало процедуры (begin – имя процедуры; far– дальняя) assume cs:codesg,ds:datasg,ss:stacksg ; директива, устанавливающая соответствие ; сегментных регистров (cs, ds, ss) сегментам (ее обычный вид для EXE-программы) ; следующие строки должны быть в любой EXE-программе: push ds sub ax,ax push ax mov ax,datasg mov ds,ax mov ax,0600h ;\ | ah=06(прокрутка), al=00(весь экран) mov bh,07 ; \ | нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; / | нижняя правая позиция int 10h ;/ | передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,00 ; управление курсором | строка 00 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS snova: ; деление слова на байт xor dx,dx ;\ dx:=0 xor bx,bx ; \ bx:=0 mov ax,w1 ; |w1/b1 ax:w1 mov bl,b1 ; / bx:=b1 div bx ;/ ax:= w1/b1 и dx:=остаток mov word ptr rezult,ax ; подготовка к вызову bin_ASCII call bin_ASCII ;вызов процедуры перевода из bin в ASCII ; помещает результат в ascval mov ah,09h ; вывод на экран lea dx,msg_w1b1 ; сообщения «w1/b1= » int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного значения int 21h call cursor ; деление байта на байт xor ax,ax ;\ mov al,b1 ; | b1/b2 div b2 ; | xor ah,ah ;/ mov word ptr rezult,ax call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ; вывод на экран lea dx,msg_b1b2 ;сообщения «b1/b2=»

Page 115: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

115

int 21h mov ah,09h ; вывод на экран lea dx,ascval ; полученного значения int 21h call cursor ; деление двойного слова на слово (d1/w1) ; деление вычитанием (результат верен даже в случае, когда частное превышает число ; 65536, т.е. не помещается в слово) cmp w1,0 ;\ jz s1er ; обнаружена попытка деления на нуль mov ax,word ptr d1 mov dx,word ptr d1+2 xor bx,bx xor cx,cx s1: cmp dx,0 jnz s2 cmp ax,w1 jnb s2 jmp s3 ; | d1/w1 (вычитанием) + проверка деления на нуль s2: sub ax,w1 sbb dx,00 add bx,1 adc cx,0 jmp s1 s3: jmp s4 s1er: mov ah,09h lea dx,msg_err2 int 21h jmp sn_e s4: mov word ptr rezult,bx mov word ptr rezult+2,cx call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ;вывод на экран lea dx,msg_d1w1 ; сообщения «d1/w1=» int 21h mov ah,09h ;вывод на экран lea dx,ascval ; полученного значения int 21h call cursor sn_e: mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,24 ; управление курсором | строка 23 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS ; деление через div (но если частное превышает число 65536, то результат НЕВЕРЕН!) mov ax,word ptr d1 mov dx,word ptr d1+2

Page 116: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

116

div w1 mov word ptr rezult,ax ; результат деления d1/w1 mov word ptr rezult+2,0 call bin_ASCII ;вызов процедуры перевода из bin в ASCII mov ah,09h ;вывод на экран lea dx,msg_d1w1 ; сообщения «d1/w1=» int 21h mov ah,09h ;вывод на экран lea dx,ascval ; полученного значения int 21h call cursor mov ah,09h ; вывод на экран сообщения lea dx,msg_e ;"Для выхода нажмите любую клавишу!" int 21h mov ah,0 ;-ожидание нажатия клавиши int 16h ret ; возврат в DOS begin endp ; процедуры ; сюда вставляется текст процедуры l_1proc7.asm из файла с таким же именем include l_1proc7.asm ; сюда вставляется текст процедуры bin_ASCII из файла bin_asci.asm include bin_asci.asm codesg ends end begin

Page 117: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

117

Приложение 1.1 Варианты формул для программирования

Первая формула (в 1 – 5, 7, 9 – 12 и 14 лабораторных работах)

№ п/п

Выполняемые вычисления

№ п/п

Выполняемые вычисления

№ п/п

Выполняемые вычисления

1 b1+b2-w1*w2+d1/b3 17 w1*w2-d1/b1+w3+b2 33 d1+b1-w1*w2*b3+w3/b2 2 b1-b2+w1*w2-d1/b3 18 w1*w2+d1/b1-(w3+b2) 34 d1-b1-w1*w2*b3+w3/b2 3 w1+w2-b1*b2+d1/b3 19 b1*b2-w1/b3+d1+d2 35 d1+w1+b4-b1*b2+w2/b3 4 w1-w2+b1*b2-d1/b3 20 b1*b2+w1/b3-(d1-d2) 36 d1-w1+b1*b2*b4-w2/b3 5 w1+b1-w1*w2+d1/b2 21 w1*w2-w3/b1+d1+b2 37 w1*w2*b3-d1/b1+b2+b3 6 w1-b1+w1*w2-d1/b2 22 w1*w2+w3/b1-(d1-b2) 38 w1*w2*b3+d1/b1-(b2-b3) 7 d1+d2-b1*b2+w1/b3 23 b1*b2-w1/b3+d1+w2 39 b1*b2*b3-d1/b3+w1+w2 8 d1-d2+b1*b2-w1/b3 24 b1*b2+w1/b3-(d1-w2) 40 b1*b2*b3+d1/b3-(w1+w2) 9 d1+b1-w1*w2+w3/b2 25 b1+b2+b3-w1*w2+d1/b3 41 w1*w2-d1/b1+w3+b2+b3

10 d1-b1-w1*w2+w3/b2 26 b1-b2-b3+w1*w2-d1/b3 42 w1*w2+d1/b1-w3+b2*b3 11 d1+w1-b1*b2+w2/b3 27 w1+w2+w3-b1*b2+d1/b3 43 b1*b2*b3-w1/b3+d1+d2 12 d1-w1+b1*b2-w2/b3 28 w1-w2-w3+b1*b2-d1/b3 44 b1*b2*b3+w1/b3-(d1-d2) 13 w1*w2-d1/b1+b2+b3 29 w1+b1+b3-w1*w2+d1/b2 45 w1*w2-w3/b1+d1+b2 14 w1*w2+d1/b1-(b2-b3) 30 w1-b1-b3+w1*w2-d1/b2 46 w1*b3+w3/b1-(d1-b2) 15 b1*b2-d1/b3+w1+w2 31 d1+d2-b1*b2*b4+w1/b3 47 b1*b2*b3-w1/b3+d1+w2 16 b1*b2+d1/b3-(w1+w2) 32 d1-d2+b1*b2*b4-w1/b3 48 b1*b2+w1/b3-(d1-w2)

Вариант № 49 для лабораторной работы №1 Выполняемые вычисления

Х1= Выполняемые вычисления

Х1= Выполняемые вычисления

Х1=

b1*b2 1 d5/d6 12 w16-w17 23 w1*w2 2 d7/w9 13 w18+b17 24 b3*w2 3 d8/b10 14 w19-b18 25 b4*d1 4 w10/w11 15 d13+d14 26 w3*d2 5 w12/b11 16 d15-d16 27 w4*b5 6 d9/d10 17 d17+b19 28 d3*b6 7 d11/w13 18 d18-b20 29 d4*w5 8 d12/b12 19 d19+w20 30 b7/b8 9 b13+b14 20 d20-w21 31 w6/w7 10 b15-b16 21 w8/b9 11 w14+w15 22

b1, b2, b3 – переменные, занимающие один байт, т.е. определенные директи-вой db; w1, w2, w3 – переменные, занимающие одно слово (два байта), т.е. определен-ные директивой dw; d1, d2 – переменные, занимающие двойное слово (четыре байта), т.е. опре-деленные в сегменте данных директивой dd.

Page 118: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

118

Приложение 1.2 Структура (схема) программы

А. Общая структура

; Лабораторная работа №1 ; выполнена студентом группы <обозначение группы> <Фамилия Имя Отчество>; ; тема: «Определение данных. Операции двоичной арифметики. Экранные операции» ; вычисление по формуле <первая формула индивидуального задания> ; г.Омск, СибАДИ, <месяц> <год> г. ; Ограничения: не вводить отрицательных чисел; ; не получать отрицательный результат. ; Сегмент стека ; Сегмент данных ; Сегмент кода ; Начало сегмента кода ; Начало главной процедуры ; Директива, устанавливающая соответствие сегментных регистров сегментам (директива assume) ; Команды, которые должны быть в любой EXE-программе ; Вывод на экран сообщения 'Привет, пользователь!' ;Вывод на экран сообщения 'Эта программа производит вычисления по формуле d1 - (b1+ w1/b2)*w2’ ; ввод с клавиатуры числа b1 ; ввод с клавиатуры числа b2 ; ввод с клавиатуры числа w1 ; ввод с клавиатуры числа w2 ; ввод с клавиатуры числа d1 ; вычисление по формуле <формула> ; Вывод результата на экран ; выход из главной процедуры (возврат в DOS) ; Конец главной процедуры ; Конец сегмента кода (директива ends) ; Конец программы (директива end)

Page 119: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

119

Продолжение прил. 1.2 Б. Детализированная структура (шаг 1)

; Лабораторная работа №1 ; выполнена студентом группы <обозначение группы> <Фамилия Имя Отчество>; ; тема: «Определение данных. Операции двоичной арифметики. Экранные операции» ; вычисление по формуле <первая формула индивидуального задания> ; г. Омск, СибАДИ, <месяц> <год> г. ; Ограничения: не вводить отрицательных чисел; ; не получать отрицательный результат. ; Сегмент стека ; Начало сегмента стека (директива segment) ; резервирование ячеек памяти под стек ;Конец сегмента стека (директива ends) ; Сегмент данных ;Начало сегмента данных (директива segment) ; ячейки памяти b1, b2,…,bm, определенные директивой db; ; ячейки памяти w1, w2,…,wn, определенные директивой dw; ; ячейки памяти d1, d2,…,dk, определенные директивой dd; ; списки параметров для ввода с клавиатуры ; символьные константы (тексты сообщений, выдаваемых на экран) ; ячейки промежуточных результатов ; Конец сегмента данных (директива ends) ; Сегмент кода ; Начало сегмента кода (директива segment) ; Начало главной процедуры (директива proc) ; Директива, устанавливающая соответствие сегментных регистров сегментам (директива assume) ; Команды, которые должны быть в любой EXE-программе ;Вывод на экран сообщения 'Привет, пользователь!' ;Вывод на экран сообщения ; 'Эта программа производит вычисления по формуле d1 - (b1+ w1/b2)*w2’ ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b1 ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b2 ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w1 ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w2 ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа d1 ; вычисление по формуле <формула> ; Вывод результата на экран ; выход из главной процедуры (возврат в DOS, команда ret) ; Конец главной процедуры (директива endp) ; Конец сегмента кода (директива ends) ; Конец программы (директива end)

Page 120: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

120

Продолжение прил. 1.2 В. Детализированная структура (шаг 2)

; Лабораторная работа №1 ; выполнена студентом группы <обозначение группы> <Фамилия Имя Отчество>; ; тема: «Определение данных. Операции двоичной арифметики. Экранные операции» ; вычисление по формуле <первая формула индивидуального задания> ; г. Омск, СибАДИ, <месяц> <год> г. ; Ограничения: не вводить отрицательных чисел; ; не получать отрицательный результат. ; Сегмент стека ; Начало сегмента стека (директива segment) ; резервирование 1024 ячеек памяти под стек ; (директива db оператор dup) ;Конец сегмента стека (директива ends) ; Сегмент данных ;Начало сегмента данных (директива segment) ; ячейки памяти b1, b2,…,bm, определенные директивой db; ; ячейки памяти w1, w2,…,wn, определенные директивой dw; ; ячейки памяти d1, d2,…,dk, определенные директивой dd; ; списки параметров для ввода с клавиатуры значений, занимающих ; один байт, т.е. значений b1, b2, ; список параметров vvod_b (поле для символов - field_b); ; одно слово (w1, w2) ; список параметров vvod_w (поле для символов - field_w); двойное слово (d1) ; список параметров vvod_d (поле для символов - field_d); ; символьные константы (тексты сообщений, выдаваемых на экран) ; ячейки памяти, используемые процедурами ascii_binb, ascii_binw, ascii_bind, bin_ascii и др. ; ячейки промежуточных результатов ; Конец сегмента данных (директива ends) ; Сегмент кода ; Начало сегмента кода (директива segment) ; Начало главной процедуры (директива proc) ; Директива, устанавливающая соответствие сегментных регистров сегментам (директива assume) ; Команды, которые должны быть в любой EXE-программе ;очистка экрана ;Вывод на экран сообщения 'Привет, пользователь!', ;Вывод на экран сообщения ; 'Эта программа производит вычисления по формуле d1- (b1+ w1/b2)*w2’ ;*************************************************************************** ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b1 ;*************************************************************************** ; вывод на экран сообщения: 'b1= ' ; ввод с клавиатуры (функция 0ah) значения переменной b1 в field_b списка параметров vvod_b

Page 121: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

121

Продолжение прил. 1.2 ;перевод введенных данных из ASCII-кодов в двоичный код (вызвать процедуру ASCII_binb) ;результат преобразования (двоичный код) процедура помещает в регистр al ;занесение двоичного значения из регистра al в ячейку памяти с символьным именем b1 ;*************************************************************************** ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b2 ;*************************************************************************** ; вывод на экран сообщения: 'b2= ' ; ввод с клавиатуры (функция 0ah) значения переменной b2 в field_b списка параметров vvod_b ;перевод введенных данных из ASCII-кодов в двоичный код (вызвать процедуру ASCII_binb) ;результат преобразования (двоичный код) процедура помещает в регистр al ;занесение двоичного значения в ячейку памяти с символьным именем b2 ;*************************************************************************** ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w1 ;*************************************************************************** ; вывод на экран сообщения: 'w1= ' ; ввод с клавиатуры (функция 0ah) значения переменной w1 в field_w списка параметров vvod_w ; перевод введенных данных из ASCII-кодов в двоичный код (вызвать процедуру ASCII_binw) ;результат преобразования (двоичный код) процедура помещает в регистр ax ;занесение двоичного значения из ax в ячейку памяти с символьным именем w1 ;*************************************************************************** ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w2 ;*************************************************************************** ; вывод на экран сообщения: 'w2= ' ; ввод с клавиатуры (функция 0ah) значения переменной w2 в field_w списка параметров vvod_w ; перевод введенных данных из ASCII кодов в двоичный код (вызвать процедуру ASCII_binw) ; занесение двоичного значения в ячейку памяти с символьным именем w2 ;*************************************************************************** ; ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа d1 ;*************************************************************************** ; вывод на экран сообщения: 'd1= ' ; ввод с клавиатуры значения (функция 0ah) переменной d1 в ячейку в field_d списка параметров vvod_d ; перевод введенных данных из ASCII-кодов в двоичный код (вызвать процедуру ASCII_bind) ;результат преобразования (двоичный код) процедура помещает в регистры (dx:ax) ; занесение переведённого значения (двойное слово) из регистров (dx:ax) в d1 ;*************************************************************************** ; вычисление по формуле <формула>, например, d1-(b1+ w1/b2)*w2 ; вычисление w1/b2

Page 122: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

122

Окончание прил. 1.2 ; вычисление b1+ w1/b2 ; вычисление (b1+ w1/b2)*w2 ; вычисление d1-(b1+ w1/b2)*w2 ; Вывод результата на экран ; Результат из двоичного кода перевести в код ASCII (вызвать процедуру bin_ascii ) ; Вывод на экран сообщения «Результат равен = » ; Вывод на экран полученного в результате вычисления значения (в коде ascii) ; выход из главной процедуры (возврат в DOS, команда ret) ; Конец главной процедуры (директива endp) ; Процедуры, вызываемые из главной процедуры ;=================================================================== ;ASCII_binb ;процедура перевода из ASCII в bin для байта ; Вход: список параметров vvod_b должен быть заполнен ; Выход: al = двоичное число ; Начало процедуры (директива proc) ; Тело процедуры ; Конец процедуры (директива endp) ;=================================================================== ;ASCII_binw ;процедура перевода из ASCII в bin для слова ; Вход: список параметров vvod_w должен быть заполнен ; Выход: ax = двоичное число ; Начало процедуры (директива proc) ; Тело процедуры ; Конец процедуры (директива endp) ;=================================================================== ;ASCII_bind ;процедура перевода из ASCII в bin для двойного слова ; Вход: список параметров vvod_d должен быть заполнен ; Выход: dx:ax = двоичное число ; Начало процедуры (директива proc) ; Тело процедуры ; Конец процедуры (директива endp) ;=================================================================== ; bin_ascii ;процедура перевода из bin в ASCII ; Вход: rezult = двоичное число ; Выход: ascval = число в кодах ascii ; Начало процедуры (директива proc) ; Тело процедуры ; Конец процедуры (директива endp) ; Конец сегмента кода (директива ends) ; Конец программы (директива end)

Page 123: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

123

Приложение 1.3 Пример лабораторной работы №1

; Лабораторная работа №1 ; ВЫПОЛНЕНА СТУДЕНТОМ ГРУППЫ ЗИ-103 СЫРВАЧЕВЫМ АЛЕКСЕЕМ ; тема: «Определение данных. Операции двоичной арифметики. Экранные операции» ; вычисление по формуле w1*w2-w3/b1+d1+b2 ; г. Омск, СибАДИ, Сургутский филиал, октябрь 2003 г. ; Ограничения: не вводить отрицательных чисел; ; не получать отрицательный результат. ; Сегмент стека ; Начало сегмента стека (директива segment) stacksg segment para stack 'Stack' ; резервирование 1024 ячеек памяти под стек

db 1024 dup (?) ;Конец сегмента стека (директива ends) stacksg ends ; Сегмент данных ;Начало сегмента данных (директива segment) datasg segment para 'Data' ; ячейки памяти b1, b2,…,bm, определенные директивой db; b1 db 0 b2 db 0 ; ячейки памяти w1, w2,…,wn, определенные директивой dw; w1 dw 0 w2 dw 0 w3 dw 0 ; ячейки памяти d1, d2,…,dk, определенные директивой dd; d1 dd 0 ; списки параметров для ввода с клавиатуры значений, занимающих ; один байт, т.е. значений b1, b2, ; список параметров vvod_b (поле для символов - field_b); vvod_b label byte max_b db 4 fact_b db 0 field_b db '0000','$' ; одно слово (w1, w2) ; список параметров vvod_w (поле для символов - field_w); vvod_w label byte max_w db 7 fact_w db 0 field_w db '0000000','$' двойное слово (d1) ; список параметров vvod_d (поле для символов - field_d); vvod_d label byte max_d db 9 fact_d db 0 field_d db '000000000','$' ; ячейки памяти, используемые процедурами ascii_binb, ascii_binw, ascii_bind и bin_ascii.

Page 124: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

124

ascval db "00000000000000000000","$" ; поле переведённых данных binval db 0 ;результат преобразования asclen db 20 ;длина введенного символьного числа mult10 db 1 ;фактор умножения binval_w dw 0 ; символьные константы (тексты сообщений, выдаваемых на экран) soob_p db 'Здравствуйте, уважаемый пользователь',0dh,0ah,'$' soob_f db 'Программа вычисляет по формуле w1*w2-w3/b1+d1+b2',0ah,0dh,'$' s_b1 db 'Введите b1',0ah,0dh,'$' s_b2 db 'Введите b2',0ah,0dh,'$' s_w1 db 'Введите w1',0ah,0dh,'$' s_w2 db 'Введите w2',0ah,0dh,'$' s_w3 db 'Введите w3',0ah,0dh,'$' s_d1 db 'Введите d1',0ah,0dh,'$' soob_o db 'Ответ будет равен:',0ah,0dh,'$' soob_vixod db "Для выхода нажмите любую клавишу","$" soob db 'До свидания',0ah,0dh,'$' perevod_cursora db 0dh,0ah,"$" oshibka_v db "Ошибка ввода!(введите другое число)","$" ; ячейки промежуточных результатов rez1 dd 0 rez2 dd 0 rez3 dd 0 rez4 dd 0 rezult dq 0 kol dq 0 osh_v db 0 prom dw 0 promd dd 0 fml dd 0 stroka db 2 ; Конец сегмента данных (директива ends) datasg ends ; Сегмент кода ; Начало сегмента кода (директива segment) codesg segment para 'Code' ; Начало главной процедуры (директива proc) begin proc far ; Директива, устанавливающая соответствие сегментных регистров сегментам ; (директива assume) assume cs:codesg,ds:datasg,ss:stacksg ; Команды, которые должны быть в любой EXE-программе

push ds xor ax,ax push ax mov ax,datasg mov ds,ax

;очистка экрана

Page 125: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

125

mov ax,0600h ;\ | ah=06(прокрутка), al=00(весь экран) mov bh,02 ; \ | нормальный атрибут (черно-белый) mov cx,0000 ; очистка экрана | верхняя левая позиция mov dx,314fh ; / | нижняя правая позиция int 10h ;/ | передача управления в BIOS mov ah,02 ;\ | установка курсора mov bh,00 ; \ | экран 0 mov dh,01 ; управление курсором | строка 01 mov dl,00 ; / | столбец 00 int 10h ;/ | передача упр. в BIOS

;Вывод на экран сообщения 'Привет, пользователь!' mov ah,09 ;Вывод приветствия lea dx,soob_p int 21h

formula1: ;Вывод на экран сообщения 'Эта программа производит вычисления по формуле ; d1 - (b1+ w1/b2)*w2’

mov ah,09 ;Вывод формулы d1 - (b1+ w1/b2)*w2’ lea dx,soob_f int 21h

; Ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b1 ; вывод на экран сообщения: 'b1= ' povtor_b1:

mov ah,09 ;вывод сообщения 'b1= ' mov osh_v,0 lea dx,s_b1 int 21h

; Ввод с клавиатуры (функция 0ah) значения b1 в field_b списка параметров vvod_b mov ah,0ah lea dx,vvod_b int 21h

;Перевод введенных данных из ASCII-кодов в двоичный код call ASCII_bin_b

;Результат преобразования (двоичный код) процедура помещает в регистр al ;Занесение двоичного значения из al в ячейку памяти с символьным именем b1

mov b1,al mov prom,0 call cursor cmp osh_v,0 je ii2 jmp povtor_b1

;Ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа b2 ii2: povtor_b2: ; Вывод на экран сообщения: 'b2= '

mov ah,09 mov osh_v,0 lea dx,s_b2

Page 126: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

126

int 21h ; Ввод с клавиатуры (функция 0ah) значения b2 в field_b списка параметров vvod_b

mov ah,0ah lea dx,vvod_b int 21h

;Перевод введенных данных из ASCII-кодов в двоичный код call ASCII_bin_b

;Результат преобразования (двоичный код) процедура помещает в регистр al ;Занесение двоичного значения в ячейку памяти с символьным именем b2

mov b2,al mov prom,0 call cursor cmp osh_v,0 jz ii3 jmp povtor_b2

;Ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w1 ii3: povtor_w1: ;Вывод на экран сообщения: 'w1= '

mov ah,09 mov osh_v,0 lea dx,s_w1 int 21h

; Ввод с клавиатуры (функция 0ah) значения переменной w1 в field_w списка vvod_w mov ah,0ah lea dx,vvod_w int 21h

; Перевод введенных данных из ASCII-кодов в двоичный код call ASCII_bin_w

;Результат преобразования (двоичный код) процедура помещает в регистр ax ; Занесение двоичного значения из ax в ячейку памяти с символьным именем w1

mov word ptr w1,ax mov prom,0 call cursor cmp osh_v,0 jz ii4 jmp povtor_w1

;Ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа w2 ii4: povtor_w2: ; Вывод на экран сообщения: 'w2= '

mov ah,09 mov osh_v,0 lea dx,s_w2 int 21h

; Ввод с клавиатуры (функция 0ah) значения w2 в field_w списка параметров vvod_w mov ah,0ah lea dx,vvod_w

Page 127: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

127

int 21h ; Перевод введенных данных из ASCII в двоичный код (процедура ASCII_binw)

call ASCII_bin_w ; Занесение двоичного значения из ax в ячейку памяти с символьным именем w2

mov w2,ax mov prom,0 call cursor cmp osh_v,0 jz ii6 jmp povtor_w2

;Ввод с клавиатуры и преобразование из ASCII в двоичное (bin) числа d1 ii6: povtor_d1: ;Вывод на экран сообщения: 'd1= '

mov ah,09 mov osh_v,0 lea dx,s_d1 int 21h

; Ввод с клавиатуры значения d1 в ячейку в field_d списка параметров vvod_d mov ah,0ah lea dx,vvod_w int 21h

; Перевод введенных данных из ASCII-кодов в двоичный код call ASCII_bin_w

; Результат преобразования (двоичный код) процедура помещает в регистры (dx:ax) ; Занесение переведённого значения (двойное слово) из регистров (dx:ax) в d1

mov word ptr d1,ax mov word ptr d1+2,dx mov prom,0 call cursor cmp osh_v,0 jz ii7 jmp povtor_d1

ii7: ; Вычисление по формуле d1-(b1+ w1/b2)*w2’ ;1. Деление w1/b2

xor dx,dx ; dx := 0 xor bx,bx ; bx := 0 mov ax,w1 ; ax :=w1 mov bl,b2 ; bx := b2 div bx ; ax :=w1/b2 dx:= остаток от деления mov word ptr rez2,ax ; rez2 :=w1/b2 (слово)

;2. Сложение b1+ w1/b2 mov al,b1 ; al := b1 cbw ; ax := b1 xor dx,dx ; dx := 0 add ax, rez2

Page 128: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

128

adc dx,0 ;учесть перенос, после этого (dx:ax) := b1+ w1/b2 mov word ptr rez3,ax mov word ptr rez3+2,dx ; rez3:= b1+ w1/b2 (двойное слово)

3. Умножение rez3*w2 [3, с. 311-312] mov ax,word ptr res3 ; ax:=мл.слово res3 mul w2 ; (dx:ax) := мл.слово res3*w2 mov word ptr rezult,ax mov word ptr rezult+2,dx mov word ptr result+4,0 mov word ptr rezult+6,0 ; rezult := мл.слово res3*w2

mov ax,word ptr res3+2 ; ax:=ст.слово res3 mul w2 ; (dx:ax) := ст.слово res3*w2 add word ptr result+2,ax adc word ptr rezult+4,dx adc word ptr result+6,0 mov word ptr rezult+6,0 ; rezult := res3*w2 = (b1+ w1/b2)*w2 (учетверен. слово)

;4 .Вычитание d1 - rezult mov ax,word ptr d1 mov dx,word ptr d1+2 xor cx,cx xor bx,bx sub ax,result sbb dx,result+2 sbb cx,result+4

; учесть заем из старших разрядов: sbb bx,result+6 mov word ptr rezult,ax mov word ptr result+2,dx mov word ptr result+4,cx mov word ptr result+6,bx ; rezult := = d1 - (b1+ w1/b2)*w2 (учетверенное слово

; Вывод результата на экран ; Результат из двоичного кода перевести в код ASCII (вызвать процедуру bin_ascii )

call bin_ASCII ;вызов процедуры перевода из bin в ASCII ; Вывод на экран сообщения «Результат равен = »

mov ah,09h ; lea dx,soob_o ; int 21h ;

; Вывод на экран полученного в результате вычисления значения (в коде ascii) mov ah,09h lea dx,ascval int 21h call cursor

mov ah,0 ;-ожидание нажатия клавиши int 16h

Page 129: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

129

; Выход из главной процедуры (возврат в DOS, команда ret) ret

; Конец главной процедуры (директива endp) begin endp ; ; Процедуры, вызываемые из главной процедуры ;=================================================================== ;ASCII_binb ;процедура перевода из ASCII в bin для байта ; ; Начало процедуры (директива proc) ASCII_bin_b proc ;процедура перевода из ASCII в bin для байта ; Вход: список параметров vvod_b должен быть заполнен; ; Выход: al=число в bin ; ; Тело процедуры

xor ax,ax xor cx,cx mov prom,ax mov osh_v,al mov al,fact_b mov cl,al dec al mov si,ax mov bx,1

met1_b: mov al,field_b[si] cbw cmp ax,30h jb error_b cmp ax,39h ja error_b and al,0fh mul bx add prom,ax mov ax,bx mov bx,10 mul bx mov bx,ax dec si loop met1_b mov ax,prom jmp end_error_b

error_b: call cursor mov ah,09h lea dx,oshibka_v int 21h mov osh_v,1

Page 130: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

130

end_error_b: ret

ASCII_bin_b endp ; конец процедуры (директива endp) ;=================================================================== ;ASCII_binw ;процедура перевода из ASCII в bin для слова ; Вход: список параметров vvod_w должен быть заполнен ; Выход: ax = число в bin ASCII_bin_w proc ; Тело процедуры

xor ax,ax xor cx,cx mov prom,ax mov osh_v,al mov al,fact_w mov cl,al dec al mov si,ax mov bx,1

met1_w: mov al,field_w[si] cbw cmp ax,30h jb error_w cmp ax,39h ja error_w and al,0fh mul bx add prom,ax mov ax,bx mov bx,10 mul bx mov bx,ax dec si loop met1_w mov ax,prom jmp end_error_w

error_w: call cursor mov ah,09h lea dx,oshibka_v int 21h mov osh_v,1

end_error_w: ret

ASCII_bin_w endp ; конец процедуры (директива endp) ;=================================================================== ;ascii_bind ;процедура перевода из ASCII в bin для двойного слова ; Вход: список параметров vvod_d должен быть заполнен

Page 131: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

131

; Выход: dx:ax = число в bin ; Начало процедуры (директива proc) ASCII_bin_d proc ; Тело процедуры

xor ax,ax xor bx,bx xor cx,cx xor dx,dx mov word ptr promd,ax mov word ptr promd[2],ax mov word ptr fml[2],ax mov word ptr fml,1 mov osh_v,al mov al,fact_d mov cl,al dec al mov si,ax

met1_d: mov bl,field_d[si] cmp bx,30h jb error_d cmp bx,39h ja error_d and bl,0fh mov dx,0 mov ax,0

abd1: cmp bl,0 jz abd2 add ax,word ptr fml adc dx,word ptr fml[2] dec bl jmp abd1

abd2: add word ptr promd,ax adc word ptr promd[2],dx mov bl,9 mov dx,word ptr fml[2] mov ax, word ptr fml

abd3: cmp bl,0 jz abd4 add word ptr fml,ax adc word ptr fml[2],dx dec bl jmp abd3

abd4: dec si loop met1_d mov dx,word ptr promd[2]

Page 132: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

132

mov ax,word ptr promd jmp end_error_d

error_d: call cursor mov ah,09h lea dx,oshibka_v int 21h mov osh_v,1

end_error_d: ret

ASCII_bin_d endp ; конец процедуры (директива endp) ;=================================================================== ; bin_ascii ;процедура перевода из bin в ASCII ; Вход: rezult = двоичное число ; Выход: ascval = число в кодах ascii ; Начало процедуры (директива proc) bin_ASCII proc; ; Тело процедуры

call clrascval ;вызов процедуры очистки строковой переменной ascval lea si,ascval[19]

m1: cmp word ptr rezult[6],0 jne m2 cmp word ptr rezult[4],0 jne m2 cmp word ptr rezult[2],0 jne m2 cmp word ptr rezult,10 jnb m2 mov ax,word ptr rezult or al,30h mov [si],al dec si jmp m3

m2: sub word ptr rezult,10 sbb word ptr rezult[2],0 sbb word ptr rezult[4],0 sbb word ptr rezult[6],0 add word ptr kol,1 adc word ptr kol[2],0 adc word ptr kol[4],0 adc word ptr kol[6],0 jmp m1

m3: cmp word ptr kol[6],0 jne m4 cmp word ptr kol[4],0

Page 133: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

133

jne m4 cmp word ptr kol[2],0 jne m4 cmp word ptr kol,0 jne m4 ret

m4: mov ax,word ptr kol mov word ptr rezult,ax mov ax,word ptr kol[2] mov word ptr rezult[2],ax mov ax,word ptr kol[4] mov word ptr rezult[4],ax mov ax,word ptr kol[6] mov word ptr rezult[6],ax mov word ptr kol,0 mov word ptr kol[2],0 mov word ptr kol[4],0 mov word ptr kol[6],0 jmp m1

; Конец процедуры (директива endp) bin_ASCII endp ;=================================================================== clrascval proc

mov cx,20 mov si,19

clr1: and ascval[si],30h dec si loop clr1 ret

clrascval endp ;=================================================================== cursor proc ;процедура перевода курсора на след. строку

mov ah,09 lea dx,perevod_cursora int 21h ret

cursor endp ;=================================================================== ; Конец сегмента кода (директива ends) codesg ends ; Конец программы (директива end) end begin

Page 134: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

134

Контрольные вопросы 1. Напишите битовые представления ASCII-кодов для следующих

однобитовых символов: а) 13, б) 2, в) 5. 3. Напишите битовые представления для следующих чисел:

а) 5, б) 13, в) 21, г) 27. 3. Сложите следующие двоичные числа:

а) 00010101 б) 00111110 в) 00011111 00001101 00101001 00000001

4. Определите двоичные дополнения для следующих двоичных чисел: а) 00010011, б) 00111100, в) 00111001 5. Определите положительные значения для следующих

отрицательных двоичных цифр: а) 11001000, б) 10111101, в) 10000000. 6. Определите шестнадцатеричные представления для следующих

значений: а) ASCII-символа 0, б) ASCII-символа 7, в) двоичного числа

01011101, г) двоичного числа 01110111. 7. Сложите следующие шестнадцатеричные числа:

а) 23A6 б) 51FD в) 7779 г) EABE 0022 3 887 2 6C4

8. Что представляют собой три типа сегментов, каковы их максимальные размеры и адреса, с которых они начинаются?

9. Сегменты, используемые в EXE-программе. 10. Признаки EXE-программы 11. Назначение директив segment, ends, proc, endp, end, assume, label. 12. Регистры МП Intel 8086. 13. Директивы определения данных db, dw, dd, dq. 14. Какие регистры можно использовать для следующих целей: а) сложения и вычитания, б) подсчета числа циклов, в) умножения и

деления, г) адресации сегментов, д) индикации нулевого результата, е) адресации выполняемой команды?

15. Основные элементы программы на языке ассемблера. 16. Команды микропроцессора Intel 8086. 17. Команды микропроцессора Intel 8086, выполняющие

арифметические операции. 18. Напишите машинные команды для: а) пересылки значения 4629h в регистр ax;

Page 135: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

135

б) сложения 036Аh с содержимым регистра ax. 19. Имеется программа, которая выполняет следующее: - пересылает значения 25h в регистр al; - сдвигает содержимое регистра al на один бит влево (в результате в al

будет 4Ah); - пересылает значения 15h в регистр bl; - умножает содержимое регистра al на содержимое регистра bl. Какое значение будет в регистре ax после выполнения программы? 20. Какие из следующих имен неправильны: а) PC_AT, б) $50, в)

@$_Z, г) 3487, д) AX? 21. Каково назначение каждого из трех сегментов: сегмента кода,

сегмента данных, сегмента стека? 22. Какая из директив endp, ends, end завершает: а) программу, б) процедуру, в) сегмент? Что каждая из них

подразумевает? 23. Укажите различия между директивой и командой. 24. Укажите различия в назначении ret и end. 25. Для сегментов кода, данных и стека даны имена cdseg, datseg и

stkseg, соответственно. Сформируйте директиву assume. 25. Напишите три команды для сохранения в стеке регистра ds и нуля. 27. Какова длина в байтах для элементов данных, определенных

директивами : а) dw, б) dd, в) dt, г) db, д) dq? 28. Определите следующие числовые значения в элементах данных с

именами FLDA и FLDB: а) двухбайтового элемента, содержащего неопределенное значение; б) директивы dw, содержащей последовательные значения 16, 19, 20,

27, 30. 29. Покажите сгенерированный шестнадцатеричный объектный код

для: а) db '26' и б) db 26. 30. Определите ассемблерный шестнадцатеричный объектный код

для: а) db 26h, б) dw 2645h, в) dd 25733Ah, г) dq 25733Ah. 31. Закодируйте следующие команды с непосредственными

операндами: а) загрузить 320 в регистр ax; б) сравнить поле FLDB с нулем; в) прибавить 40h к содержимому регистра bx; г) вычесть 40h из регистра cx. 31. Напишите команду вызова ассемблера с параметром получения lst-

файла (листинга),

Page 136: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

136

32. Какое максимальное количество байтов могут обойти команды короткий jmp, loop и условный переход?

33. Команда jmp начинается на 0624h. Определите адрес перехода, если шестнадцатеричный объектный код для операнда команды jmp:

а) 27, б) 6В, в) С6. 34. Напишите программу для вычисления 12 чисел Фибоначчи: 1, 1, 2,

3, 5, 8, 13, 21,…(каждое число представляет собой сумму двух предыдущих чисел).

35. Предположим, что регистры ax и bx содержат беззнаковые данные. Определите команды cmp (где необходимо) и команды безусловного перехода для следующих проверок:

а) значение в bx больше, чем в ax? в) ax содержит нуль? г) было ли переполнение? д) значение в bx равно или меньше, чем в ax? е) значение в ax равно bx? 36. Какая разница между кодированием в директиве proc операнда с

типом far и с типом near? 37. Каким образом может программа начать выполнение процедуры? 38. В EXE-программе процедура A10 вызывает B10, B10 вызывает

C10, а C10 вызывает D10. Сколько адресов, кроме начальных адресов возврата в DOS, содержит стек?

39. Укажите вызовы функций: а) для ввода с клавиатуры, б) вывода на экран. 40. Объясните назначение каждого из следующих файлов: file.asm,

file.lst, file.obj, file.exe. 41. Напишите две команды для инициализации регистра ds, полагая,

что имя сегмента данных – datseg. Вопросы с 42 по 45 имеют отношение к следующим данным: DATAX db 148h

db 2316h DATAY db 0237h

db 4052h 42. Закодируйте команды для сложения: а) слова DATAX со словом DATAY; б) двойного слова, начинающегося по адресу DATAX, с двойным

словом в DATAY. 43. Закодируйте команды для умножения (mul): а) слова DATAX на слово DATAY;

Page 137: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

137

б) двойного слова, начинающегося по адресу DATAX, на слово DATAY.

44. Какой делитель, кроме 0, вызывает ошибку переполнения? 45. Закодируйте команды для деления (div): а) слова DATAX на 23; б) двойного слова, начинающегося по адресу DATAX, на слово

DATAY. 46. Команды вывода на экран (функция DOS). 47. Команды ввода с клавиатуры (функция DOS). 48. Перечень ошибок в написании программ.

Page 138: ЯЗЫКИ ПРОГРАММИРОВАНИЯbek.sibadi.org/fulltext/epd627.pdf · –установить операционную систему Windows 95 (или выше: Windows

138

Учебное издание

ЛЕОНИД ЕФИМОВИЧ ОЛЕЙНИК

ЯЗЫКИ ПРОГРАММИРОВАНИЯ Учебное пособие

Для специальности 075500 Часть 1

ОПРЕДЕЛЕНИЕ ДАННЫХ. ДВОИЧНАЯ АРИФМЕТИКА. ЭКРАННЫЕ ОПЕРАЦИИ

Главный редактор Т.И. Калинина

Подписано к печати 22.05.12 Формат 60 x 90 1/16. Бумага писчая Гарнитура Таймс Оперативный способ печати Усл. п. л. 8,5, уч.-изд. л. 8,4 Тираж 145 экз. Заказ Цена договорная

Издательство СибАДИ 644099, Омск, ул. П. Некрасова, 10

Отпечатано в ПЦ издательства СибАДИ

644099, Омск, ул.П. Некрасова, 10