我是如何学习Java的~直接定址和子程序调用

14 篇文章 0 订阅
14 篇文章 0 订阅

在汇编源程序中,我们一般会使用标号来指明某段功能代码的开始地址,同样,我们也可以使用标号来表示我们定义的数据开始的偏移地址,如下:

assume cs:code

code segment

	;标号a,b指明两段数据开始的偏移地址
	a: db 1,2,3,4,5,6,7,8
	b: db 8 dup(0)

	start:
	
		mov ax, cs
		mov ds, ax
		mov es, ax
		
		;获取标号a,b的偏移地址
		mov si, offset a
		mov di, offset b
		
		;把标号a开始的数据传送到标号b开始的内存单元处
		mov cx, 8
		rep movsb
		
		mov ax, 4c00h
		int 21h
code ends

end start

同时,对于数据来说,有些是字节型,有些是字型,上述程序中定义的标号只能表示数据开始的偏移地址,无法表示该处的数据类型,汇编中提供了以下方式使用标号既可以表示偏移地址,也可以表示数据单元的类型:

assume cs:code

code segment

	;标号a,b指明两段数据开始的偏移地址和数据类型
	a db 1,2,3,4,5,6,7,8
	b db 8 dup(0)
	c db 8 dup(0)

	start:
	
		mov ax, cs
		mov ds, ax
		mov es, ax
		
		;获取标号a,b的偏移地址
		mov si, offset a
		mov di, offset b
		
		;把标号a开始的数据传送到标号b开始的内存单元处
		mov cx, 8
		rep movsb

		;也可以使用以下方法来把a处的数据传送到c处
		mov cx, 8
		mov si, 0
	s:
		;此处a[si]相当于cs:[a + si], c[si]相当于cs:[c + si]
		;即表示了单元地址,同时也表示了该数值为字节型
		mov al, a[si]
		mov c[si], al
		inc si
		loop s
		
		mov ax, 4c00h
		int 21h
code ends

end start

通过 debug 查看 b,c 处都写入了 a 处开始的数据:
代码段数据区的直接定址
通过以上程序,我们可以发现,对于标号a、b、c的使用并没有冒号,这个时候,a、b、c就有了两个含义,一个是偏移地址,一个是所定义数据的类型,所以也就代表了一个内存单元。我们可以通过以下方式来访问内存单元:

a	;相当于cs:[a],即cs:[0]
b[1];相当于cs:[b + 1],即cs:[10H + 1]

之所以段寄存器是用 cs,是因为该数据是在 code 段中定义,而 cs:code 把 code 段和 cs关联。所以,当我们使用此功能时,需要把标号所在的段和段寄存器进行关联,如,在数据段中定义:

assume cs:code, es:data	;data段需要和某一段寄存器关联

data segment
	;标号a,b指明两段数据开始的偏移地址和数据类型-字节
	a db 1,2,3,4,5,6,7,8
	b db 8 dup(0)
data ends

code segment
	start:
	
		mov ax, data
		mov es, ax

		mov cx, 8
		mov si, 0
	s:
		;此处a[si]相当于es:[a + si], c[si]相当于es:[c + si],代表一个字节单元
		mov al, a[si]
		mov b[si], al
		inc si
		loop s
		
		mov ax, 4c00h
		int 21h
code ends

end start

通过debug运行可以看到:

刚装载运行时,可以查看定义的内存单元数据:
刚装载运行时
当执行到循环处时,可以看到段寄存器为关联的 ES :
执行到循环处时
结束后查看数据的内存单元:
结束后内存单元数据
上述定义和使用标号的方式,称之为直接定址,通过该种方式,可以很方便的操作内存单元。

另外,对于db、dw等定义数据的指令,也可以使用标号,把标号的偏移地址定义到内存中:

assume cs:code, es:data

data segment
	a dw exit
data ends

code segment
	start:
	
		mov ax, data
		mov es, ax

		mov ax, a
		mov bx, offset exit
		
	exit:
		mov ax, 4c00h
		int 21h
code ends

end start

通过debug可以看到,ax 和 bx 存放了标号 exit 处的偏移地址:
定义偏移地址
通过上面的方式,我们可以很轻易的定义多个子程序并进行调用,如:
提供以下功能:

  1. 设置屏幕的背景色(按 0 键)
  2. 设置屏幕字体颜色(按 1 键)

代码如下:

assume cs:code, es:data

;存放子程序的偏移地址
data segment
	function dw backgroup, color
data ends

code segment
	start:
		mov ax, data
		mov es, ax
		
		mov dh, 00000000B
		mov dl, 00000000B
		
	key:
		
		;读取键盘输入,当输入0时,改变背景色,当输入1时,改变字体颜色
		mov ah, 0
		int 16h
		
		;回车键的扫描码为1CH
		cmp ah, 1ch
		je exit;回车时退出
		
		;0~9的ASCII码为30H~39H
		;输入的不是0或1时,循环输入
		cmp al, 31H
		ja key
		cmp al, 30H
		jb key
		;输入的时0或1时,调用子程序
		sub al, 30H
		mov ah, 0
		mov bx, ax
		add bx, bx
		call function[bx]
		
		;继续键盘输入
		jmp key
		
	;改变背景色	
	backgroup:
		mov ax, 0b800h
		mov ds, ax
		mov si, 1
		mov cx, 2000
		
		add dh, 00010000B
		and dh, 01110000B
	s: 
		mov byte ptr ds:[si], dh
		add si, 2
		loop s
		ret
	
	;改变字体颜色
	color:
		mov ax, 0b800h
		mov ds, ax
		mov si, 1
		mov cx, 2000
		
		add dl, 00000001B
		and dl, 00000111B
	s1: 
		mov byte ptr ds:[si], dl
		add si, 2
		loop s1
		ret
		
	exit:
		mov ax, 4c00h
		int 21h
code ends

end start

编译链接文件后,通过 dosbox 直接运行 exe 文件,输入0或1键即可看到相应的功能效果:
背景和颜色转换

当子功能较多时,根据这种方法可以实现灵活的程序调用,同时又便于我们功能的扩充,如果加入一个新的功能子程序,只需要在地址表function中添加他的入口地址即可。

目录
上一章
下一章

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值