又用ASM做了个加法

太可怕了……是我想多了吗……

; by forest93, 2013

data SEGMENT
	;提示字符串
	prompt DB "[Input 2 UInt16]请输入两个整数,以换行符分隔。$"
	promptAdd DB "a + b = $"
	promptInc DB "a + 1 = $"
	promptSub DB "a - b = $"
	;输入/输出缓冲区
	outBuffer DB 255 dup (0)
	inputBufferLength DB 255
	inputLength DB 0
	inputBuffer DB 255 dup (0)
	dosInputBuffer = inputBufferLength
data ENDS

code SEGMENT
	ASSUME DS:data
	Main PROC
		MOV AX, data
		MOV DS, AX
		
		;cout << prompt
		PUSH OFFSET prompt
		CALL OutputString
		
		;输入第一个数 --> bx
		CALL InputInt
		CALL Endl
		MOV BX, AX
		;输入第二个数 --> cx(ax)
		CALL InputInt
		CALL Endl
		MOV CX, AX
		
		ADD AX, BX
		PUSH OFFSET promptAdd	;a + b
		CALL OutputString
		PUSH AX
		CALL OutputInt
		CALL Endl
		
		MOV AX, BX
		INC AX
		PUSH OFFSET promptInc	;a + 1
		CALL OutputString
		PUSH AX
		CALL OutputInt
		CALL Endl
				
		MOV AX, BX
		SUB AX, CX
		PUSH OFFSET promptSub	;a - b
		CALL OutputString
		PUSH AX
		CALL OutputInt
		CALL Endl
		
		MOV AX, 4C05h			;DOS 返回值 05H
		INT 21h
	Main ENDP
	
	;向控制台输出一个字符串
	OutputString PROC NEAR
					;__stdcall uint16 (uint16 buffer)
					; LoMem
					;DX	 <- SP
					;BP
					;AX
					;IP
					;buffer
					; HiMem
		PUSH AX
		PUSH BP
		PUSH DX
		
		MOV BP, SP
		MOV DX, [BP+8]
		MOV AH, 09h
		INT 21h
		
		POP DX
		POP BP
		POP AX
		RET 2
	OutputString ENDP
	
	;向控制台输出一个换行符
	Endl PROC NEAR
		PUSH AX
		PUSH DX
		
		MOV AH, 2
		MOV DL, 0DH
		INT 21h
		MOV DL, 0AH
		INT 21h
		
		POP DX
		POP AX
		RET
	Endl ENDP
	
	;从控制台输入一个整数
	InputInt PROC NEAR
					;__stdcall uint16()
		PUSH BX
		
		;输入数字字符串
		LEA DX, dosInputBuffer
		MOV AH, 0AH
		INT 21h
		
		MOV BL, inputLength
		MOV BH, 0
		MOV inputBuffer[BX], '$'	;设置字符串结束标识
		;将字符串转换为整数
		PUSH OFFSET inputBuffer
		CALL Str2Int
		
		POP BX
		RET
	InputInt ENDP
	
	;向控制台输出一个整数
	OutputInt PROC NEAR
					;__stdcall uint16 (uint16 num)
					; LoMem
					;DX	 <- SP
					;BP
					;AX
					;IP
					;num
					; HiMem
		PUSH AX
		PUSH BP
		PUSH DX
		
		MOV BP, SP
		PUSH OFFSET outBuffer
		PUSH [BP+8]		;num
		CALL Int2Str
		
		LEA DX, outBuffer
		MOV AH, 09h
		INT 21h
		
		POP DX
		POP BP
		POP AX
		RET 2
	OutputInt ENDP
	
	;将文本转换为数字
	Str2Int PROC NEAR
					;__stdcall uint16 (char DS:* buffer)
					; LoMem
					;DX	 <- SP
					;CX
					;BX
					;IP
					;buffer
					; HiMem
		PUSH BX
		PUSH CX
		PUSH DX
		
		MOV BX, SP
		MOV BX, SS:[BX+8]	;buffer
		
		MOV AX, 0
		;乘10,然后加上当前位
	Mul10:
		MOV CX, 10
		MUL CX
		MOV CL, [BX]	;换一个寄存器操作,避免引起 AX 溢出
		SUB CL, '0'
		ADD AX, CX
		INC BX
		CMP [BX], '$'
		JNE Mul10
		
		POP DX
		POP CX
		POP BX
		RET 2			;返回值在 AX 里面
	Str2Int ENDP
	
	;将数字转换为文本
	Int2Str PROC NEAR
					;__stdcall (uint16 num, char DS:* buffer)
					;参数从右往左压入堆栈
					; LoMem
					;DX	 <- SP
					;CX
					;BX
					;AX
					;IP
					;num
					;buffer
					; HiMem
		PUSH AX
		PUSH BX
		PUSH CX
		PUSH DX
		
		MOV BX, SP
		MOV AX, SS:[BX+10]  ;num
		MOV BX, SS:[BX+12]  ;buffer
		;试除10,以确定数字位数
		MOV CX, 10
		PUSH AX
	TestDiv10:
		MOV DX, 0
		DIV CX
		INC BX
		CMP AX, 0
		JNZ TestDiv10
		
		MOV [BX], '$'   ;加入结束标识
		;除10求余
		POP AX
	Div10:
		MOV DX, 0	;or XOR DX, DX
		DIV CX
		ADD DL, '0'	;or ADD DL, 30H
		DEC BX		;从右向左移动指针
		MOV [BX], DL
		CMP AX, 0
		JNZ Div10
		
		POP DX
		POP CX
		POP BX
		POP AX
		RET 4
	Int2Str ENDP	
code ENDS

END main

使用 EMU8086 完成编写和调试。

使用 EMU8086 编写和调试 x86 汇编。

然而很明显,编译器/解释器不支持中文字符……

使用 VirtualBox + MS-DOS 运行编译后的汇编程序。

我们需要解决方案!

只能强行插字节码了……

	prompt DB 0C7H,0EBH,0CAH,0E4H,0C8H,0EBH,0C1H,0BDH,0B8H,0F6H,0D5H,0FBH,0CAH,0FDH,0A3H,0ACH,0D2H,0D4H,0BBH,0BBH,0D0H,0D0H,0B7H,0FBH,0B7H,0D6H,0B8H,0F4H,0A1H,0A3H,"$"

在 MS-DOS 中运行中文字符系统后,终于出来了:

使用字节表示中文字符串后,在 PDOS95 下终于可以显示中文了。

总之,多少有点儿蛋疼。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

ERROR: si-captcha.php plugin: GD image support not detected in PHP!

Contact your web host and ask them to enable GD image support for PHP.

ERROR: si-captcha.php plugin: imagepng function not detected in PHP!

Contact your web host and ask them to enable imagepng for PHP.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

Content is available under CC BY-SA 3.0 unless otherwise noted.