汇编笔记——函数

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也恢复了

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值