汇编原理3:分析ah=4ah时的int 21h

        在汇编原理2:源代码开始的博客中,我们可以看到fasm源代码的最开始的地方有一个ah=4ah时的int 21h调用。本文章就来分析一下这个调用有什么作用。
我们先来看一个例子:

;使用masm5.0进行编译
;程序功能:没什么功能?
;注意:使用masm5.编译asm文件的时候,文件名长度不要超过8个字符,否则会无法打开文件.

assume cs:code,ds:data

data segment
msg		db 'I have a large buffer--32KB--ha!ha!',24h
buffer 	db 32768 dup (?)
data ends

code 	segment
start:	mov ax,data
		mov ds,ax
		
		mov ah,9
		mov dx,offset msg	;ah=9,ds:dx指向由美元标志($,对应于ASCII码24h)终止的字符串.
		int 21h				;将字符串输出给标准输出设备(STDOUT)
		
		mov ah,4ch
		int 21h	

code	ends
end start

        程序中我们使用db伪指令在数据段开辟了一个32KB的缓冲区,这个缓冲区可能会被程序使用。但是使用masm5.0编译后,我们发现,生成的exe文件居然有33344个字节那么大。但是这样编程这样会显著增加可执行文件的长度。如果这样的情况比较多,那么会生成很多比较大的exe文件,浪费磁盘空间。
如何解决这个问题呢?我们知道操作系统的一个重要特征就是可以对各种资源惊醒有效的管理。这个的资源指的是各种数据(文件)及系统安装的各类设备。毫无疑问内存也属于设备,它页应该受到操作系统很好的管理。
        DOS就具备管理内存的能力。应用程序可以通过系统功能调用向DOS申请一些内存,结束之前再通过系统功能把借来的内存还给DOS。从而可以不用db伪指令在数据段里定义缓冲区。
        int 21h的48H功能就是DOS提供的用于申请内存的功能调用。看下面这个例子:

;使用masm5.0进行编译
;程序功能:没什么功能?
;注意:使用masm5.编译asm文件的时候,文件名长度不要超过8个字符,否则会无法打开文件.
;此程序中,使用int 48h分配内存会失败。
assume cs:code,ds:data

data segment
msg		db 'I have a large buffer--32KB--ha!ha!',0dh,0ah,24h
err1	db 'memory control blocks are destroyed',0dh,0ah,24h
err2	db 'not enough memory',0dh,0ah,24h
data ends

code 	segment
start:	mov ax,data
		mov ds,ax
		
		mov ah,9
		mov dx,offset msg	;ah=9,ds:dx指向由美元标志($,对应于ASCII码24h)终止的字符串.
		int 21h				;将字符串输出给标准输出设备(STDOUT)
		
		mov ah,48h
		mov bx,10
		int 21h
		jnc exit		;如果分配成功,程序就退出
		cmp ax,07h
		je error1		
		cmp ax,08h
		je error2
		jmp exit
		
error1:	mov ax,data
		mov ds,ax
		mov ah,9
		mov dx,offset err1
		int 21h
		jmp exit
		
error2:	mov ax,data
		mov ds,ax
		mov ah,9
		mov dx,offset err2
		int 21h
		
exit:	mov ah,4ch
		int 21h	

code	ends
end start
;48H功能就是DOS提供的用于申请内存的功能调用:    
;功能号:48H
;用 途:向DOS申请一定量连续内存空间
;参 数:AH=48H
;    BX=申请内存的"节"数,每一节是16个字节
;调 用:INT 21H
;返 回:如果成功,则CF清零,AX=申请到的内存块段地址
;    如果失败,则CF置1,AX=错误代码,BX=当前内存最大可用块的大小
;    AX=07H 内存控制块被破坏
;      08H 内存不够  
;注意:一"节"内存包含16个连续的BYTE,但这16个BYTE的起始地址必须是16的整数倍。比如从0B800H:0000H处开
;      始的16个BYTE可以看作是一节,而从0B800H:0001H处开始的16个字节就不是一节。
;      如果这个功能正确地执行了,则DOS将通过AX寄存器返回这块内存的段地址,偏移地址就是0。

        这个程序中,理想情况下,通过调用int 21h的48h功能,我们可以获得256个字节的内存。但是通过运行程序,我们可以发现,程序提示:not enough memory。这是怎么一回事呢?难道DOS真的连256个字节的空闲内存也没有了吗?
        程序本身并没有什么问题。问题出在DOS身上,因为它太“懒惰”。大家都知道用户程序的长度是不确定的。长的有几百KB,短的可能只有几个Byte。按理说DOS在调入一个程序时应该先确定这个程序的长度。然后再按程序的长度给它分配内存,但是DOS并没有这么做。无论程序有多么长,它都是一股脑的把所有的自由内存都分给这个程序。所以系统虽然具有几倍KB的自由内存,但是当某程序调入内存运行时,这几百KB的自由内存都成了它的“私有财产”,所以当它再次申请内存时DOS已经没有空闲内存了。因此我们调用int 21h的48h功能会失败。
        因此我们说,当一个应用程序在运行时,如果想要申请内存,应该首先按照自己需要的实际长度把DOS给它的内存给重新分配一下,自己占了多少得救保留多少,自己不占用的内存就要“无私奉献”出来。这样才能想DOS申请内存,这就是所谓的“索取”之前先要“奉献”。
        DOS提供了一个专门用于重新分配内存的功能,这就是我们开始提到的int 21h的48h号功能。看下面这个例子:

;使用masm5.0进行编译
;程序功能:没什么功能?
;注意:使用masm5.编译asm文件的时候,文件名长度不要超过8个字符,否则会无法打开文件.
;此程序中,使用int 48h分配内存会失败。
assume cs:code,ds:data

data segment
msg		db 'reallocate memory failed',0dh,0ah,24h
err1	db 'memory control blocks are destroyed',0dh,0ah,24h
err2	db 'not enough memory',0dh,0ah,24h
data ends

code 	segment
start:			

		mov ah,4ah
		mov bx,800h		;32k
		int 21h			;重新分配本程序占用的内存

		jnc next

		mov ax,data
		mov ds,ax
		mov ah,9
		mov dx,offset msg	;ah=9,ds:dx指向由美元标志($,对应于ASCII码24h)终止的字符串.
		int 21h				;将字符串输出给标准输出设备(STDOUT)

		jmp exit
		
next:	mov ah,48h
		mov bx,9000h		;576k
		int 21h
		jnc exit		;如果分配成功,程序就退出
		cmp ax,07h
		je error1		
		cmp ax,08h
		je error2
		jmp exit
		
error1:	mov ax,data
		mov ds,ax
		mov ah,9
		mov dx,offset err1
		int 21h
		jmp exit
		
error2:	mov ax,data
		mov ds,ax
		mov ah,9
		mov dx,offset err2
		int 21h
		
exit:	mov ah,4ch
		int 21h	

code	ends
end start

;48H功能就是DOS提供的用于申请内存的功能调用:    
;功能号:48H
;用 途:向DOS申请一定量连续内存空间
;参 数:AH=48H
;    BX=申请内存的"节"数,每一节是16个字节
;调 用:INT 21H
;返 回:如果成功,则CF清零,AX=申请到的内存块段地址
;    如果失败,则CF置1,AX=错误代码,BX=当前内存最大可用块的大小
;    AX=07H 内存控制块被破坏
;      08H 内存不够  
;注意:一"节"内存包含16个连续的BYTE,但这16个BYTE的起始地址必须是16的整数倍。比如从0B800H:0000H处开
;      始的16个BYTE可以看作是一节,而从0B800H:0001H处开始的16个字节就不是一节。
;      如果这个功能正确地执行了,则DOS将通过AX寄存器返回这块内存的段地址,偏移地址就是0

        这个例子中,我们在程序开始的地方调用int 21h的4ah功能给程序重新分配了32k的内存,然后后面调用int 21h的48h功能分配了576k的内存,也分配成功了。
        看到这里,大家应该明白了吧。fasm源代码的最开始的地方调用int 21h的4ah功能就是为了给程序重新分配内存空间。因为后面会调用int 21h的48h功能动态地向DOS申请内存,如果不在前面调用4ah功能重新分配内存,后面申请内存肯定会失败的。呵呵
参考:PC机汇编语言实战精解 第11章

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值