汇编语言 王爽第二版 总结,所以内容都是8086的
summary assseassummbly ,汇编总结


why, what, how

why:
最初始的编程语言就是使用打孔机,打出来的0 1 代码,然后把卡片插入到电脑中运行然后
看输出结果,这种纯01的二进制代码,编写困难调试困难运行结果的显示看着也很蛋疼,就像
一个简单的“hello world”,11个字符,需要11×8个二进制,并且再进行输出,就更麻烦,因为
全部都是二进制,代码。为了更高效的开发程序,就出现了汇编语言,用来代替二进制代码的输入。

what:
汇编语言主要由伪指令和汇编指令,和其他符号组成。

how:要想知道,汇编语言是怎么运行的,并且呈现出我们现在看到的图形化界面,比如你敲击
键盘然后在屏幕上面出现相应的字符,或者你现在正在浏览的网页上面的文字是怎么显示出来的
如果你想知道这些,那就学习汇编语言把,他会帮助你了解你想知道的并且帮助你更好学习操作
系统。

总线

cpu的外部总线总共分三种,地址总线 数据总线 控制总线
我们知道计算机一切操作转为二进制,在转为高低电平,也就是说在计算机的硬件层次所有信息的
传递就是依赖高低电平(0代表低电平1代表高电平),cpu通过总线和内存,总线就像是管道把cpu
和内存相连接,cpu相当于是一个工作站,内存就是水库,总线就是水管,把工作站和水库相连接
当然因为,工作站通过管道获取需要的东西,地址总线相当于管道的位置,数据总线就是管道内部
流通的水,控制总线相当于开关。
这里写图片描述
这里写图片描述
这里写图片描述

寄存器

因为cpu和内存之间数据的传输以及一些其他的问题,后面我们会说到,所以就有了寄存器就相当于
c语言中的全局变量,只不过名字已经固定好了,相应的变量里面存储的相应的内容,只不过这里的
寄存器是硬件:寄存器就是和cpu内部的一些存储器,主要是用来存储一些数据,提供cpu的使用,
主要分为: 段寄存器,偏移寄存器,普通寄存器,标志寄存器,
段寄存器存: cs(指令段地址) ss(栈的段地址) ds es
偏移寄存器:ip(指令) sp(栈偏移即栈顶) di si bx 这三个寄存器默认指向ds bp 默认指向cs
普通寄存器:ax dx cx dx 都是16位的寄存器,但是为了兼容以前的八位cpu就需要有八位寄存器
所以所有的16位寄存器又都可以分成俩个8位寄存器,把寄存器名字第一位不变,第二位改成:
l(low) or h(hign) such as : al ah cl ch ,这样我们就能得到8位的寄存器。
标志寄存器:就是一个16位长的特殊结构体,就跟c语言里面bit-field一样由相应的名字代替,
存储一些标记用来进行一些运算,比如我们最常见的:5+18 = 23,5+8=13就需要进一位,5+8
就会导致溢出寄存器的值变为1,然后进行十位的加法时,再加上寄存器的值,0+1+1=2,就得到了
23,总共有16个标志为,可以帮我处理很多程序运行过程中的问题,特别判断大小。

寻址方式


前面我们讲到了地址总线,寄存器,这里我们就说一下,cpu怎么通过地址总线,在内存中找到相应
的地址的,我们知道16根地址总线的地址范围就是64kb,这对于我们的程序来说太小了,为了增加
地址的范围,我们采用了段+偏移的方法来增加寻址范围,就像我们写作文一样,把文章划分位不同
的段落,每一个段落里面都有第一句话,我们只要知道第几段第几句话就可以找到对应的文字
cpu 也可以通过这种方式增加寻址范围,8086cpu的实际地址是20位,并不是我们的16位所以实际的
地址就需要段+偏移,组成20位的地址,其实很简单,就是把段地址左移4位,然后加上偏移的
4位就构成了20位的实际地址。更进一步的说,内存是没有段的概念的,只是cpu自己划分的段,通过
段和偏移找到实际的地址,实际情况中可能有的程序比较大,就需要一大块内存来管理,这个时候
16位的地址×16就是段的起始地址,16位的偏移地址就指向的段内的地址,虽然偏移是相对的,但是通过
段和偏移就是可以找到实际的地址,这样我们程序的处理速度就会更快其实我觉得这跟数组是一样的原理
当然了我们要理解的就是这种思想就可以了。实际cpu的寻址方式有三种,就跟我们c语言里面的定义:
常量 变量 变量+常量 变量+变量+常量
同样cpu寻址方式,也可以通过这种 常量(直接给出地址) 变量(通过寄存器存储的值) 变量+常量
such as : ax:[0] ax:[bx] ax:[bx+1] ax:[cx+bx+1] ax里面存储的是段的地址
这样通过ax里面锻的地址找到段的地址,然后通过偏移找到实际的地址。cpu就是通过这种方式在寄存器
和内存之间互相传递数据,从而达到自己写内存或者读内存的目的。
这里就是一点就是所有的段地址都是16的倍数,并且偏移都是从0开始的。
说道这里提一下,寄存器冲突的问题,使用stack来保存寄存器的值,把子程序中用到的寄存器,在使用前
把寄存器的值全部入栈,退出子程序的时候恢复相应寄存器的值,就可以解决寄存器冲突(针对多个程序共用寄存器
的情况)。当然了也可以通过栈来一次传递多个参数,解决参数过多的问题,就跟我们在c语言中使用数组是一样的
道理,这里可以使用栈也可以数组,在cpu里面就是内存。

指令


我们都知道一个程序是由一条条指令组成的,就像我们写的c语言一样,汇编语言也是一样,只不过汇编语言
由汇编指令和伪指令组成,汇编指令由cpu处理,伪指令又汇编编译器处理,我们写的c语言都是由c语言编译器
编译 链接 最后形成二进制可执行文件,但是由于我们的cpu可以识别汇编语言,汇编语言可以直接在cpu中执行
所以就不需要编译,这就是汇编语言厉害的一个地方,另外牛逼的地方就是可以通过地址,操作我们想做的一切
事情,做到c语言java语言等语言不能做到的,这就是我们学习它的原因,也是它的魅力,当我们用用工具把u盘
制作为启动盘的时候,都感觉很神奇吧,学习汇编就可以慢慢揭开这些神秘的面纱,你也可以通过自己写的程序
制作u盘启动盘,这都不是问题,关键的问题是,你要了解不同cpu的指令。当然了我觉得现在cpu更新换代很快
但是不用担心,这些都是有标准的,只是个别地方不一样而已,并且都会有说明哦。说了这么多,就让我们写一个
最简单的ax = 1,ax = ax +1 吧。
mov ax, 1;把ax寄存器存储为1 即0001H ,h表示是16进制
add ax, 1; ax = ax + 1
汇编指令一般分为:转移指令,跳转指令,对比指令
转移指令:其实和c语言中的赋值语句道理一样,跳转指令就是跟go语法是一样的通过一个标记,判断就是if else….
转移指令:mov push pop
跳转指令:jump loop call ret iret
对比指令:cmp 判断俩个值的大小 结果存在标志寄存器中,通过判断指令可以得到判断结果
条件跳转指令:jcxz je jne ja jna jb jnb 通过字面意思就可以理解,jcxz 等于 je就是判断等于(if 语句)
jne 就是不等于 ja就是above 高于jb blow 就是低于的意思,通过cmp 对比然后使用判断语句(相当于if 判断语句)
我们的if语句就是通过这些实现的。
数据格式: db:(byte 类型) dw(一个字俩个字节) dd(double word ,双字节)
操作数据: add sub mul div 分别是: 加 减 乘 除; inc(自增 类似于 ++ ) dec(自检)
操作标志寄存器:popf pushf std ctd 等,可以查看相关的资料
重复操作: rep db ’a‘ 根据cx 寄存器的值,连续分配cx个内存但原来存储a,
移动操作: movb movdw movdd 一次复制 byte word dword 大小的数据从一个地址到另外一个地址 根据相应的寄存器
存储的地址,以及偏移,并且会自动把存储偏移的寄存器的值加1

内部中断


所谓中断,就是打断cpu正在处理的事情(当cpu处理完正在执行的指令),然后让cpu来处理你提交的事情。
以前我知道bios就是basic input and output基本输入输出但是也就仅此而已了,看完汇编之后我我知道了,
就是使用中断来调用已经写在内存的输入输出方法。cpu使用一个表来存储所有硬件提供的中断方法的地址,
中断向量表中存储的相应方法在内存中的地址,中断发生后,去中断向量表找到对应的地址,然后跳转过去
执行执行完毕,中断结束,继续下一条指令。内中断主要指的是cpu内部的中断,中断信息来自cpu内部比如
除法错误 单步执行 执行into指令 执行int 指令,我们还知道cpu有端口可以用来连接外部设备比如键盘鼠标等,那么键盘
输入怎么处理的呢,键盘输入一个字符后,就调用相应的外部中断,告诉cpu我这里有输入信息,然后cpu就会处理,然后我们
就在屏幕上看到了刚才输入的字符了,由外部设备发出的中断就是外部中断。

中断 原理


断首先要把你写好的中断程序,放到一个稳定的安全的内存中,然后把程序的地址偏移放到中断表中,这就是中断程序的安装
过程,然后就是根据你的中断向量的在中断向量表中的下标来调用,8086cpu 中断调用是用关键字 int +中断向量下标,就可以调用了。

程序的编译 链接 运行调试


masm link debug 这些工具打包放到这里:
http://pan.baidu.com/s/1c2kEHXI
http://pan.baidu.com/s/1qYQnHFm 我写的练习

总结


看着本书主要就是打一个汇编的基础,让你对地址、数据、指令有一个明确的认识,知道一个程序是如何运行起来,cpu通过各种寄存器来区分
谁是数据,谁是指令的,让你明白这种处理逻辑,流程以及处理问题的思想,当然了我觉得看完这个之后,在去看操作系统组成原理等书,会
事半功倍,因为汇编会让你对系统的底层有一个清晰的认识,底层了解了再去学上层的操作系统就会有一种恍然大悟的感觉,了解操作系统的发展
你才会对他肃然起敬,因为这些都是最好的程序员科学家们的结晶,你每天在用的东西就是无数个牛人写出来的,虽然我只是在使用计算机
但是我觉的这就像是跟他们在交流一样,难道你不觉得你在键盘上打出一个字符就会在屏幕上显示出一个字符这是很神奇的一件事情吗?在这个
大家习以为常的背后到底隐藏了多么深奥的知识历经了几代人的发展呢,我想作为一个优秀的计算机学习人员一个都需要掌握。学习技术发展史
的重要意义正在与此:追溯的历史越久远,技术的脉络就变得越清晰。