Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скляров И. Изучаем Assembler за 7 дней (2010).pdf
Скачиваний:
1335
Добавлен:
23.02.2015
Размер:
2.11 Mб
Скачать

http://www.sklyaroff.ru

51

ДЕНЬ 3

Основные конструкции ассемблера

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

3.1. Цикл

На втором дне мы с вами научились создавать программу, которая выводит на экран фразу "Hello, World!".

А теперь представим, что нам требуется создать программу, которая должна вывести на экран пять раз фразу "Hello, World!". Конечно, можно просто пять раз выполнить в программе операцию вывода, как показано в листинге 3.1.

Листинг 3.1. Вывод на экран пять раз "Hello, World!" без использования цикла

(loop1.asm)

.model tiny

.code

org 100h

start: mov

ah,9

 

mov

dx,offset message

int

21h

 

mov

ah,9

 

mov

dx,offset message

int

21h

 

mov

ah,9

 

mov

dx,offset message

int

21h

 

mov

ah,9

 

mov

dx,offset message

int

21h

 

mov

ah,9

 

mov

dx,offset message

int

21h

 

ret

 

 

message

db

"Hello, World!",0Dh,0Ah,'$'

end start

http://www.sklyaroff.ru

52

Выполните трансляцию и линковку этой программы: ml loop1.asm

Затем запустите полученный файл loop1.com, вы должны увидеть на экране:

Hello, World!

Hello, World!

Hello, World!

Hello, World!

Hello, World!

Программа успешно работает, но нерациональность такого решения очевидна. Нам приходится набирать один и тот же участок кода в пяти экземплярах. Возможно, пять раз не столь ощутимо, но представим, что нам бы потребовалось вывести 100 или даже 1000 раз фразу "Hello, World!"?

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

loop метка

Метка служит для передачи управления на ту команду (или последовательность команд), которая должна повторяться. Число повторов для команды LOOP всегда задается в регистре CX (для 16-битных программ) или в регистре ECX (для 32битных программ) (неслучайно регистр CX называется "счетчик"). Обычно значение

вCX заносится с помощью команды MOV CX,N, где N – целое число большее нуля.

Вобщем виде цикл на ассемблере с использованием LOOP организуется следующим образом:

MOV CX, N

; устанавливаем число повторов (N>0)

Mark:

; метка

...

; тело цикла будет выполнять N раз

LOOP Mark

 

В листинге показана программа с применением цикла для вывода пять раз фразы

"Hello, World!".

Листинг 3.2. Вывод на экран пять раз "Hello, World!" с использованием цикла

(loop2.asm)

.model tiny

.code

org 100h

start:

 

 

 

mov

cx,5

; устанавливаем число повторов (5 раз)

Mark:

 

 

 

mov

ah,9

 

; тело цикла

mov

dx,offset message

;

int

21h

 

;

loop

Mark

 

 

ret

 

 

 

message

db

"Hello, World!",0Dh,0Ah,'$'

end

start

 

 

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

http://www.sklyaroff.ru

53

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

Стоит отметить важную деталь, что после каждой итерации цикла значение в CX (или в ECX для 32-битных программ) уменьшается на 1. То есть, в нашем случае после вывода первой фразы "Hello, World!" в CX останется значение 4, после вывода второй фразы в CX останется 3 и т. д. Цикл завершается, когда в CX остается значение 0.

Настоятельно советую запустить эту программу под отладчиком и потрассировать программу клавишей <F8> (пошаговое выполнение с заходом в процедуры). При этом наблюдайте, как будет уменьшаться значение регистра CX в окне регистров отладчика (окно 7). Далее в книге я не буду напоминать, но старайтесь работу каждой программы из этой книги наблюдать в отладчике (см. разд. 2.9).

Существуют разновидности команды LOOP.

Следующие две команды работают одинаково (имеют одинаковые коды): loope метка

loopz метка

Переход на метку осуществляется, если значение регистра CX ≠ 0 и значение флага

ZF = 1.

Следующие две команды также имеют одинаковые коды, а, значит, работают одинаково:

loopne метка loopnz метка

В них переход на метку осуществляется, если CX ≠ 0 и ZF = 0.

Также как для обычной команды LOOP число повторов для перечисленных четырех команд задается в регистре CX (для 16-битных программ) или в регистре ECX (для 32-битных программ). Содержимое регистра CX (ECX) уменьшается на один после каждой итерации, команды заканчивают выполнение, когда значение в CX (ECX) становится равным нулю.

3.2. Безусловный переход

В программах можно нарушать естественный (последовательный) порядок выполнения команд, для этого служат команды перехода. Переходы бывают условные и безусловные. Условный переход выполняется только тогда когда выполняется заранее заданное условие, безусловный переход выполняется всегда без каких-либо условий. В ассемблере безусловный переход выполняет команда:

JMP метка

Эта команда является аналогом оператора goto в языках высокого уровня. После выполнения JMP управление передается на метку (точнее на команду помеченную меткой).

Например, в листинге 3.3 показана программа, в которой присутствуют две функции для вывода на экран сначала фразы "Hello, World!", а затем "Goodbye, World!". Однако реально будет выведена на экран только вторая фраза, потому что с помощью команды JMP выполняет безусловный переход сразу на выполнение второй функции, т. е. первая функция вывода будет пропущена.

Листинг 3.3. Пример выполнения безусловного перехода (jump1.asm)

.model tiny

.code

org 100h

start:

http://www.sklyaroff.ru

 

54

jmp

Go_mess2

mov

ah,9

; эта функция не будет выполнена

mov

dx,offset message1 ;

int

21h

;

 

Go_mess2:

 

 

 

mov

ah,9

 

 

mov

dx,offset message2

int

21h

 

 

ret

 

 

 

message1

db

"Hello, World!",0Dh,0Ah,'$'

message2

db

"Goodbye, World!",0Dh,0Ah,'$'

end start

Вкачестве домашнего задания: добавьте в листинг 3.3 дополнительные команды JMP, так чтобы программа сначала выводила на экран фразу "Goodbye, World!", а затем "Hello, World!". При этом удалять и переставлять существующие команды в программе не нужно. Сколько минимальное количество JMP для этого нужно добавить в программу?

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

Например, команда

jmp $

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

Символ $ можно использовать для адресации. Например, в следующем примере команда JMP выполняет переход на команду MOV:

jmp $+4 ; безусловный переход на команду mov nop ; длина команды NOP составляет 1 байт nop ; длина команды NOP составляет 1 байт mov bx,10

Это происходит потому, что сама команда JMP занимает 2 байта и две команды NOP в сумме дают 2 байта, в итоге требуется всего 4 байта, для того чтобы перепрыгнуть на команду MOV. Команда NOP (ее машинный код 90h) это так называемая ничего не делающая команда, она только занимает место и время.

Вкоманде JMP может указываться тип перехода:

short (короткий переход) — если адрес перехода находится в пределах - 128…+127 байт от команды JMP. Команда короткого перехода занимает всего 2 байта: в первом байте записывается код операции (EBh), во втором – смещение к точке перехода.

near (ближний переход) — если адрес перехода находится в пределах того же сегмента, что и команда JMP. В команде ближнего перехода под смещение отводится целое слово (это дает возможность осуществить переход в любую точку 64-кбайтного сегмента), поэтому она занимает 3 байта (в первом байте находится код операции – 0E9h). По умолчанию ассемблер транслирует команды JMP, именно в этой тип.

far (дальний переход) — если адрес перехода находится в другом сегменте. Команда дальнего перехода имеет длину 5 байт. В первом байте находится код операции (0EAh), а в следующих четырех байтах — адрес сегмента и смещение точки перехода внутри сегмента.