汇编语言练习-实模式下的汇编

在MS-DOS下,没有保护模式与32位寄存器,程序可以直接调用BIOS中断,虽然DOS系统已经离我们远去,但是Intel CPU进入保护模式之前需在实模式下进行设置和跳转,所以实模式编程仍然具有一定的意义,在本篇中不介绍纯DOS环境下的MASM,仅仅利用 Windows的虚拟8086模式编程,虚拟8086是Intel为了兼容实模式程序推出的,此模式可以让用户程序在32位系统上进行16位操作,模拟了 8086处理器。

在16位实模式下,由于寻址空间的限制,必须把内存划分为多个段,如果单纯的使用一个offset,由于16位的操作数,最多能寻址 64k 的地址空间,但8086 cpu的数据总线有20位,也就是能够寻址1M的地址,所以intel处理器想出了 seg:offset 的方式,去寻址,首先由seg段寄存器定位一个地址,再此地址上进行偏移,具体计算 seg * 16 + offset ,如此便可达到20位的寻址。所以在实模式下编程,还需要注意段寄存器,在寻址之前要看使用的段。

还有一个问题是编译最后的格式,之前在windows保护模式下,编译最后都是windows可执行文件PE格式,这显然是不能在实模式下运行的,所以还需要把我们的程序编译成能够在实模式下运行的文件。

在MS-DOS下支持一种COM二进制执行文件,COM格式是纯二进制代码,系统加载时把此文件加载至100h内存处。现来写一个简单的COM程序框架:

.model tiny
.code
org 100h

main proc
	mov ah, 2
	mov dl, 'A'
	int 21h
die:
	jmp die
	ret
main endp
end main

代码开始首先使用.model设置当前内存模式是tiny,而非之前的flat模式,然后再代码开始的地方使用org伪指令指定程序将要载入内存的位置,这里设置段基址时有用,如果设置错误将会找不到定义的数据字符。

接下来使用了int 21h,int 21h是DOS调用,DOS调用相比BIOS调用就方便的多了:

首先把功能号存储于AH寄存器 
把参数传入指定寄存器
int 21h 

这里使用功能号2,输出一个字符,DOS调用的其他功能网上有大量教程,而且DOS调用至今或许也没太大价值,这里便不再叙述。

最后再来看如何编译我们的程序:

ml /c 16bit.asm
link16 /TINY 16bit.obj

这里的连接程序使用了link16处理16位程序,之后双击16bit.com,便可看到控制台窗口输出字符A,程序进入死循环。

当然,可以利用刚才所述内从结合上篇BIOS视频控制来制作系统的引导程序,仅仅需要再程序之后填充至512字节并且以 55AA结尾便可,这里列举一下填充部分代码:

fill db (510 - (fill - main)) dup (0)
db 55h
db 0AAh

这里进行了一次计算,fill为当前位置,减去程序开始地址,即到当前所用去的字节数,再被510减,得到需要填充的字节数,用0补足,最后在定义 55AA 标志字即可,当然DOS调用是无法使用的,需要替换成BIOS调用。

关于AT&T实模式编程,可参考后面的BIOS模式下的汇编编程

Built with Hugo
主题 StackJimmy 设计