汇编语言(王爽版)中值得参考的思想:知识屏蔽。针对计算机科学交叉的特点,将内容进行最小化分割,力求使读者接触的每一个知识点都是当前唯一要去理解的东西。这是为什么许多教材像字典!简单的知识罗列,引导不足。
文中部分图片直接摘自汇编语言(王爽第三版)。
采用冯诺依曼结构的现代计算机,指令和数据都采用二进制保存在存储单元中(可以理解为内存),通过硬件电路CPU通过译码器直接区分指令和数据。仅就数据角度来看,都是一堆二进制数据。
汇编语言包含三个部分:
汇编指令和二进制机器指令一一对应。
伪指令
xxx segment xxx endsassmue cs or ds or ss : xxxx 假设,表明关联关系,属于代码还是数据还是其他。 end 汇编结束标记。放在程序最后边。如下图所示,图中代码片段,表示了汇编语言的完整结构。
存储单元最重要的信息就是地址,地址可以类比为门牌号,CPU通过地址获取存储单元内部存放的数据。每一个存储单元都有唯一的编号。CPU通过数据线,控制线(读或写 指令),地址线来完成寻址,读写数据的过程。
一个存储单元存放8个bit,即一个字节。8bit=1Byte,1024Byte = 1KB,1024k = 1M,1024M等于1G
存储单元从0开始编号。
寄存器就是CPU中暂时存储数据和地址的地方,是CPU内部的器件。AX,BX,CX,DX,CS,DS,ES,SS,SI,DI,EI,IP,BP,PSW。其中AX,BX,CX,DX是8086通用寄存器,通常用于存放一般性数据。
引申:汇编指令中长度必须匹配,用AL时只能传递1个字节大小的数据。
1个字在寄存器中的存储方式
8086寻址方式:
CPU内部地址线只有16位,最大寻址范围为 2的16次方为 65536Byte,就是64KB,通过采用 物理地址=段地址✖16+偏移地址的方式,使得外部地址线达到20位,也就是说是 2的20次方 等于1 048 576Byte,也就是1024KB,也就是1M。因为地址采用16进制,乘16后效果等同于左移一位。0x0123h变为0x01230h。
CPU首先要知道当前要运行的代码存放在哪个位置。
CS是代码段寄存器,存放着当前CPU要读取的指令的地址。CS(code segment)代码段寄存器和IP(instruction pointer)指令指针寄存器成对出现,CS存储基础地址,IP存放偏移地址。
每一条指令也是有长度的。IP会自动增加,从而指向下一条即将执行的指令。
8086cpu工作流程简要描述:
从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器。IP=IP+所读取指令长度,从而指向下一条指令。执行指令,转到步骤1,重复过程。如下图所示,执行完第一行 mov ax,5h以后,CS:IP存放了CPU即将执行的mov bx,6h的地址。
CPU只认被CS:IP指向的内存单元中的内容为指令。所以要让CPU执行设定的位置,就需要修改CS,IP的内容使它们的组合指向第一条指令的地址。
CPU执行的代码位置取决于CS、IP,修改这两个寄存器中存放的值就可以控制CPU执行我们需要的代码。这里MOV没法起代替作用,最简单的指令是JMP。
同时,这种CPU跳转的行为可以进行分类:段内转移和段间转移。
两个16进制,代表一个字节。4个16进制,代表一个字。
高八位存放高位字节,低八位存放低字节。
如图中所示,0-1单元存放了字(4e20h)(20000)。2-3号单元存放了字(0012h)。
DS寄存器通常用来存储要访问的数据的地址。
8086cpu不支持直接将数据送入DS。mov ds,1000h是不被允许的。需要采用寄存器作为中介来传送数据。该问题属于8086硬件实现问题。
如上图所示,以BX寄存器为中介,把段地址传入了DS中。同时,mov ax,[0]则是默认了偏移地址对应的段地址存放在DS中。
但是由于实际 debug和实际的编译器处理不同
mov ax,ds:[0] (显式的指出段)或者是mov ax,[bx] (利用bx)寄存器实际编译器处理不能直接理解形如 mov ax,[0]这种形式。
任意时刻,SS:SP指向栈顶元素,栈符合先入后出原则。(LIFO)
SS存放堆栈的段地址,SP存放偏移地址。
push,pop指令和Mov不同
push和pop分别执行了两步
sp=sp-2 (传送数据,pop)传送数据(sp=sp+2,pop)这段代码对应着程序返回。
首先明确一个概念,标号,标号标识了一个地址,会被编译器自动转化为一个地址。
(cx)=(cx)-1(cx)不为0则转至标号处。上图中的S,就是标号。对应着 add ax,ax这行指令的地址。
从上边这张图我们就可以清晰的看出来,标号被转化为了地址。
个人认为这两种指令是通用的位处理技巧
通过这两个指令指定复位和置位的位置。
首先需要根据以上代码明确几个问题:
命名了三个段,data,stack,code。是否CPU就回去执行code段中的代码,读取data段中的数据,利用stack段的栈呢?通过伪指令assume,进行了关联,CPU就将CS指向了code,DS指向了data呢?end start指明了程序的入口。段的定义只是方便了我们人去理解代码,但是定义最终不会出现在CPU执行的命令里边。CPU如何处理段中的内容,完全取决于具体的汇编指令。重点在于相关寄存器的设置。