Министерство образования Российской Федерации
Санкт-Петербургский государственный электротехнический
университет «ЛЭТИ»
Кафедра МОЭВМ
ОТЧЁТ
по лабораторной работе №4
«Программа, подпрограмма и макрос на языке Ассемблера»
предмет: организация и функционирование аппаратных и программных средств ЭВМ
Руководитель: Улитовский В.А.
Студент гр. 3341: Соколов И.С.
Санкт-Петербург
2005 г.
Вопросы, подлежащие изучению
Программа. Операторы компилятора. Директивы компилятора.
Макрос. Макроопределение, макровызов и макрорасширение. Роль компилятора в построении макрорасширения.
Подпрограмма. Способы передачи управления подпрограмме при вызове и возврате из подпрограммы. Особенность реализации ближнего и дальнего вызова. Применение подпрограммы, представленной в файле в виде объектного кода.
Подпрограмма. Способы передачи данных в подпрограмму и из подпрограммы. Передача данных по значению и по ссылке.
Подпрограмма. Особенность использования аппаратных средств. Подготовительные и заключительные действия в теле процедуры. Сохранение регистров. Восстановление стека.
Средства языка, осваиваемые в работе
OFFSET A – на стадии компиляции заменятся на адрес смещения переменной A
LEA Destination, Source – Загружает относительный адрес переменной Source в Destination. Фактически эквивалентно MOV Destination, OFFSET Source
Директива PROC, ENDP. Организуют подпрограммы. Формат директивы:
Имя_подпрограммы PROC NEAR/FAR
<код подпрограммы>
Имя_подпрограммы ENDP
Каждая процедура имеет уникальное имя и содержит собственную директиву ENDP для указания конца процедуры.
Директивы PROC имеют операнд NEAR для указания того, что эти процедуры находятся в текущем кодовом сегменте FAR – информирует систему о том, что данный адрес является точкой входа для выполнения, а директива ENDP определяет конец процедуры. По умолчанию ассемблер принимает тип NEAR. Кроме того, если процедура объявлена с директивой NEAR то при ее вызове в стек будет помещено одно слово с адресом выхода. В случае с FAR – два слова.
Операторы языка CALL Something вызывает процедуру с именем Something, т.е. управление передается процедуре Something, после окончания которой управление передается следующей команде. Перед тем как передать управление процедуре оператор помещает в стек адрес следующей команды.
Оператор языка RET осуществляет выход из подпрограммы, выталкивая из стека необходимые элементы.
Оператор языка MUL A, перемножает содержимое регистра AX c переменной A и верхнюю часть результата помещает в DX, а нижнюю в AX. Оператор перемножает беззнаковые переменные.
Оператор языка IMUL предназначен для перемножения знаковых переменных.
Оператор языка ADD Destination, Source предназначен для сложения источника и приемника, причем результат помещается в приемник (Destination).
Оператор языка SUB Destination, Source предназначен для вычитания из приемника (Destination) источник (Source) и помещает в приемник.
Текст программы
; ТЕКСТ ПРОГРАММЫ
EOFLine EQU '$' ; Определение символьной константы
; "Конец строки"
mult MACRO A, B ; Произведение A и B, результат в AX, DX
mov DX, OFFSET MulMessage; УМНОЖЕНИЕ
call WriteMsg
push A
push B
call Write
mov AX, A
mul B
push AX
push DX
mov DX, OFFSET Message
call WriteMsg
pop AX
call WriteAX
pop AX
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
ENDM
Sum MACRO A, B ; Сумма A и B, резултат в AX
mov DX, OFFSET SumMessage ; СЛОЖЕНИЕ
call WriteMsg
push A
push B
call Write
mov AX, A
add AX, B
mov A, AX
mov DX, OFFSET Message
call WriteMsg
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
ENDM
; Стек программы
AStack SEGMENT STACK
DW 12 DUP(?) ; Отводится 12 слов памяти
AStack ENDS
;Данные программы
DATA SEGMENT
; Директивы описания данных
_Enter DB 0AH, 0DH, EOFLine
Message DB 'Результат операции: ', EOFLine
UserMessage1 DB 'A = ', EOFLine
UserMessage2 DB 'B = ', EOFLine
MulMessage DB 'Выполняю умножение...', 0AH, 0DH, EOFLine
SumMessage DB 'Выполняю сложение...', 0AH, 0DH, EOFLine
DivMessage DB 'Выполняю деление...', 0AH, 0DH, EOFLine
Hello DB 'Старт программы ', 0AH, 0DH, EOFLine
GameOVER DB 'Конец работы программы ', 0AH, 0DH, EOFLine
Variable_1 DW 2H
Variable_2 DW 10H
DATA ENDS
; Код программы
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:AStack
; Процедура печати строки
WriteMsg PROC NEAR
push AX
xor AX, AX
mov AH, 9
int 21h ; Вызов функции DOS по прерыванию
pop AX
ret
WriteMsg ENDP
; Процедура печати числа в шестнадцатиричной системе
WriteAX PROC NEAR
mov BX, AX
mov CL, 4
shr AH, CL
mov AL, AH
call Print_Nible
mov AH, BH
and AH, 0Fh
mov AL, AH
call Print_Nible
mov CL, 4
mov AL, BL
shr AL, CL
call Print_Nible
mov AL, BL
and AL, 0Fh
Print_Nible:
cmp AL, 10
sbb AL, 69H
das
mov DL, AL
mov AH, 2
int 21h
ret
WriteAX ENDP
Write PROC NEAR
mov DX, OFFSET UserMessage1
call WriteMsg
mov AX, SS:10H
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
mov DX, OFFSET UserMessage2
call WriteMsg
mov AX, SS:12H
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
ret 4
Write ENDP
delenie PROC NEAR ; В стеке длжны находиться делимое и делитель
mov DX, OFFSET DivMessage ; ДЕЛЕНИЕ
call WriteMsg
mov DX, OFFSET UserMessage1
call WriteMsg
mov AX, Variable_2
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
mov DX, OFFSET UserMessage2
call WriteMsg
mov AX, Variable_1
call WriteAX
mov DX, OFFSET _Enter
call WriteMsg
mov AX, Variable_2 ; Делимое
mov BX, Variable_1 ; Делитель
; результат в CX
xor CX, CX ; Очистка частного
Repeat: cmp AX, BX ; Если делимое < делителя,
jb Quit ; то выйти
sub AX, BX ; Вычитание делителя из делимого
inc CX ; Инкремент частного
jmp Repeat ; Повторить цикл
; Частное в CX, остаток в AX
Quit:
mov DX, OFFSET Message
call WriteMsg
mov AX, CX
call WriteAX
mov DX, OFFSET _Enter
call Writemsg
ret
delenie ENDP
; Головная процедура
Main PROC FAR
push DS ;\ Сохранение адреса начала PSP в стеке
xor AX, AX ; > для последующего восстановления по
push AX ;/ команде ret, завершающей процедуру.
mov AX, DATA ; Загрузка сегментного
mov DS, AX ; регистра данных.
mov DX, OFFSET HELLO
call WriteMsg
call delenie
Mult Variable_1, Variable_2
sum Variable_1, Variable_2
mov DX, OFFSET GAMEOVER
call WriteMsg
ret 2 ; Выход в DOS по команде,
; находящейся в 1-ом слове PSP.
Main ENDP
CODE ENDS
END Main