Практическая часть лабораторной работы
На диске С создайте папку VMCxxx (ххх – аббревиатура ФИО студента на английском языке. Например, VMCVAN).
1. Скопируйте с сетевого диска в эту папку следующие программы:
a. TASM.exe – транслятор Ассемблера;
b. TLINK.exe – компоновщик программ;
c. TD.exe – отладчик программ.
2. Перейдите в режим FAR (файлового менеджера программ).
3. В FARе зайдите в папку VMCxxx.
4. Создайте в папке VMCxxx текстовый файл кликнув Shift +F4.
5. Укажите имя файла LAB1xxx.ASM.
6. В папке VMCxxx выделите курсором созданный файл и кликните F4 (перейдете в режим редактирования созданного файла).
7. Кликните Tab. (Курсор сдвинется на позицию табуляции вправо).
8. Перейдите на латинскую раскладку клавиатуры и наберите приведенный ниже текст программы.
Текст программы | Комментарии |
.Model small .Stack 300h .Data Txt TXT db ‘Привет!Это первая программа студента ХХХ группы УУ-УУ выполненная на Ассемблере’,‘$’ Tabb db 33,66,99 db 47,74,55 Tabb1 db 33h,66h,99h db 3Ah,6Bh,9Ch Tabw dw 7721,1345 dw 4774,1536 Tabw1 dw 7721h,1345h dw 3A6Bh,0AD2h .Code Beg: Mov AX,@data Mov DS,AX | Директивы задания модели памяти программы (модель типа small). Директива задания и описания стекового сегмента объемом в 768 десятичных байт. Директива задания и описания сегмента данных. В этом сегменте находятся текстовая строка и числа различных систем счисления. Этот текст будет отображен на экране монитора. Две строки десятичных, байтовых данных. Две строки шестнадцатиричных, байтовых данных. Две строки десятичных, словных (двухбайтовых) данных. Две строки шестнадцатиричных, словных (двухбайтовых) данных. Директива задания и описаниякодового сегмента программы (сегмента в котором находятся команды программы). @-предопределенный символ, формирующий с директивой data адрес сегмента данных. Метка Beg определяет точку входа в программу. Инициализация сегментного регистра DS. По этой команде в сегментный регистр DS из регистра АХ пересылается адрес сегмента данных. Эти две команды всегда начинают любую программу на Ассемблере. |
Lea DX,Txt Mov Ah,09h Int 21h Mov AL,Tabb Mov AH,Tabb+1 Mov BL,Tabb+2 Mov BH,Tabb+3 Mov DL,Tabb+5 Mov AL,Tabb1 Mov AH,Tabb1+1 Mov BL,Tabb1+2 Mov BH,Tabb1+3 Mov CX,Tabw Mov DX,Tabw+2 Mov BX,Tabw1+2; Mov AX,Tabw1+6; Xchg AX,BX; Xchg CL,DH; Mov Ah,4Ch; Int 21h End Beg; | Процедура вывода текста на экран Пересылка в регистр DX адреса выводимого текста. Пересылка в регистр Ah шестнадцатиричного числа 09h являющегося кодом функции операционной системы выводящей текст на экран. Команда программного прерывания, заставляющая процессор выполнить функцию 09h (вывод строки текста на экран). Далее идут несколько команд манипулирования данными Команда Mov пересылает (копи-рует) данные из первого байта таблицы Tabb находящейся в оперативной памяти, в регистр AL. Пересылка в регистр АН второго байта таблицы Tabb. Пересылка в регистр BL третьего байта таблицы Tabb. Пересылка в регистр ВН четвертого байта таблицы Tabb. Пересылка в регистр DL шестого байта таблицы Tabb. Пересылка в регистры процессора al,ah,bl,bh,cx,dx десятичных ишестнадцатиричных данных из таблиц Tabb, Tabb1, Tabw, Tabw1. Пересылка в регистры процессора cx,dx,bx,aх, десятичных ишестнадцатиричных данных из таблиц Tabb, Tabb1. Tabw, Tabw. Эти команды меняют содер-жимое регистров AX,BX и CL,DH. Команды завершения программы на языке Ассемблера Эти три команды завершают любую программу на Ассемблере. |
9. Сохраните набранный текст программы, кликнув F2.
10. Кликните Esc и выйдите из редактора .
11. Выделите курсором TASM.exe.
12. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке появится TASM.exe.
13. Выделить курсором LAB0xxx.ASM.
14. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке, появится TASM.exe LAB0xxx.ASM.
15. Кликните Enter. Этим кликом запустите транслятор TASM.exe, который проверит синтаксис текста и преобразует мнемокоды программы в машинные (двоичные) коды.
16. В случае успешной трансляции (транслятор не обнаружил ошибок в тексте программы), TASM создаст объектный файл LAB0xxx.OBJ.
17. Если файл LAB0xxx.OBJ не появился в списке файлов нашей папки, это означает, что транслятор обнаружил ошибки в тексте программы.
18. Результаты трансляции можно посмотреть кликнув Ctrl + О. Транслятор отобразит на экране некоторую служебную информацию и номера строк нашей программы с типами ошибок.
19. Найдите и запомните номера строк и типы ошибок.
20. Вернитесь в папку, кликнув Ctrl + О.
21. Станьте курсором на файл LAB0xxx.ASM и кликните F4 (перейдете в режим редактирования файла). На экране появится набранный текст программы.
22. Отыщите ошибочную строку (номер строки, где находится курсор, указывается в верхнем правом углу экрана) и исправьте ошибку в тексте программы.
23. Исправьте ошибки во всех ошибочных строках.
24. Сохраните программу (F2).
25. Повторите пункты 11‒14.
26. Повторяйте пункты 17‒22 до появления файла LAB0xxx.OBJ.
27. После появления файла LAB0xxx.OBJ приступаем ко второму этапу – компоновке программы.
28. Выделите курсором TLINK.exe.
29. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке, появится TLINK.exe.
30. Выделите курсором файл LAB0xxx.OBJ.
31. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке появится TLINK.exe LAB0xxx.OBJ.
32. Кликните Enter. В результате работы компоновщика создастся исполняемый файл LAB0xxx.EXE.
33. Станьте курсором на файл LAB0xxx.EXE и кликните Enter. Ваша программа исполнится. Результаты работы программы можно посмотреть на экране кликнув Ctrl + О.
34. Кликните Ctrl + О и вернитесь в папку.
35. Выделите курсором TD.exe.
36. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке появится TD.exe.
37. Выделите курсором файл LAB0xxx.exe.
38. Нажмите Ctrl и кликните Enter (Ctrl + Enter). Внизу экрана, в командной строке появится LAB0xxx.exe.
39. Кликните Enter. Появится экран Турбо Дебюггера.
· Кликните мышкой «OK» на экране монитора. Вы увидите на экране свою программу в машинных кодах и мнемоническом виде, все видимые регистры процессора и их содержимое на данный момент (рисунок 1.3).
File Edit View Run Breakpoints Data Options Window Help ── CPU 80486 ─ 1 2 3 4 5 6 7 cs: 0000 B81653 mov ax,5316 ax 5321 c=0 cs: 0003 8ED8 mov ds,ax bx 0000 z=0 cs: 0005 A05200 mov al,[0052] cx 0000 s=0 cs: 0008►8A265300 mov ah,[0053] dx 0000 o=0 cs: 000C 8A1E5400 mov bl,[0054] si 0000 p=0 cs: 0010 8A3E5500 mov bh,[0055] di 0000 a=0 cs: 0014 8A165700 mov dl,[0057] bp 0000 i=1 cs: 0018 A05800 mov al,[0058] sp 0400 d=0 cs: 001B 8A265900 mov ah,[0059] ds 5316 cs: 001F 8A1E5A00 mov bl,[005A] es 5302 cs: 0023 8A3E5B00 mov bh,[005B] ss 531D cs: 0027 A15E00 mov ax,[005E] cs 5312 cs: 002A 8B1E6000 mov bx,[0060] ip 0008 ╔═[■]═Dump══════════════════════════2═[↑][↓]═╗┤ ds:0000 8F E0 A8 A2 A5 E2 21 20 Привет! ▲│ ds:0008 9D E2 AE 20 AF A5 E0 A2 Это перв ds:0010 A0 EF 20 AF E0 AE A3 E0 ая прогр │ ds:0018 A0 AC AC A0 20 E1 E2 E3 амма сту ▼ │ F1-Help F2-Bkpt F3-Mod F4-Here F5-Zoom F6-Next F7-Trace F8-Step F9-Run F10-Menu |
Рисунок 1.3 – Экран Турбо Дебюггера |
Турбо Дебюггер дает возможность выполнять программу в шаговом режиме по одной команде. Во время исполнения команд можно наблюдать, как изменяется состояние регистров процессора.
На приведенном рисунке 1.3 цифрами 1–7 обозначены столбцы со следующей информацией:
· в первом столбце регистр CS, показывающий, что команда находится в сегменте кода;
· второй столбец отображает содержимое регистра указателя команд (IP), то есть здесь указан относительный адрес команды в байтах;
· в третьем столбце отображен шестнадцатиричный код команд программы. Каждая пара знаков кода располагается в одном байте;
· четвертый столбец отображает мнемонический код команд программы;
· в пятом столбце приведены операнды команд. В квадратных скобках указаны адреса операндов в основной памяти;
· в шестом столбце приведены видимые регистры процессора и их содержимое;
· седьмой столбец отображает состояние регистра флагов.
40. Кликните F8. Исполнится первая команда, пересылающая в регистр АХ адрес сегмента данных.
41. Каждое нажатие клавиши F8 заставляет процессор выполнять
очередную команду.
Таким образом можно просмотреть выполнение всей программы, отслеживая изменение состояния регистров и проверяя корректность исполнения каждой команды.
42. После исполнения второй команды можно вызвать на экран и посмотреть содержимое сегмента данных программы. Для чего кликните по команде View главного меню и в выпадающем меню команду Dump. В результате на экране появится содержимое сегмента данных исполняемой программы. Ухватив мышкой за Dump, перетащите изображение вниз экрана. Теперь можно наблюдать, какие данные хранятся в адресах, указанных в квадратных скобках команд.
43. Сравните числа из сегмента данных в исходном тексте программы, с этими же числами, в оттранслированной программе. Вы увидите, что шестнадцатиричные числа не изменились, а десятичные преобразовались в шестнадцатиричный код.
44. Нажимая F8 и исполняя команды программы обратите внимание, на какую величину изменяется содержимое регистра указателя команд (IP), при исполнении каждой команды и как изменяется содержимое регистров процессора. Выясните, соответствует ли появляющееся содержимое регистров процессора ожидаемому результату.
В результате проделанной работы вы получили первый опыт составления, набора, редактирования и трансляции программы, написанные на Ассемблере.
Пояснения к программе
Прочитайте этот текст в обязательном порядке.
Первые пять предложений программы служат для передачи служебной информации Ассемблеру, который пользуется ею в своей дальнейшей работе. Однако в состав исполняемой программы, состоящей из машинных кодов, эти строки не попадут, так как процессору, выполняющему команды программы, они не нужны. Другими словами, операторы .Model small, .Stack, .Data, db, dw, .Code в машинные коды не преобразуются, а используются Ассемблером на этапе трансляции программы. Такие нетранслируемые операторы являются псеводооператорами, или директивами Ассемблера в отличие от истинных операторов ‒ команд языка.
Директива .Stack определяет наш сегмент стека. Так как стек используется не только нами, но и операционной системой тоже, то размер стека должен быть не менее 128 байт. Мы задали произвольно размер стека 300h, что в десятичной системе составит 768 байт.
Директива .Data определяет наш сегмент данных. У нас в качестве данных выступает строка текста. Двоичный код каждого символа в строке имеет 8 бит т.е. один байт. Поэтому текстовые строки определяются директивой ассемблера db (от define byte, определить данные как байтовые коды). Каждая строка текста заключается в апострофы и заканчивается символом доллара ($).
Для того чтобы в программе можно было обращаться к данным, поля данных, как правило, предваряются именами. В нашем случав таким именем является вполне произвольное обозначение Txt.
Предложение, начинающееся с метки beg, является исполнимой строкой программы. Метка указывает процессору адрес первой строки программы после ее загрузки. Начиная от точки входа программа исполняется строка за строкой точно в том порядке, в каком написана программистом.
Две первых команды выполняют инициализацию сегментного регистра данных (DS). Для чего, значение имени (т.е. адрес сегмента) загружается командой mov (от move, переместить) в регистр общего назначения процессора АХ, а затем из регистра АХ переносится в регистр DS.
Такая двухступенчатая операция нужна потому, что процессор в силу некоторых особенностей своей архитектуры не может выполнить команду непосредственной загрузки адреса в сегментный регистр. Поэтому приходится пользоваться регистром АХ в качестве "перевалочного регистра".
Следующие три команды реализуют существо процедуры вывода на экран строки текста. Делается это не непосредственно, а путем обращения к служебным программам или функциям операционной системы.
Дело в том, что в составе команд процессора нет команд вывода данных на экран (как ввода с клавиатуры, записи в файл на диске и т.д.). Вывод даже одного символа на экран в действительности представляет собой сложную операцию, для выполнения которой требуется длинная последовательность команд процессора.
Конечно, эту последовательность команд можно было бы включить в нашу программу, однако гораздо проще обратиться за помощью к операционной системе (OС).
В состав операционной системы входит большое количество программ, осуществляющих стандартные и часто требуемые функции.
Для того, чтобы обратиться к OS, надо загрузить в регистр АН номер требуемой функции, а в другие регистры исходные данные для выполнения этой функции, после чего выполнить команду int 21h, (int - от interrupt, прерывание), которая передаст управление операционной системе.
Вывод на экран строки текста выполняется функцией ОС 09h, которая требует, чтобы в регистре DX содержался адрес выводимой строки, что мы и делаем командой Lea DX,Txt, (Lea − переслать адрес строки Txt в регистр DX).
Конец строки в программе отчетливо виден, однако в машинных кодах, из которых состоит выполнимая программа, он никак не отмечен, и OС, выведя на экран последнее слово, продолжит вывод байтов памяти, расположенных за текстом до конца оперативной памяти.
Поэтому операционной системе следует передать информацию о том, где кончается строка текста, что мы и делаем, помещая в конец строки символ $ (24h), который заканчивает нашу фразу.
Далее в программе идут команды пересылки данных. Байтовые и словные данные представлены в десятичной и шестнадцатиричной системах счисления.
Обратите внимание на операнды команд пересылки данных. В этих командах в байтовые регистры, такие как AL, AH, BL, BH и прочие, записываются байтовые типы данных, а в словные регистры, такие как AX, BX, CX, DX, записываются словные (двухбайтовые) типы данных. Соблюдение соответствия типов данных ассемблером контролируется строго.
После окончания работы программы операционная система должна выполнить некоторые служебные действия.
Во-первых необходимо сохранить параметры выполненной программы.
Во-вторых, надо освободить занимаемую нашей программой память, чтобы туда можно было загрузить следующую программу.
В-третьих, надо вызвать системную программу, которая будет ожидать следующую команду оператора ЭВМ.
Все эти действия выполняет функция OС с номером 4Ch. Поэтому мы загружаем 4Ch в регистр AН и вызываем OС уже знакомой нам командой int 2In.
Директивой End заканчивается любая программа на Ассемблере. Операндом директивы является метка точки входа в программу. В нашем случае это метка Beg (может быть и другое произвольное имя).