ПЕРЕДАЧА ПАРАМЕТРОВ В ПРОЦЕДУРУ
Команды возврата
СТРУКТУРА ПОДПРОГРАММЫ
КОМАНДЫ ВЫЗОВА ПОДПРОГРАММ CALL
КОМАНДЫ ПЕРЕХОДОВ LOOPZ, LOOPE
КОМАНДА ЦИКЛА LOOP
Loop met
┌─────┐
│CX:=n│
└──┬──┘
┌──────>х met:
│ ┌──┴──┐
│ │тело │
│ │цикла│
│ └──┬──┘
│ ┌────┴────┐
│ │CX:=CX-1 │
│ └────┬────┘
│ нет / ^\ да
└────/CX=0\────┐
\ / │
\/ │
v
Команда Loop не проверяет и не изменяет значения флагов, она только уменьшает регистр СХ на единицу и сравнивает последний с нулём.
Пример: подсчитать сумму элементов массива.
x db 10 dup(?)
n dw ?
sub ax,ax
lea bx,x
mov cx,n
m:
add al,[bx]
inc bx
loop m
Мнемоники различны, но команда одна и та же:
Loopz met ( Loope met)
┌──────────────┤ MET:
│ ┌──────┴──────┐
│ │тело цикла с │
│ │формированием│
│ │ ZF │
│ └──────┬──────┘
│ ┌──────┴──────┐
│ │ CX := CX-1 │
│ └──────┬──────┘
│ / \ да
│ /ZF=1 \──────────┐
│ \ / │
│ \/ │
│ │ │
│ нет / \ да │
└───────────/CX=0 \─────┬────┘
\ / │
\/ v
Команда имеет дополнительный выход из цикла, по значению ZF=1.
В массиве Х определить первый элемент, значение которого = 5.
X DW 10 DUP (?)
N DW ?
NOM DW ?
;----------------------------
X ┌─────┬─────┬─────┬───────────┬─────┐
│X1=-1│ X2=2│ X3=5│ ......... │ Xn │
└──┴──┴──┴──┴──┴──┴───────────┴──┴──┘
Просмотр массива будет завершен после определения X3 = 5
mov cx,n
mov si,-2
met:
inc si
inc si
cmp [si],5
loopz met
jnz m1 ;в массиве нет элементов равных 5
;SI := (nom-1)*size(x)
;nom:= SI/2 +1
;после выхода из цикла
;SI указывает на исходный элемент
shr si,1
inc si
mov nom,si
jmp kon
m1: ;выдача сообщения 'в массиве нет элементов, равных 5'
КОМАНДЫ ПЕРЕХОДОВ LOOPNZ, LOOPNE содержат дополнительный выход из цикла при ZF=0. С помощью этой команды можно найти первый элемент массива, который <> заданному.
Команд цикла, которые проверяют условия >= и <= нет, для этого случая требуется самостоятельно организовывать доп. выход из тела цикла.
CALL < имя подпрограммы >
7 0 7 0 7 0
┌───────┐ ┌───────┐ ┌───────┐
│ KOP │ │dispL │ │ dispH │
└───────┘ └───────┘ └───────┘
\ /
смещение адреса относительно текущей команды
CALL OP ;OP определяет адрес входа в п/п
ALL disp ;прямой внутрисегментный вызов п/п
1) SP:= SP – 2
2) IP:= [SP]
3) disp --> IP
N_proc proc near
; ------ ---- ----
; имя директива внутрисегментная
; любая последовательность команд
; к-во push & pop должно быть одинаковым
ret
N_proc endp
RET – внутресегментный возврат
KOP = C3
1) [SP]--> IP
2) SP:= SP-2
RET – внешнесегментный возврат
1) [SP]--> IP
2) SP:= SP+2
3) [SP]--> CS
4) SP:=SP+2
1) Через общее поле памяти
DSEG SEGMENT
A DB 10 DUP (?)
N DW ?
DSEG ENDS
CSEG SEGMENT
MAIN PROC FAR
.........................
MAIN ENDP
P1 PROC NEAR
.........................
P1 ENDP
CSEG ENDS
END MAIN
Данные, описанные в DSEG доступны из любой точки программы ассемблера, отсюда и название – «передача данных в процедуру через общее поле памяти». В нашей программе обработка массива А может осуществляться с одинаковым успехом в процедурах MAIN и P1. На Паскале такой способ называют «передача параметров в процедуру через аппарат глобальных переменных», а именно: в описанной процедуре параметры отсутствуют.
На Паскале используют вложенные процедуры. Переменные внутри процедуры локальные, т.е. не доступные для других процедур.
На Ассемблере переменные одинаково доступные для всех процедур, поэтому, хотя и можно но не целесообразно строить программу с вложенными процедурами.
MAIN PROC FAR
.............
CALL P1
.............
JMP OBHOD
P1 PROC NEAR
; тело процедуры
P1 ENDP
OBHOD: .............
MAIN ENDP
2) Передача параметров через регистры.
Пусть процедура выполняет операцию: С = А + В
MOV AX,A
MOV BX,B
CALL PSUM
MOV C,AX
PSUM PROC NEAR
ADD AX,BX
RET
PSUM ENDP
Параметры процедуры делят на входные и выходные. В данном примере входные параметры: регистры AX и BX, выходные – регистр AX.
Данный способ является самым быстрым, однако не основным, т. к. регистров в МП не очень много.
3) Передача параметров через стек.
A¤-B¤-3
x = ────── A,B – слова
(A-B)*5
А,В – входные параметры
АХ – результат
В процедуре для промежуточных результатов обычно используются свободные регистры, например нам потребовались регистры AX,BX,CX,DX,SI. В процедуре все используемые регистры, кроме регистра, через который передаются параметры, целесообразнее сохранять на стек, т. к. эти же регистры могли быть использованы в вызывающей программе.
SP────┐ ┌────BP
├────┤
+0 │ SI │ ...........................
├────┤ PUSH A
+2 │ DX │ PUSH B
├────┤ CALL P2 ;вызов
+4 │ CX │ MOV X,AX ;процедуры
├────┤ ...........................
+6 │ BX │
├────┤
+8 │ IP │
├────┤
+10 │ A │
├────┤
+12 │ B │
├────┤
│ │
└────┘
P2 PROC NEAR
PUSH BX
PUSH CX
PUSH DX
PUSH SI
MOV BP,SP ;прямой доступ к стеку
MOV AX,[BP+12] ;AX:=A
MOV BX,[BP+10] ;BX:=B
;вычисление формулы
;результат в AX
;восстановление регистров
POP SI
POP DX
POP CX
POP BX
; после этих действий SP указывает на адрес возврата
RET 4
; команда RET с параметром работает аналогично обычной
; команде RET, т.е. выполняет операцию POP IP, одна-
; ко в стеке остаются 2 параметра А и В, которые необ-
; ходимо удалить со стека. Дополнительное действие
; команды состоит в следущем: SP := SP + 4.
; После выхода из процедуры SP будет указывать на
; ячейку, лежащую ниже А
P2 ENDP
Если не использовать параметры в команде RET, то вызов процедуры будет иметь вид:
PUSH A
PUSH B
CALL P2
MOV X,AX
; в стеке лишние 2 слова
POP AX
POP AX
В одномерном массиве поменять местами 1-й положительный и последний отрицательный.
┌───┬───┬───┬───┬───┬───┐
│ 0 │ 2 │ 4 │-8 │-16│ 3 │
└───┴───┴───┴───┴───┴───┘
SI = 0 – начальное значение
DI:= (N-1) size X
MOV CX,N
MOV SI,0
M1: CMP X[SI],0
JG M2
INC SI
INC SI
LOOP M1
GCXZ N_P_E ;переход, если CX = 0
;найден положительный элемент
MOV CX,N
MOV DI,N
DEC DI
SHL DI,1 ;DI:=DI*2
M4: CMP X[DI],0
JL M5
DEC DI
DEC DI
LOOP M4
M5: JCXZ N_NEG_E
MOV AX,[SI]
MOV BX,[DI]
MOV [SI],BX
MOV [DI],AX
JMP KON
N_P_E: LEA DX,MSG1
MOV AH,9
INT 21h
JMP KON
N_NEG_E: LEA DX,MSG2
MOV AH,9
INT 21h
KON: RET