START后面的 MOV AX,DATAS MOV DS,
相当于左括号,MOV AH,4CH INT 21H
相当于右括号,一组括号算一个函数,还可以自定义别的函数
声明函数
name PROC ;函数名字为name
;函数内容
RET ;返回值
name ENDP ;函数结束标志
调用函数
CALL name
简单调用的例子:输出字符A
在代码段输入
CALL ABC
代码段后面输入
ABC PROC ;声明ABC 函数
MOV DL,'A'
MOV AH,2
INT 21H
RET
ABC ENDP
完整代码,可以复制去运行一下
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
CALL ABC ;调用ABC函数
MOV AH,4CH
INT 21H
ABC PROC ;声明ABC 函数
MOV DL,'A'
MOV AH,2
INT 21H
RET
ABC ENDP
CODES ENDS
END START
现在来看传参与返回值,emmmm,简单来说就是传参传的不明显,返回也返回的不明显,
先看传参,给AX一个数,以无符号十进制形式输出
函数如下:
;定义ABC函数
ABC PROC
MOV BH,0;记录压栈次数
MOV CL,10
L1:
ADD BH,1
DIV CL;AX/CL,商AL,余数AH
PUSH AX
MOV AH,0
CMP AL,0
JA L1
;全部压栈,开始输出
L2:
SUB BH,1
POP DX
MOV DL,DH
ADD DL,48
MOV AH,2
INT 21H
CMP BH,0
JA L2
RET
ABC ENDP
在 MOV AX,DATAS MOV DS,AX
后给AX赋值,调用ABC函数,会正确显示AX中的值,因为AX 是函数要的参数,为什么这么说呢?请注意:DIV CL;AX/CL,商AL,余数AH
如果多个几个寄存器赋值,像下面这样,依旧是值输出AX的值,所以传参传的啥需要自己记住,而且是牢记 隐约感觉到大作业的恐怖
DATAS SEGMENT
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
MOV BX,123
MOV CX,456
MOV AX,126
CALL ABC
MOV AH,4CH
INT 21H
ABC PROC
MOV BH,0;记录压栈次数
MOV CL,10
L1:
ADD BH,1
DIV CL;AX/CL,商AL,余数AH
PUSH AX
MOV AH,0
CMP AL,0
JA L1
;全部压栈,开始输出
L2:
SUB BH,1
POP DX
MOV DL,DH
ADD DL,48
MOV AH,2
INT 21H
CMP BH,0
JA L2
RET
ABC ENDP
CODES ENDS
END START
如果想多输出几个数,如下代码也是错的,因为函数里用到了BX,调函数的时候改变了BX的值;因为汇编直接改了对应地址的数据
MOV BX,123
MOV CX,456
MOV AX,126
CALL ABC
MOV AX,BX
CALL ABC
返回值基本和没有一样,需要自己牢记该函数的功能以及寄存器变成的样子,变了就是返回了
最后来个复杂一点的样例,结合汇编的“数组”,循环输入5个数字并输出
提示一下:输入可以写成一个函数,需要留意最后存到了哪里;输出可以写成另一个函数,需要记得第一步的结果存到了哪里
;函数
DATAS SEGMENT
;此处输入数据段代码
A1 WORD 1
A2 WORD 5 DUP(?)
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
MOV DI,5
MOV SI,OFFSET A2
L5:
CALL INPUT ;调用INPUT函数,输入数字并转成无符号十进制数
MOV [SI],AX ;存入内存
ADD SI,2 ;内存地址+1
SUB DI,1 ;还需循环次数-1
CMP DI,0 ;循环次数到5,停止循环
JA L5
L6:
SUB SI,2
MOV AX,[SI]
CALL OUTPUT ;调用OUTPUT函数,以无符号十进制数形式输出输入的数字
MOV DL,' '
MOV AH,2
INT 21H
ADD DI,1
CMP DI,5
JB L6
MOV AH,4CH
INT 21H
;--------------------------分隔线------------------------------;
;定义INPUT函数
INPUT PROC
MOV BX, 0
MOV CL, 10
MOV AH, 1
INT 21H
CMP AL, '0'
JB L3
CMP AL, '9'
JA L3
MOV BL, AL
SUB BL, 48
L4:
MOV AH, 1
INT 21H
CMP AL, '0'
JB L3
CMP AL, '9'
JA L3
MOV DL, AL
SUB DL, 48
MOV AL, BL
MOV CL, 10
MUL CL
MOV BX, AX
MOV DH, 0
ADD BX, DX
JMP L4
L3:
MOV AX, BX
RET
INPUT ENDP
;--------------------------分隔线------------------------------;
;定义OUTPUT函数
OUTPUT PROC
MOV BH,0;记录压栈次数
MOV CL,10
L1:
ADD BH,1
DIV CL;AX/CL,商AL,余数AH
PUSH AX
MOV AH,0
CMP AL,0
JA L1
;全部压栈,开始输出
L2:
SUB BH,1
POP DX
MOV DL,DH
ADD DL,48
MOV AH,2
INT 21H
CMP BH,0
JA L2
RET
OUTPUT ENDP
CODES ENDS
END START
这样两个函数调用起来,都感觉到记住寄存器中数据有点难了,如果再多几个函数更乱,所以这里就需要想办法让寄存器调函数前后数据不变(除有出口参数的情况)。我们可以用堆栈解决,在函数开始时,将用到的寄存器数据压栈,函数结束时,寄存器数据出栈回到各个寄存器。上面的代码加工一下,就是这个样子:
;函数
DATAS SEGMENT
;此处输入数据段代码
A1 WORD 1
A2 WORD 5 DUP(?)
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
MOV DI,5
MOV SI,OFFSET A2
L5:
CALL INPUT ;调用INPUT函数,输入数字并转成无符号十进制数
MOV [SI],AX ;存入内存
ADD SI,2 ;内存地址+1
SUB DI,1 ;还需循环次数-1
CMP DI,0 ;循环次数到5,停止循环
JA L5
L6:
SUB SI,2
MOV AX,[SI]
CALL OUTPUT ;调用OUTPUT函数,以无符号十进制数形式输出输入的数字
MOV DL,' '
MOV AH,2
INT 21H
ADD DI,1
CMP DI,5
JB L6
MOV AH,4CH
INT 21H
;--------------------------分隔线------------------------------;
;定义INPUT函数
INPUT PROC
PUSH BX
PUSH CX
PUSH DX
MOV BX, 0
MOV CL, 10
MOV AH, 1
INT 21H
CMP AL, '0'
JB L3
CMP AL, '9'
JA L3
MOV BL, AL
SUB BL, 48
L4:
MOV AH, 1
INT 21H
CMP AL, '0'
JB L3
CMP AL, '9'
JA L3
MOV DL, AL
SUB DL, 48
MOV AL, BL
MOV CL, 10
MUL CL
MOV BX, AX
MOV DH, 0
ADD BX, DX
JMP L4
L3:
MOV AX, BX
POP DX
POP CX
POP BX
RET
INPUT ENDP
;--------------------------分隔线------------------------------;
;定义OUTPUT函数
OUTPUT PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV BH,0;记录压栈次数
MOV CL,10
L1:
ADD BH,1
DIV CL;AX/CL,商AL,余数AH
PUSH AX
MOV AH,0
CMP AL,0
JA L1
;全部压栈,开始输出
L2:
SUB BH,1
POP DX
MOV DL,DH
ADD DL,48
MOV AH,2
INT 21H
CMP BH,0
JA L2
POP DX
POP CX
POP BX
POP AX
RET
OUTPUT ENDP
CODES ENDS
END START
注意:INPUT函数有出口参数AX,恢复数据的时候别给AX也恢复了