X86学习笔记P4--函数表

之前已经完成了X86的基本编程与串操作编程,此次作业是完成完成X86函数的初步调用,并完成一个函数指针数组,使用函数表进行相关的函数调用。

一、进制转换与乘除运算

此次完成一个集合程序,将十六进制转为十进制,十进制转十六进制,二进制转十进制和乘除运算作为函数可供主程序循环调用,并将这些子程序集合在一个函数指针数组内。

这些函数都不难完成,现在只需要在数据段中进行设置即可将他们映射到函数表里

首先需要在数据段中生命相关空间,5各函数指针使用5个32位DW存储即可

STACK			SEGMENT	PARA	STACK
STACK_AREA		DW		100H	DUP(?)
STACK_BTM		EQU		$	-	STACK_AREA
STACK			ENDS

DATA			SEGMENT	PARA
FUNCTAB			DW		5 DUP(0)
TABLEN			DB		0		
SELECT_MSG		DB		'SELECT FUNCTION: 0 EXIT 1 HEC2DEC 2 DEC2HEC 3 BIN2DEC 4 MUL 5 DIV$'	
NEWLINE			DB		0DH,0AH,'$'
DATA			ENDS

之后需要考虑如何将这些子函数与数组对应,只需要将这些函数的有效地址存到数组即可

MOV       FUNCTAB:OFFSET,OFFSET    FUNCION
按照这样的思路,就可以存储函数指针和循环调用函数指针的设计:
MAIN			PROC	FAR
				MOV		AX,DATA
				MOV		DS,AX
				MOV		ES,AX
				MOV		AX,STACK
				MOV		SS,AX
				MOV		SP,STACK_BTM

				MOV		SI,OFFSET	FUNCTAB				;初始化函数表
				MOV		BX,OFFSET	FUNCTION_HEX2DEC
				MOV		[SI],BX
				INC		TABLEN
				MOV		BX,OFFSET	FUNCTION_DEC2HEX
				MOV		[SI + 2],BX
				INC		TABLEN
				MOV		BX,OFFSET	FUNCTION_BIN2DEC
				MOV 	        [SI + 4],BX
				INC		TABLEN
				MOV		BX,OFFSET	FUNCTION_MULT
				MOV 	        [SI + 6],BX
				INC		TABLEN				
				MOV		BX,OFFSET	FUNCTION_DIV
				MOV 	        [SI + 8],BX
				INC		TABLEN		

				PUSH	        SI

MAIN_LOOP:		
				LEA		DX,SELECT_MSG
				MOV		AH,09H
				INT		21H
				PRINT_LINE

				MOV 		AH,1
				INT		21H	
				SUB		AL,'0'
				XOR		AH,AH
				
				CMP		AX,0
				JZ		EXIT

				DEC		AX

				MOV		BX,AX
				SHL		BX,1 		;BX X 2
				PRINT_LINE
				CALL		[SI + BX]	

				PRINT_LINE
				JMP			MAIN_LOOP


EXIT:			        MOV		AX,4C00H
				INT		21H

MAIN			ENDP


那么现在只需要补充我们想要的相关函数即可,由于前几次已经完成了类似的设计,这一部分还是比较轻松的

首先是读取一个16进制数到AX中,因为对于16进制,读取高位数字仅仅左移操作即可完成,仅需要做一些ASCII码到数值的转换即可。ANS = (ANS << 4) + C

READ_HEX		PROC		;读16进制数到AX
				PUSH		        SI
				MOV			SI,0
READ_HEX_LP1:
				MOV 		        AH,1
				INT			21H
				CMP 		        AL,0DH        ;判断是否位回车
				JE 			READ_HEX_RETURN

				CMP			AL,'9'
				JA			READ_HEX_L2
READ_HEX_L1:				
				XOR			AH,AH
				SUB			AX,30H
				SAL			SI,4
				ADD			SI,AX
				JMP			READ_HEX_LP1
READ_HEX_L2:	
				XOR			AH,AH
				SUB			AX,'A' - 10
				SAL			SI,4
				ADD			SI,AX
				JMP			READ_HEX_LP1
READ_HEX_RETURN:
				MOV			AX,SI
				POP			SI
				RET
READ_HEX		ENDP


类比于读取16进制,完成读取二进制,读取一位后将ANS左移一位再加刚刚读取的数值即可

读取十进制,不能用移位来实现,使用乘法也不难完成

READ_BIN		PROC
				PUSH		        SI
				MOV			SI,0
READ_BIN_LP1:
				MOV 		        AH,1
				INT			21H
				CMP 		        AL,0DH
				JE 			READ_BIN_RETURN
				SHL			SI,1
				CMP 		        AL,'0'
				JZ			READ_BIN_LP1			;读数为0直接下一次循环
				INC			SI
				JMP			READ_BIN_LP1
READ_BIN_RETURN:
				MOV			AX,SI
				POP			SI
				RET
READ_BIN		ENDP


READ_DEC		PROC		;读十进制数到AX
				PUSH		        SI
				PUSH		        DX
				PUSH		        BX


				MOV			SI,0
				MOV			BX,10
READ_DEC_LP1:
				MOV 		        AH,1
				INT			21H
				CMP 		        AL,0DH
				JE 			READ_DEC_RETURN
				CMP 		        AL,30H
				JB 			READ_DEC_LP1
				CMP 		        AL,39H
				JA 			READ_DEC_LP1
				SUB 		        AL,30H
				XOR 		        AH,AH
				PUSH		        AX
				MOV		    	AX,SI
				MUL			BX
				MOV			SI,AX
				POP			AX
				ADD			SI,AX
				LOOP		        READ_DEC_LP1
READ_DEC_RETURN:
				MOV			AX,SI
				POP			BX
				POP			DX
				POP			SI
				RET
READ_DEC		ENDP


接下来考虑如何将16进制数AX转换成各种进制输出。

对于十进制,可以考虑整除10^N来得出商和余数来完成,对于而十六进制,只需要每次读取最高4位显示即可

根据以上思路得出相关代码

DISP_NUM		MACRO		;宏定义,输出十进制ASCII码
				PUSH		DX
				MOV			AH,2
				MOV			DL,AL
				ADD			DL,30H
				INT			21H
				POP			DX
DISP_NUM		ENDM


DIVIDE			MACRO		WNUM1,WNUM2
				MOV			AX,WNUM1
				MOV			BX,WNUM2
				XOR			DX,DX
				DIV 		        BX
DIVIDE			ENDM   


DISP_DEX		PROC			;显示AX十进制数
				PUSH		DX
				PUSH		AX
				XOR			DX,DX
				DIVIDE		AX,10000
				DISP_NUM				;	商在AX中,余数在DX中
				DIVIDE		DX,1000
				DISP_NUM
				DIVIDE		DX,100
				DISP_NUM
				DIVIDE		DX,10
				DISP_NUM
				MOV			AL,DL
				DISP_NUM	
				POP			AX
				POP			DX
				RET
DISP_DEX		ENDP
				

DISP_HEX		PROC			;显示16进制形式输出AX,32位二进制数同理
				
				MOV			BX,AX
				MOV			CX,4
DISP_HEX_LP1:
				PUSH		CX
				MOV			CL,4
				ROL			BX,CL
				MOV			AL,BL
				AND			AL,0FH
				ADD 		AL,30H
				CMP			AL,39H
				JBE			DISP_HEX_DIS
				ADD			AL,'A' - '9' - 1

DISP_HEX_DIS:	MOV			DL,AL
				MOV			AH,2
				INT			21H
				POP			CX
				LOOP		DISP_HEX_LP1

				RET
DISP_HEX		ENDP


最后补上乘除操作和集合的代码块,得到我们想要的结果

FUNCTION_DEC2HEX	PROC
				CALL		READ_DEC
				PRINT_LINE
				CALL		DISP_HEX
				RET
FUNCTION_DEC2HEX	ENDP

FUNCTION_HEX2DEC	PROC
				CALL		READ_HEX
				PRINT_LINE
				CALL		DISP_DEX
				RET
FUNCTION_HEX2DEC	ENDP

FUNCTION_BIN2DEC	PROC
				CALL		READ_BIN
				PRINT_LINE
				CALL		DISP_DEX
				RET
FUNCTION_BIN2DEC	ENDP

FUNCTION_MULT	PROC
				CALL		READ_HEX
				MOV			DX,AX
				CALL		READ_HEX
				MUL 		DX
				XCHG		DX,AX
				CALL		DISP_HEX
				XCHG		DX,AX
				CALL		DISP_HEX
				RET
FUNCTION_MULT	ENDP

FUNCTION_DIV	PROC
				CALL		READ_HEX
				MOV			DX,AX
				CALL		READ_HEX
				XCHG		DX,AX
				DIV 		DX
				XCHG		DX,AX
				CALL		DISP_HEX
				XCHG		DX,AX
				CALL		DISP_HEX				
				RET
FUNCTION_DIV	ENDP


进行测试


通过

二、串相关操作集合程序

既然已经将一些数值运算集合到了一个程序中,不妨将P3部分中完成的串操作做一次集合

运行结果如下


则将字符串查找与替换、字符串的排序集合到一个程序中,之前已经完成了大部分工作,细数现在需要做的工作

1、完成函数映射的框架

2、因为需要循环调用,需要完成一个字符串的输入函数

首先完成框架设计

STACK			SEGMENT	PARA	STACK
STACK_AREA		DW		100H	DUP(?)
STACK_BTM		EQU		$	-	STACK_AREA
STACK			ENDS

DATA			SEGMENT	PARA
FUNCTAB			DW		5 DUP(0)
TABLEN			DB		0		
SELECT_MSG		DB		'SELECT FUNCTION: 0 EXIT 1 SORT 2 REPLACE$'	
NEWLINE			DB		0DH,0AH,'$'
TR_BUFF			DB		200H	DUP(0)		;缓冲区
STR_NUM			DW		0
STR_LEN			Dw		0
STR_CPY			DB		20H 	DUP(0)		;备份区域
CMP_FLAG		DW		0
STR_ARR			DW		0FFH 	DUP(0)

DST 			DB 		100 	DUP(0)
DST_LEN			DW 		0
SEL 			DB 		100 	DUP(0)
DST 			DW 		0

DATA			ENDS

CODE			SEGMENT		PARA
				ASSUME		DS:DATA,CS:DATA,SS:STACK,ES:DATA 


MAIN			PROC	FAR
				MOV		AX,DATA
				MOV		DS,AX
				MOV		ES,AX
				MOV		AX,STACK
				MOV		SS,AX
				MOV		SP,STACK_BTM

				MOV		SI,OFFSET	FUNCTAB				;初始化函数表
				MOV		BX,OFFSET	FUNCTION_SORT
				MOV		[SI],BX
				INC		TABLEN
				MOV		BX,OFFSET	FUNCTION_REPLACE
				MOV		[SI + 2],BX
				INC		TABLEN
				MOV		BX,OFFSET	FUNCTION_UPPER
				MOV 	[SI + 4],BX
				INC		TABLEN

				PUSH	SI

MAIN_LOOP:		
				LEA		DX,SELECT_MSG
				MOV		AH,09H
				INT		21H
				PRINT_LINE

				MOV 		AH,1
				INT			21H	
				SUB			AL,'0'
				XOR			AH,AH
				
				CMP			AX,0
				JZ			EXIT

				DEC			AX

				MOV			BX,AX
				SHL			BX,1 		;BX X 2
				PRINT_LINE
				CALL		[SI + BX]	

				PRINT_LINE
				JMP			MAIN_LOOP


EXIT:			MOV		AX,4C00H
				INT		21H

MAIN			ENDP

CODE			ENDS
				END 		MAIN


再补充输入函数,功能为将字符串输入到SI 所指的空间中

SORT_RETURN:	
				RET
STR_SORT		ENDP 			

READ_STR		PROC
				PUSH	DX
				PUSH	CX

				MOV		SI,DI
				MOV		AH,0AH
				INT		21H
				XOR		CX,CX
				XOR		BX,BX
				CLD
READ_STR_LEN_LP1:							;统计字符串长度
				LODSB
				CMP 	AL,00H
				JZ		READ_STR_LEN_END
				INC		CX						;统计字符串长度	
				CMP		AL,' '
				JNZ		SHORT READ_STR_LEN_LP1			;统计空格的次数,即单词数量
				INC		BX

				PUSH	BX
				SHL		BX,1
				ADD		BX,OFFSET	STR_ARR		;将每处的索引位置存入到STR_ARR中
				MOV		DS:[BX],SI
				POP		BX
				
				JMP		SHORT READ_STR_LEN_LP1

READ_STR_LEN_END:
				PUSH	SI				
				MOV		SI,OFFSET	STR_LEN
				MOV 	DS:[SI],CX 			;已经统计出输入字符串的长度
				MOV		SI,OFFSET	STR_NUM
				MOV 	DS:[SI],BX 			;已经统计出输入字符串的数量
				POP		SI
				POP 	CX
				POP		DX
				RET
READ_STR		ENDP

将之前做的串处理函数引入其中,完成

STR_SORT 		PROC
				
SORT_LP1:		
				MOV		SI, OFFSET	STR_BUFF
				MOV		CX, STR_NUM					;单词个数
				DEC		CX							;使用CX计数
				XOR		BX,BX						;BX为当前单词索引
				MOV		CMP_FLAG,0
SORT_LP2:	
				MOV		AX,BX
				SHL		AX,1
				MOV		SI,AX
				ADD		SI,OFFSET	STR_ARR
				MOV		DI,SI
				MOV		DX,[SI]
				MOV		SI,DX
				MOV		DX,[DI + 2]
				MOV		DI,DX					;DI SI为当前索引

				CALL	STRCMP						;比较两字符串
				JNZ		SORT_CONTINUE
				CALL 	CHG_STR
				MOV		CMP_FLAG,1					;设立FLAG表示已交换
SORT_CONTINUE:
				INC		BX
				LOOP	SORT_LP2
				MOV		AX,CMP_FLAG
				CMP 	AX, 1
				JZ		SORT_RETURN		
				JMP		SORT_LP1

SORT_RETURN:	
				RET
STR_SORT		ENDP 

FIND		PROC							;查找字符串
			PUSH		SI
			PUSH		DI

			MOV			DI,OFFSET	SEL

FIND_LP1:	
			CLD
			CMPSB
			JNZ			FIND_END		;找出不同

			MOV			BX,SEL_LEN		;匹配完成dst
			MOV			AX,OFFSET	SEL
			ADD			BX,AX
			CMP 		BX,DI
			MOV			AX,1
			JZ 			FIND_RET

			MOV			BX,SRC_LEN		;SRC的末尾
			CMP 		SI,BX
			JA			FIND_END

			JMP			FIND_LP1

FIND_END:	
			MOV			AX,0			;用AX做返回值
FIND_RET:
			POP			DI
			POP			SI
			RET
FIND		ENDP


TRANSLATE	PROC
			PUSH		SI
			PUSH		DI

			MOV 		AX,SEL_LEN
			MOV			BX,DST_LEN
			CMP 		AX,BX			;AX > BX 向前平移
			JA			TRAN_CLD

TRAN_STD:
			STD							;向后平移,向前复制
			ADD			AX,SI 			;AX为目的
			DEC			AX
			MOV			BX,AX
			MOV 		SI,(OFFSET SRC) + SRC_LEN - 1
			MOV			DI,SI
			SUB			DI,SEL_LEN
			ADD			DI,DST_LEN
TRAN_LOOP1:
			LODSB
			STOSB
			CMP 		SI,BX
			JA			TRAN_LOOP1
			JMP			TRAN_END

TRAN_CLD:								;向前平移,向后复制
			MOV 		DI,SI
			ADD 		DI,DST_LEN
			ADD			SI,SEL_LEN
			MOV 		BX,(OFFSET SRC) + SRC_LEN
			CLD
TRAN_LOOP2:
			LODSB
			STOSB
			CMP 		SI,BX
			JB			TRAN_LOOP2

TRAN_END:
			POP			DI
			POP			SI
			RET
TRANSLATE	ENDP

STRCPY		PROC
			PUSH		SI

			MOV			DI,SI
			MOV			SI,OFFSET DST			
			MOV			BX,(OFFSET DST) + DST_LEN
			CLD
CPY_LOOP:	LODSB
			STOSB
			CMP 		SI,BX
			JB			CPY_LOOP

			POP			SI
			RET
STRCPY		ENDP

REPLACE		PROC

			MOV			SI,OFFSET	SRC
			MOV			DI,OFFSET	SEL
REPLACE_LP1:
			XOR			AX,AX
			CALL		FIND
			INC			SI
			CMP 		AX,0
			JZ			REPLACE_LP1
			DEC			SI

			CALL		TRANSLATE
			CALL		STRCPY
REPLACE		ENDP


NEXT:递归调用与堆栈传参


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值