第9章
本章讲转移指令,书中说:
可以修改IP,或同时修改CS和IP的指令统称为转移指令
转移指令根据转移时是否修改CS分为段内转移和段间转移。
最值得注意的一点,以段内转移为例,如jmp s0指令,转换为机器码后占用两个字节,第一个字节是jmp指令自己的机器码,而第二字节尤其重要,它是转移目标指令相对于jmp的下一条指令的偏移距离。
为什么会这么设计呢?简单回顾一下指令的执行过程:
CPU从CS:IP指向的地址中读取指令
IP指向下一条指令
执行指令
因为IP寄存器总是在读取指令后就更改为当前指令的下一条指令的地址了,而此时当前指令还没有执行,当控制器执行jmp指令时,只需要将IP中的值加上第二个字节中的偏移距离,就可以找到跳转的目标指令的地址了。
而这个特点在本书实验8中得以体现,可以说分析完实验8才真正意义上让我记住了jmp指令的特点。
关于实验9
实验9通过介绍内存中的显示缓冲区,让我对计算机是如何将输入输出打印在屏幕上有了更深的认识,因为我知道现代计算机的显示通常是通过显卡完成的,而显卡中有一块内存区域就对应到显示器的显示内容。显然在很早以前8086就通过这种规定内存中一块区域对应显示内容来实现了数据的输出显示。
第10章
本章通过call和ret指令引入了子程序的概念,同时也不得不开始使用栈,因为在程序的反复调用中必然涉及到寄存器不够用的问题,如果不使用栈,不论是子程序还是多重循环,都会破坏寄存器中原有的值,使得整个程序发生错误。
所以说栈的设计真的很精妙,它使程序员能用更大容量的内存保存寄存器值,以达到整个计算机只需要少量寄存器就可以完成规模庞大的复杂算法的目的。
第11章
本章讲标志寄存器,在学习本章之前,我对标志寄存器的认识也仅仅停留在“知道有这么个东西,但是具体都是啥并不清楚”的程度。
CF标志寄存器
其中让我觉得最巧妙的设计是进位(借位)标志位CF,如果在上一次运算中产生了进位(或借位)CF就为1,否则为0。和它相关的还有一个指令是 adc 指令,如 adc ax,1 这条指令,执行后相当于ax = ax + 1 + CF。在我初看到这里时并不理解这样做的意义是什么,直到后文中通过adc命令完成了32位加法时我才霍然开朗。也就是说:
CF标志和adc指令共同作用,使得16位寄存器系统中能够完成32位,64位甚至1024位的加法运算。
与adc指令类似的还有sbb,它同样利用CF的借位信息完成多位数的减法运算。
CMP指令
另外本章根据zf,cf等标志位引入了CMP指令,至此一个能够完成复杂算法的包括顺序结构、分支结构、循环结构的程序终于完整了。
第12~13章
内中断,也就是现代操作系统概念中的异常。由于前段时间刚通过《深入理解Linux内核》和网络等途径理解过一次中断,所以对本书中提到的中断的概念都在学习前就有了大概认识。
通过这两章自己动手编写中断例程并安装中断,更清楚了在电脑加电的那一刹那,BIOS是如何配置中断向量表,加载中断例程,再将控制权交给操作系统的。
另外,一些保留的中断号,用户是可以通过编程来添加中断例程的,这也使我随之想到了现代操作系统中各种权限的限制的必要性。
第14章
本章主要知识点总结如下:
在DOS系统中,所有的外设都有专属的一个或多个端口号,CPU通过端口号对外设进行读写操作。
同一外设可能因为操作需要有多个端口号,比如CMOS RAM芯片,70h端口用于写入需要访问的数据地址,71h端口根据70h端口提供的地址取出数据。
访问端口数据只需使用 in 和 out 两条指令
第15章
本章主要讲外中断,内存中通过特定内存单元存储键盘的状态字节,通过该字节判断键盘中Ctrl、Shift、Capslock等控制和切换键的状态
也就是说,我们在每次使用键盘输入的时候,如果是字符键,操作系统首先会读入扫描码,然后检测键盘的状态字节,看是否有切换键按下,根据切换键选择字符键对应的ASCII码写入键盘的缓冲区。