实验日期 |
2018/9/29 |
实验项目 |
第2天:汇编语言学习与Makefile入门 |
(一)汇编
1、关键代码
运行结果:
2、相关汇编指令的解释
指令 |
格式 |
含义 |
ORG指令 |
ORG address |
指定程序的装载地址 |
JMP指令 |
JMP address |
跳往指定地址执行 |
ADD指令 |
ADD r1,r2 ADD r,m ADD m,r ADD r,data |
加法指令,将两个操作数相加,m可以为[r]、[address],即寄存器r所存数据或地址address对应的内存区数据 |
CMP指令 |
CMP r,m CMP r,data CMP m,r CMP m,data |
比较两个操作数的值,一般后面会跟一个条件跳转指令 |
JE指令 |
JE,address JE,函数名 |
条件跳转指令之一,即CMP中两个比较的数据相等时跳转到此指令中对应的地址address(也可以是函数名)处,若不等则执行该指令(JE)的下一条指令 |
INT指令 |
INT,address |
软件中断之令,用来调用该地址对应的中断函数,执行INT时,CPU会自动将标志寄存器的值入栈 |
HFLT指令 |
HLT |
让CPU停止动作进入待机状态 |
MOV指令 |
MOV r,m MOV r1,r2 |
把源操作数送给目的操作数 |
3、相关寄存器
(1)16位的寄存器
寄存器名 |
AX |
CX |
DX |
BX |
SP |
BP |
SI |
DI |
详细名称 |
累加 寄存器 |
计数 寄存器 |
数据 寄存器 |
基址 寄存器 |
栈指针寄存器 |
基址指针寄存器 |
源变址寄存器 |
目的变址寄存器 |
(2)16位的段寄存器
寄存器名 |
ES |
CS |
SS |
DS |
FS |
GS |
|
详细名称 |
附加段寄存器 |
代码段寄存器 |
栈段寄存器 |
数据段寄存器 |
无名称 |
无名称 |
|
(二)启动区制作
1、生成.bin和.lst文本文件来查看汇编代码翻译成机器语言的过程:
①修改之前的day2.nas文件:删除其他扇区部分有关的代码
②改造asm.bat文件中的输出文件的名字,改为day2.bin和day2.lst:
③另创建一个makeimg.bat文件,利用day2.bin生成day2.img映像文件:
启动区的字节数(此时程序刚好只用了1个扇区,每个扇区的大小为512字节)
2、打开!cons_nt.bat,输入asm->makeimg->run,依次生成day2.bin、day2.lst,day2.img文件,同时输出了运行的结果:
打开day2.bin文件,发现在地址0x000200之前的部分与day2.img文件无异,但0x00200之后,day2.bin没有其他信息,而day2.img全为0x00,如下:
day2.lst文件如下:
(三)Makefile
部分内容如下:
解释:
1、“#”:表示注释,注释内容以换行符结束,如果其它地方用到‘#’要用双引号引用;
2、“\”:续行符号,表示这一行写不下跳转到下一行继续写;
3、格式规则:即指定多个目标并能够根据每个目标名构造对应的依赖名的规则。
格式规则的语法格式:
targets... :
[tab]commands
Target:生成的目标文件,必写;
prerequisites:前置条件,,生成目标文件时,会先检查源文件是否准备好了,若准备好了Make工具就执行下一行(即命令行);
[tab]:tab键,每个命令行必须以tab键为首,"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。
4、命令行的书写
-r:如果一个规则中的某个命令出错了(命令退出码非零),那么make就会终止执行当前规则,这将有可能终止所有规则的执行,为了忽略命令的出错,我们可以在Makefile的命令行前(在Tab键之后)加一个减号“-”,标记为不管命令出不出错都认为是成功的。“-r”表示禁止使用预定义的隐含规则,同时也清除了缺省的后缀列表和后缀规则。注意缺省的变量仍然有效。
-C dir :在读入makefile之前,把路径切换到dir下。
-del file:删除文件file
问题一:
运行时出现下图情况:
分析和处理过程:
查看Makefile中第13行的代码并与原作者的代码进行对比:
本人的内容: 《30天自制操作系统》作者的内容:
可以看到书写内容并无区别,于是排除了书写出错的问题,但发现将作者的代码复制过去时,若不复制前面的空格,则仍会报错,只有将前面的空格部分一同复制过去时,运行时才不会报错,于是得出结论:代码前面的空格不符合书写规定。
那为什么会不对呢?之前《30天自制操作系统》作者介绍notepad++时,介绍了一些基本设置即settings->preference->languages,里面提到有tab size:4,如下:
于是在上网查找了tab键和空格键的相关信息,如下:
不同编辑器的Tab键大小设置不一样,在本实验中代表4个空格(4个字符), 有时在其他电脑下tab键默认为8个空格;如果使用空格代替Tab,就不会有这个问题,因为空格的数量是不会变化的。
一般编程时尽量使用空格键而不使用tab键,以免用不同的编辑器阅读程序时,因TAB键所设置的空格数目不同而造成程序布局不整齐,不要使用BC作为编辑器合版本,因为BC会自动将8个空格变为一个TAB键,因此使用BC合入的版本大多会将缩进变乱。
在网上查找结果都表明尽量用空格键代替tab键,可是我发现用tab键来替换4个空格就能成功运行而直接使用4个空格时就出错,并且若在上图中勾选“Replace by space”,则所有新产生的Tab都会自动转换成对应的空格数(原先已经存在的Tab并不会因为该选项而自动转换成空格)来代替Tab,这种情况下使用tab键时,也会报错,那这是为什么呢?
本人猜测:会不会tab键还有其他的功能时空格键无法替代的?还是Makefile文件的行首不能有空格?于是我又在网上查找tab键的其他功能,得到的结果如下:(参考网址:http://www.mamicode.com/info-detail-1389887.html)
即在Makefile文件中,命令行行首必须使用tab,否则会报错。
解决方法:
所有的命令行的行首全用tab来替换之前写下的4个空格(后来在网上直接用“*** missing separator”搜索时就有许多解释和解决办法,一开始就没想过这茬儿,自己一个劲儿地瞎分析【狗头】)。
1、创新点以及关键代码
对汇编代码进行改写使屏幕显示出一个皮卡丘图案,关键代码如下:
在汇编代码中,实现在屏幕上显示字符的代码部分如上,我们要改变显示的内容只需设计好图案皮卡丘对应的ASCII码以及相应的排版即可。由于在0x7dfe和0x7dff处输入0x55和0xaa来结束对磁盘中这一扇区的操作,且在这地址0x7dfez之前我们必须保证:(1)信息显示部分最多可以有约400字节;(2)除了信息显示部分,剩下部分用0x00填充。这样计算机才能检测到相应的扇区且不会 出错。
结果截图:
感觉这一次的实验不算很难,主要了解到了一些汇编知识,比如8个16位寄存器和8个16位段寄存器,也了解到了一些常用的基本的汇编指令的应用如加法指令ADD、比较指令CMP等,但我印象最深的是待机指令HLT,在之前学习汇编的时候似乎也很少见,感觉这个指令特别有用,可以让CPU不用不停地去执行JMP指令进入睡眠状态,可以节省很多电。