5. Исполняемые файлы. Консольный ввод/вывод символа

5. Исполняемые файлы. Консольный ввод/вывод символа

Цель работы: ознакомление с типами исполняемых файлов, приобретение навыков использования функций ввода/отображения символа.

Теоретическая часть

Исполняемые файлы

Рассмотрим форматы исполняемых файлов типа .comи .exe.

В файлах типа .comпрограмма состоит из одного сегмента. Код и данные могут занимать до 64Kb и располагаться в одном сегменте. Для создания .com–файлов используется модель памяти tiny. Чтобы получить .com–файл на этапе линкования, необходимо задать параметр /t.

Исходный код программы начинается с псевдокоманды ORG 100h для сохранения пространства памяти размером 100h под заголовок файла. Данные могут быть размещены в любом месте программы, но рекомендуется  объявлять их вначале.

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

Регистр DS , как и регистр CS, содержит адрес сегмента кода. Это делается компилятором автоматически.

Точка входа в программу не описывается. Программа всегда начинается с адреса 100h. Завершить программу можно либо с помощью команды RET (возврат из подпрограммы), либо вызовом функции 4ch прерывания 21h.

Образец программы типа .com:

.model tiny
.code
	org 100h 		
start:
	jmp label
...			; область объявления данных
label:
...			;текст программы
	mov ah,4ch
	int 21h		; выход из программы
end start

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

tasm p.asm

tlink /t p.obj

Формат .exe– самый распространенный для исполняемых файлов. В программах этого формата может быть несколько сегментов. Этот формат используется для программ с большим объемом кода. Размер программы ограничивается только размером доступной памяти.

Программист должен сам следить за правильностью адресов, хранящихся в сегментных регистрах, и явно их инициализировать. Для программ типа .exe можно использовать любую модель памяти: tiny, small, compact, medium, large, huge. Пример программы в формате .exe рассмотрен в предыдущих работах.

Ввод/вывод символа функциями 01h и 02h прерывания 21h

Вызов функции01hпрерывания 21h для введения символа с клавиатуры выполняется следующим образом:

mov   ah, 01h     ;номер вызываемой функции записывается в регистр ah

int       21h             ;вызов прерывания.

;код введенного символа помещается в регистр al

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

Вывод символа на экран можно выполнить с помощью функции02h прерывания 21h:

mov ah, 02h            ;определяем номер функции

mov dl, <код>        ;код символа помещается в регистр dl

int      21h                    ;вызов прерывания

Рассмотрим пример программы, в которой символ вводится с клавиатуры. Введенный символ сохраняется в переменной S, а затем выводится на консоль. Программа будет иметь тип .com:

.model tiny
.code
org 100h
start: jmp 	label_start
s		db 	? 	;объявление неинициализированной переменной
mes1 	db 	‘Введите символ: $’
mes2	db 	‘Вы ввели символ:,10,13,$’
 
label_start:
; вывод первого сообщения
mov	ah,9
lea 	dx,mes1
int 	21h
; ввод символа 
mov 	ah, 1
int 	21h		;в al находится код введенного символа
mov 	s,al		;сохраним его в s
; вывод сообщения 2 
mov 	ah,9
lea 	dx,mes2
int 	21h
; вывод на экран введенного символа
mov 	ah, 2
mov 	dl, s	;ранее мы сохранили символ в переменной s
int 	21h
; завершение программы
mov 	ah, 4ch
int 	21h
end	start
end

Задания

  1. Написать программу для форматов .com и .exe.
  2. Сравнить размеры полученных файлов. Объяснить, почему файлы этих форматов различаются в размерах.

Варианты задач

1. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строка s2 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s2:
s2
Введите символ a1:
a1
Введите символ a2:
a2
Результат: s1ba1ba2bs2 (b – символ пробела)

2. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся символы a1 и a2 и строка s3. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s3:
s3
Введите символ a1: a1
Введите символ a2:
a2
Результат: a1bbs2a2bbs1bbs3 (b – символ пробела)

3. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строки s2 и s3 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s2:
s2
Введите символ a1:
a1
Введите строку s3: s3
Результат: s1bba1s1a1bbs2s3 (b – символ пробела)

4. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строка s2 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s2: s2
Введите символ a1:
a1
Введите символ a2: a2
Результат: a1bbs1bba2bbs1bbs2 (b – символ пробела)

5. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строки s2 и s3 и символы a1, a2 и a3. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s2: s2
Введите символ a1: a1
Введите символ a2:
a2
Введите символ a3: a3
Введите строку s3:
s3
Результат: s1a1bba3a2a2bbs2bbs3 (b – символ пробела)

6. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s3:
s3
Введите символ a1: a1
Результат: a1bbs2a1s1bbs3bba1 (b – символ пробела)

7. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строка s2 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1:
a1
Введите строку s2:
s2
Результат: s1bba1s1bbs2bba1 (b – символ пробела)

8. Массив символов s1 определен в сегменте данных. С клавиатуры вводятся строка s2 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1:
a1
Введите символ a2: a2
Введите строку s2: s2
Результат: a2s1bbs1a1bbs2 (b – символ пробела)

9. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1: a1
Введите символ a2: a2
Введите строку s3:
s3
Результат: s1a1bba2bbs2bbs3 (b – символ пробела)

10. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1: a1
Введите строку s3:
s3
Введите символ a2:
a2
Результат: a1bbs2a2s1bbs3 (b – символ пробела)

11. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s3: s3
Введите символ a1:
a1
Результат: a1bs2a1s1bbba1bs3 (b – символ пробела)

12. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s3:
s3
Введите символ a1: a1
Введите символ a2: a2
Результат: s2bba2s1bs3ba1s3 (b – символ пробела)

13. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1: a1
Введите строку s3: s3
Результат: s2ba1bs1bs3ba1bs1 (b – символ пробела)

14. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1: a1
Введите символ a2:
a2
Введите строку s3: s3
Результат: s1ba2ba1bs2bs3ba1 (b – символ пробела)

15. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символ a1. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите строку s3: s3
Введите символ a1: a1
Результат: a1bs2ba1s1bs3ba1ba1 (b – символ пробела)

16. Массивы символов s1 и s2 определены в сегменте данных. С клавиатуры вводятся строка s3 и символы a1 и a2. Написать программу, которая выводит на экран входные данные по следующему сценарию:
Введите символ a1: a1
Введите строку s3:
s3
Введите символ a2: a2
Результат: a1bs2a1s3bbs1ba2 (b – символ пробела)

Лаб4. Команды пересылки. Ввод/вывод строки функциями 3Fh и 40h прерывания 21h.

Цель работы: ознакомление с возможностями буферизированного ввода/вывода, различными командами пересылки данных и закрепление навыков выполнения и отладки программ на ЭВМ с использованием интерактивных отладчиков.

Теоретическая часть

Команды пересылки данных

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

Команды пересылки данных делятся на следующие группы:

  • команды общего назначения;
  • команды пересылки адреса;
  • команды пересылки флажков.

Рассмотрим некоторые из них.

Команды общего назначения

Команда MOV

Это основная команда общего назначения. Она позволяет переслать:

  • байт или слово между регистрами или между регистром и ячейкой памяти;
  • непосредственно адресуемое значение в регистр или ячейку памяти.

Формат команды:

MOV <приемник>, <источник>

Примеры:

mov AX, TABLE     ;переслать из памяти с адресом TABLE в регистр AX

mov TABLE, AX     ;переслать из регистра AX в память с адресом TABLE

mov CL, 25                ;переслать в регистр СLчисло 25

mov CX, BX              ;переслать в регистр CX содержимое BX

Запрещается:

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

Команда пересылки адреса LEA

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

Формат команды:

LEA <регистр>, <память>

Пример: lea BX, TABLE[DI]  ;если регистр DI содержит 5, то в

;регистре BX будет смещение ячейки

;TABLE+5 в сегменте, адресуемом

;текущим значением регистра DS

Команды PUSHиPOP

Команда PUSH помещает содержимое регистра или ячейки памяти размером в слово в вершину стека. Формат команды:

PUSH <источник>

Примеры:

push SI

push CS

push TABLE[BX][DI]

Команда POP извлекает слово с вершины стека и помещает его в ячейку памяти или регистр. Формат команды:

POP <приемник>

Пример: POP AX

Под вершиной стека понимается ячейка памяти в сегменте стека, смещение которой содержится в указателе SPSP всегда указывает на слово, помещенное в стек последним. Команда PUSH уменьшает значение SP на 2, а команда POP – увеличивает на 2.

Команды пересылки флажков PUSHF и POPF

Команда PUSHF помещает содержимое регистра флажков в вершину стека. Формат команды:

PUSHF

Команда POPF извлекает слово с вершины стека и помещает его в регистр флагов. Формат команды:

POPF

Ввод/вывод строки функциями 3Fh и 40h

При вводе строки с помощью функции 3Fh необходимо описать буфер для вводимых символов. Надо только помнить, что, в отличие от функции 0Ah, функция 3Fh сохраняет в конце введенной строки не один, а два символа:0Ah – код новой строки и 0Dh – код клавиши Enter, поэтому буфер должен быть на два байта вместительней.

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

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

Например, если буфер для ввода объявлен как

Stroka  DB   12 DUP(?) ,

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

mov AH, 3Fh               ;номер функции помещаем в регистр AH

lea DX, Stroka         ;адрес буфера ввода – в регистр DX.

;эту строчку кода можно

;заменить на MOV DX, OFFSET Stroka

mov BX, 0                 ;в BX хранится дескриптор стандартного входного потока

mov CX, 12               ;в CX – количество вводимых символов

int21h                           ;вызов прерывания

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

Функция 40h выводит строку на экран. Вызов функции осуществляется следующим образом:

mov  AH, 40h              ;номер функции помещаем в регистр AH

lea  DX, Stroka        ;адрес буфера вывода – в регистр DX.

mov  BX, 1                    ;в BX хранится дескриптор стандартного

;выходного потока

mov  CX, 10                ;в CX – количество выводимых символов

int  21h                      ;вызов прерывания

Выходной параметр – регистр AL содержит количество выведенных символов.

Задания

  1. Написать программу, соответствующую вашему варианту из третьей лабораторной работы, с использованием функций 3Fh и 40h для ввода и вывода строк на экран. Символы копировать через стек с помощью команд PUSH и POP.
  2. Выполнить программу под управлением отладчика TD. Провести пошаговую трассировку программы, отслеживая на каждом шаге содержимое сегмента данных. Изучить изменение указателя стека SP, указателя команд IP и сегмента данных от шага к шагу выполнения программы.

 

3. Способы адресации памяти. Ввод и вывод строки функциями 09h и 0Аh прерывания 21h.

3. Способы адресации памяти. Ввод и вывод строки функциями 09h и 0Аh прерывания 21h

Цель работы:  приобретение навыков в составлении простых программ, содержащих ввод данных и вывод результатов; получение знаний о режимах адресации микропроцессора i8088, о выполнении и отладке программ на ЭВМ.

Теоретическая часть

Режимы адресации микропроцессора i8088

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

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

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

При регистровой адресации МП извлекает операнд из регистра или загружает его в регистр. Например,

mov ax, cx          ; пересылка содержимого регистра cx в регистр ax

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

mov cx, 500        ; загрузить в регистр cx значение 500

Для описания других режимов адресации введем понятие исполнительного адреса.

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

При прямой адресации исполнительный адрес является составной частью команды. МП добавляет этот адрес к сдвинутому на 4 бита (т.е. умноженому на 16) содержимому регистра сегмента данных DS и получает 20–битовый физический адрес операнда. Обычно прямая адресация применяется, если операндом служит метка (символический адрес). Например,

mov ax, table ;загрузка в регистр ax содержимого
;ячейки памяти (2 байта) с меткой table

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

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

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

mov bx, offset table ;поместить в регистр bx смещение
;ячейки table
;регистре bx

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

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

mov ax, [bx]+4    ;загрузить в регистр ax содержимое по адресу,
mov ax, [bx+4]    ;отстоящему на 4 байта от ячейки, исполнительный
mov ax, 4[bx]      ;адрес которой находится в регистре bx

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

mov di, 2
mov al, table[di]
;загрузить в al третий элемент
; (со смещением 2) таблицы table

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

mov ax, [bx+2+di]
mov ax, [bx+2][di]
mov ax, [bx][di+2]

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

mov es:[bx], dx

пересылает слово из регистра dx в ячейку памяти находящуюся в сегменте, адресуемом текущим содержимым сегментного регистра es (вместо ds) со смещением, находящемся в регистре bx.

Ввод строки с помощью функции OAh прерывания 21h

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

1 байт 1 байт Буфер для ввода символов

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

Вводимые символы будут сохраняться в буфере, начиная с третьего байта от начала описываемой области.

Итак, описать область для ввода строки из 10 символов можно как

Stroka   DB   11, ?, 11 DUP(?).

Длина строки и размер буфера задаются на единицу больше, так как один символ нужен для хранения числа 0dh – кода клавиши Enter.

Для облегчения доступа к каждой из описанных областей, описание можно разбить на 3 части:

MaxLength       DB 11
CurrentLehgth DB ?
Buffer                 DB 11 DUP(?)
;знак вопроса означает, что начальное
;значение данной ячейки памяти не определено

Вызов функции 0Ah выглядит так:

mov	AH, 0Ah	;номер функции заносим в регистр AH.
;в DX заносим адрес начала области ввода
mov	DX, OFFSET MaxLength	 
;таким же образом загружается адрес начала области ввода для Stroka
;mov 	DX, OFFSET Stroka
int	21h	;вызов прерывания

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

message	DBEnter the string:,10,13,$;приглашение к вводу
maxlength DB   11		;максимально допустимая длина строки
				;последним введенным символом
;будет символ с кодом 13 (0dh шестнадцатеричное – код клавиши Enter)
curlength DB   ?		;текущая длина строки равна количеству
				;введенных символов без учета кода Enter
s1	  DB   11 DUP(?)	;буфер, в который будут помещаться 
				;вводимые символы
s2	  DB   3 DUP(?)		;вторая строка: 2 позиции под буквы и одна
				;позиция под символ $ – признак конца 
				;строки для 9–ой функции
new_line  DB  10,13,$;строка, которая будет использоваться для 
;перевода курсора на новую строку

Далее программу можно составлять по следующему сценарию:

1. Выводим строку message на экран.
2. Вводим строку s1 на экран.
3. Копируем первый символ из s1 в s2 через регистр AL:

mov     AL, s1
mov     s2, AL

4. Помещаем в BX количество введенных символов:

mov      BL, curlength
mov      BH, 0

5. Копируем последний символ из s1 в s2 на вторую позицию через регистр AL:

mov      AL, s1[BX–1]
mov      s2+1,AL

6. Помещаем символ $ в конец строк s1 и s2:

mov s2+2,’$’
mov s1[bx],’$’

7. Выводим строку s1 на экран.
8. Выводим строку new_line.
9. Выводим строку s2 на экран.
10. Выводим строку new_line.
11. Завершаем программу с помощью функции 04ch прерывания 21h.

Задания

  1. Написать программу, соответствующую вашему варианту.
  2. Выполнить программу под управлением отладчика TD. Провести пошаговую трассировку программы, прослеживая на каждом шаге содержимое сегмента данных. Изучить изменение командного указателя IP и сегмента данных от шага к шагу выполнения программы.

Варианты задач

  1. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2
    2–ой, 4–ый и 6–ой символы из строки s1. Вывести на экран строки s1 и s2.
  2. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2
    10–ый, 5–ый и 2–ой символы из строки s1. Вывести на экран строки s1 и s2.
  3. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 каждый 3-ий символ из строки s1. Вывести на экран строки s1 и s2.
  4. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 все символы, стоящие на нечетных позициях из строки s1. Вывести на экран строки s1 и s2.
  5. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 все символы, стоящие на четных позициях из строки s1. Вывести на экран строки s1 и s2.
  6. Ввести строку s1 длиной не менее 10 символов. Скопировать в строку s2 три последних символа в прямом порядке из строки s1. Вывести на экран строки s1 и s2.
  7. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три первых символа. Вывести на экран строки s1 и s2.
  8. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три первых символа в обратном порядке. Вывести на экран строки s1 и s2.
  9. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 три последних символа в обратном порядке. Вывести на экран строки s1 и s2.
  10. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 последний символ три раза. Вывести на экран строки s1 и s2.
  11. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 предпоследний символ три раза и первый. Вывести на экран строки s1 и s2.
  12. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 пятый символ два раза и три раза второй. Вывести на экран строки s1 и s2.
  13. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 первые 3 символа два раза. Вывести на экран строки s1 и s2.
  14. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 второй и четвертый символы три раза. Вывести на экран строки s1 и s2.
  15. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 девятый символ – три раза, второй – два раза. Вывести на экран строки s1 и s2.
  16. Ввести строку s1 длиной не менее 10 символов. Скопировать из строки s1 в строку s2 последний и предпоследний символы два раза. Вывести на экран строки s1 и s2.

2. Этапы создания программы на языке Ассемблер. Вывод строки на экран

2. Этапы создания программы на языке Ассемблер. Вывод строки на экран

Цель работы:  получение знаний об основных правилах записи и структуре программ на языке Ассемблер для ПЭВМ типа IBM PC; приобретение практических навыков по составлению простейших программ на языке Ассемблер.

Теоретическая часть

Этапы создания программы

Разработка программы на  Ассемблере включает несколько шагов:

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

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

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

Процесс подготовки программы включает и процесс компоновки (редактирования связей). Работа компоновщика заключается в том, чтобы в каждом модуле определить и связать ссылки на неопределённые имена и обеспечить переместимость программы. Когда программа включает  несколько модулей, компоновщик объединяет их в один файл. В итоге будет получен выполняемый файл с расширением .exe или .com. Для этих целей можно использовать программу–компоновщик link фирмы Microsoft или tlink фирмы Borland.

Например, пусть файлы с исходными кодами называются prog1.asm и myLib.inc. В этом случае ассемблирование и компоновку можно выполнить следующими командами:

Таблица команд ассемблирования и компоновки

Microsoft Borland
Этап ассемблирования masm prog1.asm
masm myLib.inc
tasm prog1.asm
tasm myLib.inc
Этап компоновки link prog1.obj
link myLib.obj
tlink prog1.obj
tlink myLib.obj

 

Общая схема программы на языке Ассемблер

Строка в программе на Ассемблере может состоять из 4–х полей:

[метка:] команда [поле операндов] [;комментарий]

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

  •  буквы от A до Z, причем Ассемблер не делает разницы между строчными и прописными буквами;
  • цифры от 0 до 9;
  • спец.символы – '?', '.'(только первый символ), '@'(коммерческое эт), '$', '_'.

Первым символом в метке должна быть буква или специальный символ. Максимальная длина метки – 31 символ.

Поле команды содержит её имя. Операнды определяют данные, регистры, символические имена (относительные адреса).

Например, команда mov ax, 4 заносит в регистр ax значение 4.

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

Комментарий начинается с символа ';'. Все символы справа от символа ';' до конца строки воспринимаются Ассемблером как комментарий.

Так как строчные и прописные символы в Ассемблере не различаются, то записи вида mov ah, 9 и MOV AH, 9 воспринимаются Ассемблером  одинаково.

Ниже представлены примеры оформления программ для компиляторов masm и tasm.

;Шаблон оформления программы в “стиле” masm
.model small	; директива описания модели памяти
; программа имеет модель памяти 
; типа small – один сегмент кода и один сегмент данных
.stack 100	; начало сегмента стека
.data	; начало сегмента данных
...	; определение данных
.code	; начало сегмента кода
...	; здесь можно включить текст подпрограмм и 
; данные, которые необходимо расположить 
; в сегменте кода
.startup	; точка начала выполнения программы
...	; текст программы
end	; директива окончания текста программы

 

;Шаблон оформления программы в “стиле” tasm
sstack	SEGMENT	para stack "stack" ;определение сегмента стека	
	DB	100 dup (?)		;область стека, не менее 32 слов
sstack 	ENDS				;конец сегмента стека
 
sdata	SEGMENT	para data		;определение сегмента данных
...					;здесь помещаются директивы 
;определения данных
sdata	ENDS				;конец сегмента данных
scode 	SEGMENT para "code"	;определение сегмента кода
ASSUME 	CS:scode, DS:sdata 	;указывает Ассемблеру, что сегмент scode будет
;адресоваться с помощью сегментного регистра CS, 
;а сегмент sdata – с помощью сегментного регистра DS. здесь можно
;включить текст подпрограмм и данные, которые необходимо расположить в 
;сегменте кода
start:					;точка входа в программу здесь
...					;помещается текст программы
scode	ENDS				;конец сегмента кода
END 	start				;директива окончания текста 
					;программы

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

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

По крайней мере, один сегмент – сегмент команд должен присутствовать в каждой программе.

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

	mov	ax, @data	; для masm
	mov	ds, ax
или	mov	ax, sdata	; для tasm
	mov	ds, ax

Задание

1. Изучить структуру программы на Ассемблере и основные требования к ней.

2. Разработать программу вывода строки “Hello World” на экран в стилях masm и tasm:

  • с использованием директивы db определить в сегменте данных строку ‘Hello World’,10,13,’$’ (Hi db  ‘Hello World’,10,13,’$’),
  • инициализировать регистр ds адресом сегмента данных,
  • с помощью функции 9 прерывания 21h вывести эту строку на экран
mov	ah, 9		;номер функции всегда помещается в регистр ah
mov	dx, offset Hi	;регистр dx содержит начальный адрес
;выводимой строки
int	21h		;вызов прерывания
  • завершить программу функцией 4Ch прерывания 21h
mov	ah, 4Ch
int	21h

3. С помощью текстового редактора набрать программу и записать ее на диск. Оттранслировать программу и получить объектный файл, листинг программы и исполняемый файл. Например, если исходный файл называется myLab1.asm, то с помощью команд

tasm myLab1.asm, ,

tlink myLab1.obj

получаются файлы myLab1.obj, myLab1.exe и myLab1.lst.

Изучить полученный листинг программы.

1. Базовые системы счисления. Объявления данных в Ассемблере

1. Базовые системы счисления. Объявления данных в Ассемблере

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

Теоретическая часть

Наименьшая единица информации, которую можно сохранить в компьютере – это бит (eng. bit - binary digit), т.е. 0 или 1. Бит – это атом информации, он не может быть разделен. Биты группируются по 8 и образуют байт. Информация, которой манипулирует компьютер – это строка бинарных чисел. Из 8 битов можно сформировать 256 комбинаций. Эти комбинации используются для того, чтобы закодировать большие и малые буквы, цифры, специальные символы.

Для измерения информации на компьютере используются величины:

1 Килобайт = 1 Кбайт  = 210 байтов = 1024 байтам;

1 Мегабайт = 1 Мбайт = 220 байтов = 1024 Кбайтам;

1 Гигабайт  = 1 Гбайт  = 230 байтов = 1024 Мбайтам.

Системы счисления

Система счисления – это множество правил и цифр представления чисел. Для любой позиционной системы счисления число цифр для представления равно основанию системы счисления, например, для двоичной системы основанием является число 2, следовательно, для представления чисел нужны две цифры 0 и 1, для шестнадцатеричной системы счисления это 0, 1, 2, …, 9, A, B, C, D, E, F, где буквы соответствуют значениям 10, 11, 12, 13, 14 и 15 соответственно.

Чтобы различать системы счисления, в конце числа ставится буква: B – для двоичного числа, Q – для восьмеричного числа, D – для десятеричного числа и H – для шестнадцатеричного. Для десятеричного числа указывать D не обязательно.

Если число записано в b–ричной системе счисления в виде

Nr(b) = Cn Cn-1 Cn-2 … C2 C1 C0 , D1 D2 D3… ,

то в десятеричной системе счисления его значение можно представить в виде суммы цифр, умноженных на основание системы счисления в степени равной номеру позиции цифры в числе (нумерация начинается с 0, справа налево):

Nr(10) = Cn*bn +C n-1*bn-1+…+C2*b2+C1*b1+C0*b0+D1*b-1+D2*b–2+D3*b–3+...

Например:

Пусть даны два бинарных числа 11b, 1100011b. Переведем эти числа в десятеричную систему счисления:

11b =1*21+1*20 =3;

11100011b = 1*27+1*26+1*25+0*24+0*23+0*22+1*21+1*20= 227.

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

11q = 1*81+1*80 = 9;

210q =2*82+1*81+0*80 =136.

Пример перевода шестнадцатеричных чисел в десятичные:

11h = 1*161+1*160=17;

CA0h= C*162+A*161+0*160= 3232

Для перевода чисел из десятичной системы в двоичную или шестнадцатеричную применяется целое деление. Число делится на основание системы счисления пока не получится неделимый остаток. Полученное от деления частное снова делится и процесс завершается, когда частное тоже становится неделимым. Полученные при делении остатки записываются в обратном порядке. На схеме показан перевод числа 25 в двоичную систему счисления, в результате которого получаем число 11001b, а также перевод числа 418 в шестнадцатеричную систему счисления, в результате которого получаем число 1A2h, учитывая, что цифра десять  - это A.

Conver_Binary      Conver_Hex

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

Таблица соответствия шестнадцатеричных цифр и двоичных чисел.

0

0000

4

0100

8

1000

C

1100

         1

0001

5

0101

9

1001

D

1101

2

0010

6

0110

A

1010

E

1110

3

0011

7

0111

B

1011

F

1111

Например, переведем число 1FDh в двоичное представление:

1FDh = 0001-1111-1101b = 111111101b

Переведем двоичное число 1110100101b в шестнадцатеричное представление:  0011-1010-0101b = 3A5.

Представление целых чисел в памяти компьютера

Для представления информации на компьютере используют двоичную систему счисления. Для хранения целых чисел используется строго фиксированное число битов: 8, 16, 32, 64. На n бинарных позиций можно записать целое число со знаком в диапазоне от -2n-1 до 2n-1-1. Позиции нумеруются от 0 до n-1 справа налево. Например, число 67 в восьми двоичных позициях будет представлено как 01000011b. Числа без знака можно представить в диапазоне 0 до 2n-1.

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

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

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

Например, для представления числа -65 имеем:

01000001b               прямой код числа +65

10111110b                обратный код

10111111b                дополнительный код числа -65

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

Типы данных

BYTE. Этот тип данных занимает 1 байт (8 битов). При помощи этого типа можно зашифровать целое число со знаком в диапазоне от -128 до +127 или без знака в диапазоне от 0 до 255, любой ASCII–символ, который также кодируется целым числом. Директива определения – DB (Define Byte).

WORD. Этот тип данных занимает 2 байта (16 битов). В переменную данного типа можно поместить целое число в диапазоне от -32768 до+32767 или от 0 до 65535, два ASCII–символа или относительный адрес памяти типа near. При этом запись в память производится следующим образом: младшая часть числа располагается по младшему адресу, а старшая – по старшему. Это справедливо и для других типов данных. Например, если целое шестнадцатеричное число 1234h расположено по адресу 1000h, то младшая часть 34h будет расположена по адресу 1000h, а 12h – по адресу 1001h. Директива определения – DW (Define word).

DWORD – 4 байта (2 слова) может вместить целое 32–битное число со знаком или без знака, число с плавающей точкой, 32–разрядный адрес памяти или 4 ASCII–символа. При хранении адреса адрес сегмента располагается в двух старших байтах, а смещение – в двух младших байтах памяти. Директива определения – DD (Define Double word).

QWORD – 8 байтов. Может быть целым знаковым или беззнаковым, числом или числом с плавающей точкой двойной точности. Директива определения – DQ (Define Quad).

TEN-BYTES – 10 байтов. Используется для хранения данных в основной памяти или в сопроцессоре. Может быть упакованным двоично–десятичным числом, расширенным целым числом или расширенным числом с плавающей точкой. Директива определения - DT (Define Ten bytes).

Общий синтаксис определения данных:

<имя> <тип> <список значений>

или

<имя> <тип> <число> dup (выражение),

где имя – идентификатор, тип – одна из рассмотренных выше директив выделения памяти, список значений – список, который может содержать символьные или числовые константы. Он может также содержать символ ?, если значение не определено, или адрес – имя переменной или метку, строку ASCII–символов, заключенных в кавычки или апострофы. Директива dup предписывает повторение значений, определяемых выражением, заданное <число> раз. Выражение может быть константой, константами, объединенными знаками арифметических операций, списком значений или символом ?, если значение не определено.

Например,

var_a	db 2 dup (0, 3 dup (1))
; эквивалентно 
var_a 	db 0,1,1,1,0,1,1,1
var_b	db 1, 2, 3, ?, ? 
adr_a 	dw var_a 
adr_b3 	dd var_b+3

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

m1	db	4, 5, 1, 6			; 4*1=4 байта
m2	db	“xzyqw”				; 5*1=5 байтов
m3	dw	12 dup(?)		        ; 12*2=24 байта
m4	dd	345h, 234h			; 2*4=8 байтов


Общее количество байтов, выделенных данными директивами, равно 41 байту. Переменная m1 располагается по относительному адресу 00h, m2 – 04h, m3 – 09h, а m4 – 021h.

Индивидуальные задания:

1. Перевести в двоичную, шестнадцатеричную и восьмеричную системы счисления десятеричные числа:

1)42;31;113 5)46;35;119 9) 49;30;103 13)29;37;97
2)45;81;89 6)66;25;110 10)19;53;101 14)21;87;98
3)12;38;118 7)17;63;96 11)34;50;107 15)28;45;130
4)11;43;67 8)13;69;88 12)14;70;99 16)15;72;100

2. Перевести в двоичную систему счисления шестнадцатеричные числа:

1)A45;12;56B 5)7C;72EB;31DB 9)34A;6AB;9AD 13)2B9;6F1;81B
2)1EF3;5AB;46F 6)3EB;4D8;A61 10)5AB;79F;AB8 14)7CD;2A1;B53
3)A56;5E9;CDE 7)6A3;9D0;8BE 11)9A;4DE;EF7 15)10B;87F;CD9
4)3B8;DE1;BAE 8)BC;7F9;78A 12)AB;8E4;C17 16)38E;9C7;B89

3. Перевести в восьмеричную и шестнадцатеричную системы счисления бинарные числа:

1)   00101011;     00100110;
01110011
5)   11110010;      01101010;
11111100;
9)   10000101;     11100010;    
11001011
13)  00011101;     11111001;    
00111101
2)   01100001;     01101110;    
11110011
6)   00110110;     00111011;    
10001100
10)  00011101;     01010110;    
10110010
14)  00011100;     01001100;    
01101110
3)   11100100;     01011100;     11000001 7)   11010010;     01001100;     11000111 11)  11100010;     10100001;     10001110 15)  10101001;     11010101;     111001100
4)   00001111;     10100101;     10010001 8)   11100000     11111000;     01000011 12)  10100101;     01101100;     11100001 16)  11100111;     01100101;     10110010;

4. Представить в дополнительном коде следующие числа:

1)-42;-31;-96 5)-46;-35;-94 9) -49;-30;-103 13)-29;-37;-97
2)-52;-41;-93 6)-66;-25;-85 10)-19;-53;-101 14)-21;-87;-98
3)-12;-38;-93 7)-17;-63;-99 11)-34;-50;-94 15)-28;-45;-95
4)-11;-43;-67 8)-13;-69;-88 12)-14;-70;-99 16)-15;-72;-89

5. Даны следующие определения переменных:

1) a   db   45,16,76,-6 
b   db   “abcd” 
c   dw   15 dup(0),3,3 
d   dd   345h
2) a   dd   2,24 
b  db   “aaa”,-8,23h,11101b 
c  db   6 dup(0), 45, 6 
d dw   -7,4Dh,8 dup(0)
3) a   db   “Salut”,10,13 
b   db   -16,-20,13h,2 dup(0)  
c   dw   62,34,-15 
d   dd   456C9h,4567
4) a   dd   92,45h,90,-54,-67   
b   db   10 dup(‘$’),10,13 
c   db   “amdto”,10,13,’$’ 
d   dw   5 dup(?),7,-80h
5) a   db   “lucrarea_1”,10,13 
b   db   2 dup(0) 
c   dw   38,-15,78,41,12 
d   dd   678EFh,3489,456
6) a   db   12,24,”sss” 
b   db   “ab”,-8,23h 
c   dd   6 dup(0),45 
d   dw   -7,5 dup(0)
7) a   db   35,53 
b   db   10 dup(‘ ’),10,13,“$” 
c   dw   5 dup(0) 
d   dd   555h
8) a   db   34,6,3,-8,-2 
b  db   “Hello”,‘$’ 
c   dw   6 dup(0),‘$’,10,13 
d   dw   -68,46h,7 dup(0)
9) a   db   45,16 
b   db   5 dup(?),10,13,“$” 
c   dw   55 dup(0) 
d   dd   34567h
10) a   db   76,87,92,45h 
b   db   20 dup(‘$’),10,13 
c   db   “qwert” 
d   dw   10 dup(0)
11) a   dd   78,34,67 
b   db   “Rezultat”,‘$’ 
c   db   16 dup(0),‘$’,10,13
12) a   db   73,74,75,77,78,-67 
b   db   15 dup(‘?’),10,13 
c   dd   777h
13) a   db   24,76,-56 
b   db   “abc”,11101b 
c   dd   45,4 dup(?) 
d   dw   4 dup(0),8,3
14) a   db   “testul_nr_2”,13,10 
b   db   -18,-22,18h,2 dup(0) 
c   dw   81,-16,44,18 
d   dd   568ABh
15) a   dd   87,45h,-9  
b   db   10 dup(?) 
c   db   “test_1$” 
d   dw   4 dup(0),2,7
16)  a   db   “Matematica”,10,13 
b   db   10,20h,2 dup(0) 
c   dw   60,30,-10,-20,-50 
d   dd   56789Bh

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

 

Translate Переводчик

Подписка на новости

SmartResponder.ru
Ваш e-mail: *
Ваше имя: *

Хостинг для Wordpress сайтов