第2天 汇编语言学习与Makefile入门

进一步修改helloos.nas:

; hello-os
; TAB=4

		ORG		0x7c00			; 指明程序的装载地址

; 以下的记述用于标准FAT12格式的软盘

		JMP		entry
		DB		0x90
		DB		"HELLOIPL"		; 启动区的名称可以是任意的字符串
		DW		512				; 每个扇区(sector)的大小(必须为512字节)
		DB		1				; 簇(cluster)的大小(必须为1个扇区)
		DW		1				; FAT12的起始位置(一般从第一个扇区开始)
		DB		2				; FAT的个数(必须为2)
		DW		224				; 根目录的大小(一般设成224项)
		DW		2880			; 该磁盘的大小(必须是2880扇区)
		DB		0xf0			; 磁盘的种类(必须是0xf0)
		DW		9				; FAT的长度(必须是9扇区)
		DW		18				; 1个磁道(track)有几个扇区(必须是18)
		DW		2				; 磁头数(必须是2)
		DD		0				; 不使用分区,必须是0
		DD		2880			; 重写一次磁盘大小
		DB		0,0,0x29		; 意义不明,固定
		DD		0xffffffff		; (可能是)卷标号码
		DB		"HELLO-OS   "	; 磁盘的名称(11字节)
		DB		"FAT12   "		; 磁盘格式名称
		RESB	18				; 先空出18字节

; 程序核心

entry:
		MOV		AX,0			; 初始化寄存器
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX
		MOV		ES,AX

		MOV		SI,msg
putloop:
		MOV		AL,[SI]
		ADD		SI,1			; 给SI加1
		CMP		AL,0
		JE		fin
		MOV		AH,0x0e			; 显示一个文字
		MOV		BX,15			; 指定字符颜色
		INT		0x10			; 调用显卡BIOS
		JMP		putloop
fin:
		HLT						; 让CPU停止,等待指令
		JMP		fin				; 无限循环

msg:
		DB		0x0a, 0x0a		; 换行2次
		DB		"hello, world"
		DB		0x0a			; 换行
		DB		0

		RESB	0x7dfe-$		; 填写0x00,直到 0x7dfe

		DB		0x55, 0xaa

; 以下是启动区以外部分的输出

		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	4600
		DB		0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
		RESB	1469432

  • ORG指令——来源于英文“origin”,程序要从指定的这个地址开始,也就是要把程序装载到内存中的指定地址,这里指定的地址是0x7c00。

有了这条指令的话,美元符($)的含义 也随之变化,它不再是指输出文件的第几个字节,而是代表将要读入的内存地址。

  • JMP指令——相当于C语言的goto语句,来源于英文的jump,意思是“跳转”。
  • “entry:”——标签的声明,用于指定JMP指令的跳转目的地等。
  • MOV指令——相当于赋值,MOV的源和目的可以是寄存器、常数、内存地址,用方括号([ ])来表示内存地址,MOV指令有一个规则:源数据和目的数据位数必须相同。所以在源数据中可以省略数据大小(BYTE)等的描述。

CPU里有一种名为寄存器的存储电路,在机器语言中就相当于变量的功能。

  • AX——accumulator,累加寄存器
  • CX——counter,计数寄存器
  • DX——data,数据寄存器
  • BX——base,基址寄存器
  • SP——stack pointer,栈指针寄存器
  • BP——base pointer,基址指针寄存器
  • SI——source index,源变址寄存器
  • DI——destination index,目的变址寄存器

说明:

  1. 这些寄存器都是16位寄存器,可以存储16位的二进制数,不管使用哪一个,差不多都能进行同样的计算,但如果都用AX来进行各种运算的话,程序就可以写得很简洁。“简洁”是指“用机器语言写程序”的情况,从汇编语言的源代码上是看不到这些区别的。
  2. 其中"X"表示扩展(extend)的意思,之所以说是扩展,是因为之前寄存器都是8位的,现在变成了16位。另外这几个寄存器不是按照字母排序的,是按照机器语言中寄存器的编号顺序排序的。
  3. 这8个寄存器全部只有16个字节(16bit*8/8),也就是说CPU最多只能存储16个字节

另外,CPU中还有8个8位寄存器:

  • AL——累加寄存器低位(accumulator low)
  • CL——计数寄存器低位(counter low)
  • DL——数据寄存器低位(data low)
  • BL——基址寄存器低位(base low)
  • AH——累加寄存器高位(accumulator high)
  • CH——计数寄存器高位(counter high)
  • DH——数据寄存器高位(data high)
  • BH——基址寄存器高位(base high)

名字看起来和上面的16位寄存器有点像,这是因为:AX的0~7低八位称为AL;AX的8-15高8位称为AH.
BP、SP、SI、DI不能分为H和L,如果需要取高8位或者低8位,需要用“MOV AX,SI”,然后再用AH、AL来取值
-----------------------------------------------------------------------------------------------------------------------
32位寄存器有:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI,它们和前面的16位寄存器共用,32位寄存器中低16位是AX,高16位没有名字,也没有寄存器编号,如果要取高16位,需要用移位命令获取
-----------------------------------------------------------------------------------------------------------------------
段寄存器(segment register)–16位寄存器

  • ES——附加段寄存器(extra segment)
  • CS——代码段寄存器(code segment)
  • SS——栈段寄存器(stack segment)
  • DS——数据段寄存器(data segment)
  • FS——没有名称(segment part 2)
  • GS——没有名称(segment part 3)

在汇编语言中,所有标号都是单纯的数字,每个标号对应的数字都是由汇编语言编译器根据ORG指令计算出来的,编译器计算出的标号的地方对应的内存地址就是那个标号的值。

内存到底是什么?
简单用一句话概括就是超大规模存储单元住宅区。前面通过对寄存器的说明了解到CPU的存储能力很差(32位CPU所有的寄存器如果用来存储,只能存储8[通用寄存器个数]*4[每个寄存器字节数]+6[段寄存器个数]*2[每个寄存器字节数] =44字节),如果想让CPU处理大量信息,就必须给它准备一套用于存储的电路。
------------------------------------------------------------------------------------------------------------------
对CPU来说,内存实际是外部存储器,程序本身保存在内存里,CPU在执行机器语言时,从内存一个命令一个命令地读取程序,顺序执行。
内存虽然如此重要,但是它离CPU的位置却相当远,当CPU向内存请求数据或者输出数据时,内存需要花费很长时间才能实现CPU的要求,所以CPU访问内存的速度比访问寄存器的速度慢很多倍

BYTE、WORD、DWORD是汇编的保留字,用法如下:

MOV BYTE [678],123

BYTE指明操作8位,用内存的“678”号地址保持“123”这个数值;这里“678”是一大串的开(ON)或者关(OFF)的电信号,当内存收到这一串电信号后,电路中某8个存储单元就会响应,这8个存储单元会记住代表"123"的开(ON)或关(OFF)的电信号。

MOV WORD [678],123

WORD指明操作16位,此时内存地址678号和679号都会做出反应,123被解释成16位数值,低8位保存在678号,高8位保存在679号上
在这里插入图片描述

数据大小[地址]是一个固定组合,如果知道数据大小为BYTE,那么使用的单元就只是地址所指定的字节;如果为WORD,则相邻的一个字节也会成为这个指令的操作对象;如果为DWORD,则与WORD相邻的两个字节也会成为这个指令的操作对象(共4个字节)。(这里相邻指的是地址增加方向的相邻)
--------------------------------------------------------------------------------------------------------------------------
内存地址的指的方法:常数和寄存器。比如“BYTE [SI]”、“WORD [BX]”,如果SI中保持的是978,那么“BYTE [SI]”解释为指定地址为978的内存。
注意:
虽然寄存器可以用来指定内存地址,但可用作此用途的寄存器非常有限,只有BX、BP、SI、DI。剩下的AX、CX、DX、SP不能用来指定内存地址,这是因为CPU没有处理这种指令的电路,或者没有表示这种处理的机器语言。

  • ADD——加法指令,ADD SI,1 对应C语言中的SI=SI+1
  • CMP——比较指令
    JE——条件跳转指令之一,如果比较结果相等就跳转,不等就不跳转,继续执行下一条指令。这条指令源于英文“jump if equal”。

条件跳转指令是指根据比较结果决定跳转或者不跳转。

因此,如下指令

CMP		AL,0
		JE		fin

相当于

if(AL==0){goto fin;}
  • INT——软中断指令,源自英文“Interrupt”,意思是中途打断

BIOS(basic input output
system 基本输入输出系统程序)程序在电脑出厂时就存储在电脑主板的ROM(Read Olny memory)单元里,厂家会在BIOS中预先写入操作系统开发人员经常会用到的函数,而INT就是用来调用这些函数的指令。INT后面使用不同的数字可以调用不同的函数,本次调用0x10(16)号函数,它的功能是控制显卡,具体用法如下:
显示一个字符:

  • AH=0x0e;
  • AL=character code;
  • BH=0;
  • BL=color code;
  • 返回值:无
    注:beep、退格(back space)、CR、LF都会被当做控制字符处理
  • HLT——让CPU进去待机状态,源自“halt”,停止的意思

至此,上面的汇编程序可以改成C语言:

entry:
	AX = 0;
	SS = AX;
	SP = 0x7c00;
	DS = AX;
	ES = AX;
	SI = msg;
putloop:
	AL = BYTE [SI];
	SI = SI + 1;
	if (AL == 0) { goto fin; }
	AH = 0x0e;
	BX = 15;
	INT 0x10;
	goto putloop;
fin:
	HLT;
	goto fin;

至此,可以打印出“hellow world”。

为什么程序的装载地址是0x7c00呢?
电脑中的内存一般都非常大(64MB,512MB,…),但这些内存并不是想怎么用就怎么用的,0号地址处,是BIOS用来实现各种不同功能的地方,0xf0000存放这BIOS程序本身,启动区内容的装载地址为:0x00007c00~0x00007dff。0x7c00这个值是由当时设计的人决定的。

制作512字节的启动区:

  1. 修改asm.bat,输出文件名修改为ipl.bin,输出文件列表ipl.lst(可以确认每个指令是怎么翻译成机器语言的)
..\z_tools\nask.exe ipl.nas ipl.bin ipl.lst
  1. 增加makeing.bat,以ipl.bin为基础,制作磁盘映像文件helloos.img。
..\z_tools\edimg.exe   imgin:../z_tools/fdimg0at.tek   wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img

编译测试:asm -> makeing -> run

使用Makefile实现:

  1. 新建Makefile文件,输入:
# 默认动作

default :
	../z_tools/make.exe img

# 文件生成规则

ipl.bin : ipl.nas Makefile
	../z_tools/nask.exe ipl.nas ipl.bin ipl.lst

helloos.img : ipl.bin Makefile
	../z_tools/edimg.exe   imgin:../z_tools/fdimg0at.tek \
		wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img

# 命令

asm :
	../z_tools/make.exe -r ipl.bin

img :
	../z_tools/make.exe -r helloos.img

run :
	../z_tools/make.exe img
	copy helloos.img ..\z_tools\qemu\fdimage0.bin
	../z_tools/make.exe -C ../z_tools/qemu

install :
	../z_tools/make.exe img
	../z_tools/imgtol.com w a: helloos.img

clean :
	-del ipl.bin
	-del ipl.lst

src_only :
	../z_tools/make.exe clean
	-del helloos.img

#号表示注释。下一行“ipl.bin : ipl.nas Makefile”的意思是,如果想要制作文件ipl.bin,就先检查一下ipl.nas和Makefile这两个文件是否都准备好了。如果这两个文件都有了,Make工具就会自动执行Makefile的下一行。
“\”是续行符号,表示这一行太长写不下,跳转到下一行继续写。

  1. 需要调用make.exe来让这个Makefile发挥作用,新建make.bat:
..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值