汇编基础(王爽版阅读记录)

it2025-09-09  8

汇编语言(王爽版)中值得参考的思想:知识屏蔽。针对计算机科学交叉的特点,将内容进行最小化分割,力求使读者接触的每一个知识点都是当前唯一要去理解的东西。这是为什么许多教材像字典!简单的知识罗列,引导不足。

文中部分图片直接摘自汇编语言(王爽第三版)。

第一章 计算机基础

1.1 汇编编程过程

采用冯诺依曼结构的现代计算机,指令和数据都采用二进制保存在存储单元中(可以理解为内存),通过硬件电路CPU通过译码器直接区分指令和数据。仅就数据角度来看,都是一堆二进制数据。

汇编语言包含三个部分:

汇编指令和二进制机器指令一一对应。

伪指令

xxx segment          xxx endsassmue cs or ds or ss   : xxxx   假设,表明关联关系,属于代码还是数据还是其他。 end 汇编结束标记。放在程序最后边。

如下图所示,图中代码片段,表示了汇编语言的完整结构。

1.2 存储单元

存储单元最重要的信息就是地址,地址可以类比为门牌号,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。

2.1 CS和IP

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的地址。

2.2 CS、IP修改

CPU只认被CS:IP指向的内存单元中的内容为指令。所以要让CPU执行设定的位置,就需要修改CS,IP的内容使它们的组合指向第一条指令的地址。

CPU执行的代码位置取决于CS、IP,修改这两个寄存器中存放的值就可以控制CPU执行我们需要的代码。这里MOV没法起代替作用,最简单的指令是JMP。

 

同时,这种CPU跳转的行为可以进行分类:段内转移和段间转移。

2.3 DS和[address]

两个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]这种形式。

2.4 栈

任意时刻,SS:SP指向栈顶元素,栈符合先入后出原则。(LIFO)

SS存放堆栈的段地址,SP存放偏移地址。

push,pop指令和Mov不同

push和pop分别执行了两步

sp=sp-2 (传送数据,pop)传送数据(sp=sp+2,pop)

这段代码对应着程序返回。

2.5 loop指令

首先明确一个概念,标号,标号标识了一个地址,会被编译器自动转化为一个地址。

(cx)=(cx)-1(cx)不为0则转至标号处。

上图中的S,就是标号。对应着 add ax,ax这行指令的地址。

从上边这张图我们就可以清晰的看出来,标号被转化为了地址。

2.6 and 和 or

个人认为这两种指令是通用的位处理技巧

通过这两个指令指定复位和置位的位置。

3 使用多个段进行汇编

3.1 将数据、代码、栈放入不同的段

assume cs:code,ds:data,ss:stack data segment dw 2012h,0456h,0789h data ends stack segment dw 1111h,1111h,1111h stack ends code segment start: mov ax,stack mov ss,ax mov sp,06h mov ax,data mov ds,ax mov bx,0h mov cx,3h s: push [bx] add bx,2h loop s mov bx,0h mov cx,3h s1: pop [bx] add bx,2h loop s1 mov ax,4c00h int 21h code ends end start

首先需要根据以上代码明确几个问题:

命名了三个段,data,stack,code。是否CPU就回去执行code段中的代码,读取data段中的数据,利用stack段的栈呢?通过伪指令assume,进行了关联,CPU就将CS指向了code,DS指向了data呢?

end start指明了程序的入口。段的定义只是方便了我们人去理解代码,但是定义最终不会出现在CPU执行的命令里边。CPU如何处理段中的内容,完全取决于具体的汇编指令。重点在于相关寄存器的设置。

 

 

最新回复(0)