Лаб8. Циклы. Процедуры

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

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

Команды циклов

Циклы организуются для многократного повторения одной или нескольких команд программы или процедуры. Цикл можно организовать, используя команды условного и безусловного переходов, рассмотренных в лабораторной работе 6, а можно с помощью специальных команд. Формат команд представлен в таблице.

ТАБЛИЦА ФОРМАТОВ КОМАНД ЦИКЛА

Название команды Мнемоника и формат команды Проверяемое условие цикла
Повторять цикл LOOP label (ECX/ CX) = 0
Повторять цикл, пока ноль или равно LOOPZ/ LOOPE label (ECX/ CX) = 0 или ZF = 0
Повторять цикл, пока не ноль или не равно LOOPNZ/ LOOPNE label (ECX/ CX) = 0 или ZF = 1
Переход по CX JCXZ label (ECX/ CX) = 0

 

Команда LOOP и ее расширения позволяют организовывать циклы, подобные циклам в языках высокого уровня. Регистр ECX/CX служит счетчиком максимального числа повторений цикла, его загружают перед началом цикла. Все команды, за исключением команды JCXZ, которая не изменяет ECX/CX, вычитают единицу из ECX/CX перед повторением цикла. В случае, когда условие цикла удовлетворяется, управление передается на метку label, в противном случае управление переходит на следующую за LOOP команду. Флажки этими командами не модифицируются. Метка label должна находиться в диапазоне от -128 до 127 байтов от команды, следующей за командой цикла.

Примеры.

;складываем числа от 1 до 12
mov	bx, 0
mov	ax, 0
mov	cx, 12	        ;количество повторений цикла
a1:	inc	bx
	add	ax, bx	;складываем числа
	loop	a1	;повторять, пока cx не станет равен 0
 
;тот же самый пример, но с использованием jcxz
;складываем числа от 1 до 12
mov	bx, 0
mov	ax, 0
mov	cx, 12	        ;количество повторений цикла
a1:jcxz	a2		;выход из цикла, если cx равен 0
	inc	bx
	add	ax, bx	;складываем числа
	dec	cx
	jmp	a1	;переход на начало цикла
a2: ...			
 
;ищем первую букву ’а’ в строке, адресуемой регистром bx
;длина строки 120 байтов
	mov	cx, 120		;количество повторений цикла
m1:	inc	bx
	cmp	byte ptr[bx],’а’;ищем первую букву ’а’
	loopne	m1		;повторяем цикл 120 раз или пока не найдем ’а’
                                ;проверяем, закончилась ли строка или найдена ’а’
	jz	naidena
	... 		        ;строка закончилась, буква ’а’ не найдена
naidena:...	                ;адрес ’а’ в bx

Обращение к процедурам

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

Описание процедуры состоит из заголовка, тела и конца процедуры:

имя_процедуры PROC [расстояние]     ;заголовок процедуры

;команды, директивы Ассемблера – тело процедуры

ret

имя_процедуры ENDP                                  ;конец процедуры

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

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

Процедуру можно разместить:
1) в начале программы (до первой исполняемой команды);

c_s segment
	assume cs:c_s
pr1	proc near
	...
	ret
p1	endp
begin:            ;начало программы
	...
	end begin

2) в конце программы (после команды корректного завершения работы и возвращения управления операционной системе);

c_s	segment
	assume cs:c_s
begin:
	...
	mov ah, 4ch
	int 21h	;корректное завершение работы 
		;и передача управления ОС
	;ret	;можно использовать команду ret
p1	proc near
	...
	ret
p1	endp
c_s	ends
end	begin

3) внутри тела программы или другой процедуры (должен быть предусмотрен обход процедуры с помощью оператора jmp);

c_s	segment
	assume cs:c_s
begin:
	...
	jmp m1
p1	proc near
	...
	ret
p1	endp
m1:	...
	mov ah, 4ch
	int 21h    ;корректное завершение работы 
		   ;и передача управления ОС
c_s	ends
end	begin

4) в другом модуле.

Команда CALL осуществляет вызов процедуры, сохраняя предварительно в стеке адрес возврата – адрес команды, следующей после команды CALL. При выполнении команды CALL осуществляется передача управления по адресу с символическим именем имя_процедуры.

Формат команды CALL: CALL [модификатор] имя_процедуры

Модификатор может принимать значения NEAR или FAR, для обращения к процедурам ближнего или дальнего вызовов, соответственно.

Команда RET считывает из стека адрес возврата и загружает его в регистр IP/EIP или в пару регистров CS и IP/EIP, возвращая тем самым управление на команду, следующую в программе за командой CALL. Для процедур ближнего вызова адрес возврата полностью определяется содержимым регистра IP/EIP, а для процедур дальнего вызова – содержимым двух регистров: CS и IP/EIP. При этом команда CALL запоминает в стеке сначала значение регистра CS, а затем значение регистра IP/EIP.

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

Примеры

;1. Фрагмент программы для вычисления в цикле выражения
;y = 5+6+7+8+9+10+16
mov	cx, 6		;количество циклов (10-5+1)
mov	ax, 0		;накопитель результата
mov	bx, 5		;первоначальное значение i=5
m:	add ax, bx	;ax=5+6+… 
inc	bx		;инкрементируем i
loop	m		;если цикл не завершен, возвращаемся на m
add	ax, 16		;прибавляем к сумме 16
 
;2. Программа и процедуры вывода сообщений
dseg	segment	para publicdata’
m1	db	’message1’,10,13,$’
m2	db	’message2’,10,13,$’
contor1	dw	0
contor2	dw	1
dseg	ends
 
cseg	segment	para publiccode’
	assume	cs:cseg, ds:dseg
 
main_pr	proc		;основная программа
	...
	lea	dx, m1	;параметр для процедуры print в dx
	call	print
	lea	dx, m2	;параметр для процедуры print в dх
	call	print
	...
	mov	ax,0
	push	ax	;параметр для incnum в стеке
	call	incnum
	pop	ax	;получение результата
	...
	mov	cx,offset contor1	
	push	cx	;параметр для addnum в стеке
	call	addnum
	mov	cx,offset contor2	
	push	cx	;параметр для addnum в стеке
	call	addnum
	ret
main_pr	endp
 
print	proc	near	;процедура вывода сообщений
	mov	ah, 9
	int	21h		
	ret
print	endp
incnum	proc	near	;процедура увеличения значения на 3
	pop	cx	;извлечение параметра из стека в сх
	add	cx,3
	push	cx
	ret
incnum	endp
 
;процедура увеличения значения в памяти на 1
;параметр передается через стек
;результат записывается в память в вызывающей программе
addnum	proc	near	
	pop	bx	;извлечение адреса памяти из стека в bх
	mov	ax,[bx]
	add	ax,1
	mov	[bx],ax	 ;запись результата в память
	ret
addnum	endp
 
cseg	ends
	end	main_pr
	end

Задания

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

  1. y = sum{i=0}{16}{i*6}
  2. y = sum{i=1}{7}{(i-2)}
  3. y = sum{i=5}{17}{i%3}
  4. y = sum{i=-8}{10}{i*2}
  5. y = sum{i=0}{20}{i/2}
  6. y = sum{i=-1}{15}{(i+2)}
  7. y = sum{i=-5}{5}{i*i}
  8. y = prod{i=1}{5}{i+2}
  9. y = prod{i=1}{4}{i%2}
  10. y = prod{i=1}{5}{i*2}
  11. y = prod{i=1}{7}{i+4}
  12. y = prod{i=1}{6}{i+7}
  13. y = sum{i=5}{20}{(i+i/2)}
  14. y = sum{i=-3}{20}{(i%2+i)}
  15. y = sum{i=-3}{17}{(2*(i-2))}
  16. y = sum{i=2}{10}{((i+1)/3)}
рассказать друзьям и получить подарок

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Translate Переводчик

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

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

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