
- •I.Ошский Государственный Университет
- •1. Предварительная подготовка
- •2 Порядок выполнения работы на эвм
- •Контрольные вопросы:
- •IV.Лабораторная работа №2 Массивы
- •23 04 05 67 05 06 07 99 67 08 09 23 87 09 00 08
- •Контрольные вопросы:
- •Лабораторная работа №3
- •Контрольные вопросы:
- •Лабораторная работа №4 Процедуры.
- •Теоретическая часть
- •Работа команд ret и retf
- •Состояние флагов после выполнения команды не меняется. Error: Reference source not found
- •Программа №7.1
- •Контрольные вопросы
Работа команд ret и retf
Алгоритм работы: Работа команд зависит от типа процедуры:
для процедур ближнего типа — восстановить из стека содержимое ip;
для процедур дальнего типа — последовательно восстановить из стека содержимое ip и сегментного регистра cs.
если команда ret имеет операнд, то увеличить содержимое sp на величину операнда число;
Состояние флагов после выполнения команды не меняется. Error: Reference source not found
Применение:Команду ret необходимо применять для возврата управления вызывающей программе из процедуры, управление которой было передано по команде call. На самом деле микропроцессор имеет три варианта команды возврата ret - это ret, ее синоним retn, а также команда retf. Они отличаются типами процедур, в которых используются. Команды ret и retn служат для возврата из процедур ближнего типа. Команда retf — команда возврата для процедур дальнего типа. Какая конкретно команда будет использоваться, определяется компилятором; программисту лучше использовать команду ret, и доверить транслятору самому сгенерировать ее ближний или дальний вариант. Количество команд ret в процедуре должно соответствовать количеству точек выхода из нее. Некоторые языки высокого уровня, к примеру Pascal, требуют, чтобы вызываемая процедура очищала стек от переданных ей параметров. Для этого команда ret содержит необязательный параметр число, который, в зависимости от установленного атрибута размера адреса, означает количество байт или слов, удаляемых из стека по окончании работы процедуры
Синтаксис директив ARG и LOCAL
Приведем синтаксис определения передаваемых процедуре аргументов:
ARG аргумент [,аргумент]... [=идентификатор]
[RETURNS аргумент] [,аргумент]]
При определении локальных переменных процедуры используется следующий синтаксис:
LOCAL аргумент [,аргумент]... [=идентификатор]
Отдельные аргументы имеют следующий синтаксис:
имя_аргумента [[выражение_счетчик_1]]
[: сложный_тип [:выражение_счетчик_2]]
где "сложный_тип" - это тип данных аргумента. Он может быть либо простым типом, либо сложным выражением-указателем.
"Выражение_счетчик_2" задает, сколько элементов данного типа определяет аргумент. Например, в определении аргумента:
ARG tmp:DWORD:4
определяется аргумент с именем "tmp", состоящий из 4 двойных слов.
По умолчанию "выражение_счетчик_2" имеет значение 1 (кроме аргументов типа BYTE). Так как вы не можете занести в стек байтовое значение, для аргументов типа BYTE значение счетчика по умолчанию равно 2, что обеспечивает для них в стеке размер в слово.
Это согласуется с языками высокого уровня, которые интерпретируют передаваемые в качестве параметров символьные переменные. Если вы действительно хотите задать аргумент, как один байт в стеке, нужно явным образом определить значение поля "выражение_счетчик_2", равное 1. Например:
ARG realbyte:BYTE:1
"Выражение_счетчик_1" представляет собой число элементов массива. Общее пространство, резервируемое для аргумента в стеке, равно произведению "выражения_счетчик_2" на длину, заданную полем "тип_аргумента" и на "выражение_счетчик_1". Если поле "выражение_счетчик_1" не задано, то по умолчанию оно равно 1. Общее число аргументов задает произведение "выражения"_счетчик_1" на "выражение_счетчик_2".
Если вы завершаете список аргументов символом равенства (=) и идентификатором, тоАссемблер будет приравнивать этот идентификатор к общему размеру блока аргументов (в байтах). Если вы не используете автоматическое использование соглашений языков высокого уровня вАссемблере, то можете использовать данное значение в конце процедуры в качестве аргумента инструкции RET. Заметим, что это вызывает очистку стека от всех занесенных туда перед возвратом аргументов (это соглашения по вызову, принятые в Паскале).
Аргументы и переменные определяются в процедуре как операнды в памяти относительно BP. Передаваемые аргументы, определенные с помощью директивы ARG, имеют положительное смещение относительно BP. Локальные переменные, определенные с помощью директивы LOCAL, имеют отрицательное смещение от BP. Приведем пример:
.
func1 PROC NEAR
ARG a:WORD,b:WORD:4,c:BYTE=d
LOCAL x:DWORD,y=WORD:2=z
.
Здесь a определяется, как [bp+4], b определяется, как [bp+6], c определяется, как [bp+14], а d - как 20. x - это [bp-2], y - [bp-6], а z - 8.
Область действия аргументов и имен локальных переменных
Если вы не задаете для них имена с предшествующий префиксом локального идентификатора, все аргументы, заданные в заголовке процедуры, определены ли они с помощью директивы ARG (передаваемые аргументы), RETURN (возвращаемые аргументы) или LOCAL (локальные переменные) имеют глобальную область действия.
Идентификаторы с локальной областью действия разрешает директива LOCALS. Например:
..
LOCALS
test1 PROC PASCAL FAR
ARG @a:WORD,@d:WORD,@c:BYTE
LOCAL @x:WORD,@y:DWORD
MOV ax,@a
MOV @x,ax
LES di,@b
MOV WORD ptr @y,di
MOV WORD ptr @y+2,es
MOV @c,'a'
RET
ENDP
test2 PROC PASCAL FAR
ARG @a:DWORD,@b:BYTE
LOCAL @x:WORD
LES di,@a
MOV ax,es:[di]
MOV @x,ax
CMP a1,@b
jz @dn
MVO @x,0
@dn: MOV ax,@x
RET
ENDP
..
Поскольку в данном примере используются переменные локальной области действия, их имена существуют только в теле процедуры. Таким образёом, в test2 можно снова использовать имена @a, @b и @x.
Сохранение регистров
Большинство языков высокого уровня требуют, чтобы вызываемые процедуры сохраняли определенные регистры. Это можно сделать, занося их в стек в начале процедуры и извлекая из стека в конце процедуры.
Ассемблер может автоматически генерировать код для сохранения и восстановления этих регистров, который включается в код начала и завершения. Эти регистры можно указать в операторе USES, который имеет следующий синтаксис:
USES элемент [,элемент]...
где "элемент" может быть регистром или состоящим из одной лексемы элементом данных, который можно заносить и извлекать из стека. В одной процедуре допускается использовать не более 8 элементов.
Например:
.
myproc PROC PASCAL NEAR
ARG @source:DWORD,@dest:DWORD,@count:WORD
USES cx,si,di,foo
MOV cx,@count
MOV foo,@count
LES di,@dest
LDS si,@source
REP MOVSB
ENDP
..
Вложенные процедуры и правила области действия
Хотя вы можете вкладывать одну процедуру в другую, все процедуры имеют глобальную область действия. Например:
.
test1 PROC FAR
; код процедуры
CALL test2
; код процедуры
RET
test2 PROC NEAR
; код процедуры
RET ; ближний возврат
test2 ENDP
test1 ENDP
.
В данном примере вне охватывающей процедуры можно вызывать test1 и test2.
Если вы хотите получить локальные подпроцедуры, используйте имя с локальной областью действия, например:
.
LOCALS
test1 PROC FAR ; код процедуры
RET
@test2 PROC NEAR ; код процедуры
RET
@test2 ENDP
test1 ENDP
.
.
Примечание: Директива LOCALS разрешает идентификаторы с локальной областью действия.
В данном коде в процедуре test1 вы можете обратиться только к процедуре @test2. Фактически, если они не находятся в одной и той же процедуре может существовать несколько процедур с именем @test2. Например, допустимо следующее:
.
.
LOCALS
test1 PROC FAR
MOV si, OFFSET Buffer
CALL @test2
RET
@test2 PROC NEAR ; некоторый код
RET
@test2 ENDP
test2 PROC FAR
MOV si,OFFSET Buffer2
CALL @test2
RET
@test2 PROC NEAR ; некоторый код
RET
@test2 ENDP
test2 ENDP
.
Следующий код недопустим:
..
LOCALS
test1 PROC FAR
MOV si,OFFSET Buffer
CALL @test2
RET
test1 ENDP
@test2 PROC NEAR
; код процедуры
RET
@test2 ENDP
..
так как вызов @test2 задает локальный идентификатор для процедуры test1, а таких идентификаторов не существует.
Ниже приведены форматы соответствующих машинных команд. Прямой вызов NEAR-процедуры (для получения адреса перехода disp добавляется к IP):
Е8 |
disp_l |
disp_h |
Прямой вызов FAR-процедуры (offset и seg замещают IP и CS):
Е8 |
offset_l |
offset_h |
seg_l |
seg_h |
Задание 1 (2 часа)
Повторить теоретический материал о процедурах по конспекту лекций и литературе.
Прочитайте задание, которое выполняет нижеприведеннаяпрограмма, напишите эту программу с именем Lab7-1.asm.
Сделайте исполняемый файл, и проследить за работой в Турбоотладчике с различными данными.
Задание 2 (2 часа)
Напишите комментарий к каждой строке программы №7.1 с содержанием регистров.
На основе проделанной работы сделать отчет, внести в него краткие выводы.
Следующая программа переводит содержимое регистра AX в шестнадцатеричное представление и записывает результат в строку смещение которой хранится в регистре BX