欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《汇编语言》——王爽第三版笔记(1-3章)

程序员文章站 2022-06-07 09:22:45
...

汇编语言

书籍电子版 提取码: b62a
书上内容比较全,初学者多看看王爽老师的书。有不懂的再来查。
笔记是简略版,有检测点和实验的答案,还有自己的理解。

前言

在学之前,搞清楚本书的重心:

通过学习关键指令来深入理解机器工作的基本原理,培养底层编程意识和思想。

读者应具备以下知识:

  • 二进制、十六进制的知识
  • 一门高级语言基本编程基础(顺序,选择,循环)

第一章:基本知识

位、字、字长、字节

  • 位(bit,b):是计算机中最小的数据单位,一个位的值只可能是0或1
  • 字节(Byte,B):8位是一个字节
  • 字长:CPU在单位时间可以处理的最大二进制的位数。8位CPU,也就是单位时间内最大可以处理一字节。
  • 字(Word,W):计算机处理数据时,一次存取、加工、传送的数据的长度称为字。一个字通常是由多个字节构成。字长为32的CPU,一个字等于4个字节。显然,字与字长有关,可以理解为:一个字 = 字长/8。

机器语言

  1. 机器语言是机器指令的集合
  2. 机器指令展开来讲就是一台机器可以正确执行的命令。

汇编语言的产生

  1. 汇编语言的主体是汇编指令
  2. 汇编指令与机器指令的差别在于指令的表示方法上。汇编指令是机器指令便于记忆的书写格式。
  3. 汇编指令是机器指令的助记符。

汇编语言的产生

机器只认识二进制,机器语言就是一堆二进制码。所有的高级语言写的源程序最终都会变成二进制,给机器运行。

机器语言人难写又难读,所以就用另一种人比较好看的语言来做这些事情,通过编译器最终转换成机器语言。

这个转换过程叫做翻译。

寄存器:CPU中可以存储数据的器件,一个CPU中有多个寄存器。

汇编语言的组成

  1. 汇编指令(机器码的助记符,有对应的机器码)
  2. 伪指令(没有对应的机器码,由编译器执行,计算机不执行)
  3. 其它符号(由编译器识别,没有对应的机器码)

汇编语言的核心是汇编指令,它决定了汇编语言的特性。

存储器

CPU是计算机的核心部件,它控制整个计算机的运作并时进行运算,要想让一个CPU工作,就必须向它提供指令和数据。

指令和数据在存储器中存放, 也就是平时所说的内存。计算机中的硬件一般都有固定的存储,显卡,网卡,BIOS都有。

存储单元

存储器被划分为若干个存储单元,每个存储单元从0开始编号。

微机存储器的容量是以字节为最小单位来计算的,一个存储单元就是1Byte,即8个二进制位。也就是说64KB就是10^16字节,字节单位已经是最小单位了,不能再细分了。

B=>KB=>MB=>GB=>TB

指令和数据

在计算机的内存和磁盘上,只有二进制数。这些二进制数有两种可能,要么是数据,要么是指令。

CPU对存储器的读写

  1. 存储单元的地址(地址信息)
  2. 器件的选择,读或写命令(控制信息)
  3. 读或写的数据(数据信息)

《汇编语言》——王爽第三版笔记(1-3章)

地址线发出操作3这个地址,控制线说是读,数据线将08读入CPU。

同理:地址线发出操作3这个地址,控制线说是写,数据线将一个数据写进3这个内存单元。

三大总线

  • 地址总线:

    • CPU是通过地址总线来指定存储单元的*(定位的是Byte,不是bit)*

      尤其要注意这里,能寻址的最小单元是字节单元,也就是说,这个单元上的二进制能表达256种可能。

    • 地址总线上能传送多少个不同的信息,CPU就可以对多少个存储单元进行寻址

    一个CPU有N根地址总线,则可以说这个CPU的地址总线的宽度为N

    其最多可以寻找2的N次方个内存单元(2^N byte)

《汇编语言》——王爽第三版笔记(1-3章)

  • 控制总线

    • CPU对外部器件的控制是通过控制总线来进行的。在这里控制总线是个总称,控制总线是一些不同控制线的集合
    • 有多少根控制总线,就意味着CPU提供了对外部器件的多少种控制,其宽度决定了CPU对外部器件的控制能力

    内存的读或写命令是由几根控制线综合发出的:

    • 其中有一根名为读信号输出控制线负责由CPU向外传送读信号,CPU向该控制线上输出低电平表示将要读取数据
    • 有一根名为写信号输出控制线负责由CPU由外传送写信号

    可以粗略的理解为每一条线对应一个东西,发送0、1进行读写。

  • 数据总线

    • CPU和内存或其它器件之间的数据传送是通过数据总线来进行的
    • 数据总线的宽度决定了CPU和外界的数据传送速度

    数据总线与地址总线不同了,他的一根线就表示一位。8位数据(1byte)就要8根线,而地址线找地址一根就能找两种内存单元(byte)。

《汇编语言》——王爽第三版笔记(1-3章)

《汇编语言》——王爽第三版笔记(1-3章)

注意点

地址总线寻址是从存储(内存)单元寻址的,从寻址来说,存储单元就是最小可编址单位,一般就是1Byte。一根就是1Byte。N根就是2^N个Byte。

数据总线一根就是一位。

内存编址:存储器由许多可存放一段信息的单元(位置)组成,每个单元都有一个编号,程序可以通过这个编号来访问这个单元,这个编号就是这个单元的地址。

显然地址总线就是通过这个编号来访问每一个地址单元的,而地址线一根就是两种状态,通过组合又组成了多种状态来找到这个编号。 如果有6个单元就至少需要3根线(2^3=8)。

检测: 检测点1.1

内存地址空间

一个CPU地址总线宽度为10,那么可以寻址1024个内存单元(Byte),这个1024个可寻址的单元就构成了CPU的内存地址空间。

主板

主板上有一些主要部件和一些核心器件,这些器件通过三大总线相连。CPU、存储器、外围芯片组、扩展卡槽等

接口卡

计算机系统中,所有可用程序控制其工作的设备,都要受到CPU的控制,但是CPU并不能直接控制这些设备,直接控制这些的是在扩展卡槽上的接口卡,扩展卡槽通过总线与CPU相连,所以接口卡也相连。CPU可以直接控制这些接口卡,来间接的控制这些外部设备。

CPU ——> 接口卡——>外设

各类存储器芯片

一台PC机中,装有多个存储器芯片。

物理上来看这些芯片是独立的,从读写属性上分为两类

  • RAM 可读写,掉电内容丢失
  • ROM 只读

从功能和连接上分为

  1. 随机存储器RAM

    用于存放CPU使用的绝大部分数据和程序,主随机存储器一般由两个位置上的RAM组成

    1. 装在主板上RAM
    2. 插在扩展插槽上的RAM
  2. 装有BIOS(Basic Input/Output System)的ROM

    BIOS是由主板和各类接口卡厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的输入与输出。

    主板有主板的BIOS

    显卡有显卡的BIOS

    如果网卡有ROM,那其中就可以存储网卡的BIOS

  3. 接口卡上的RAM

    某些接口卡需要对大批量输入、输出数据进行暂时存储,在其上装有RAM。

    典型的是显卡上的显存,显示卡随时将显存中的数据向显示器上输出,将需要的内空写入显存,就会出现在显存中。

《汇编语言》——王爽第三版笔记(1-3章)

内存地址空间

上面的存储器在物理上是独立的,但是下面两点是相同的

  • 都和CPU的总线相连
  • CPU对它们进行读或写的时候都通过控制线发出内存读写命令

CPU在操控它们时,把它们都当作了内存看待,把它们总的看作一个由若干存储单元组成的逻辑存储器,这个存储器就是内存地址空间

《汇编语言》——王爽第三版笔记(1-3章)

所有物理存储器被看作一个由若干存储单元组成的逻辑存储器,每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间。CPU在这段地址空间中读写数据,实际上就是在对应的物理存储器中读写数据。

内存地址空间大小受CPU地址总线宽度的限制,8086CPU地址总线宽度为20,所以8086PC内存地址空间为1MB,80386地址总线为32,则PC内存地址空间为4GB。
《汇编语言》——王爽第三版笔记(1-3章)

第二章:寄存器

一个典型的CPU由运算符、控制器、寄存器等器件构成,这些器件靠内部总线相连。

前一章说的总线相对于CPU内部而言其实是外部总线,而内部也有一个总线,实现了CPU内部各个器件之间的联系,外部总线实现CPU和主板上其他器件的联系。

在CPU内部

  • 运算器进行信息处理
  • 寄存器进行信息存储
  • 控制器控制各种器件进行工作
  • 内部总线连接各种器件,在它们之间进行数据传送

对于汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。程序员通过改变各种寄存器中内容来实现对CPU的控制。

这里的寄存器是在CPU中的

8086CPU

8086CPU中的所有寄存器都是16位的

通用寄存器

AX、BX、CX、DX

为了兼容上一代的8位寄存器, 这4个寄存器都可以分为两个可独立使用的8位寄存器。

以AX为例高8位AH,低8位AL。
《汇编语言》——王爽第三版笔记(1-3章)

《汇编语言》——王爽第三版笔记(1-3章)

上面表中AX最高位少了一个0

字在寄存器中的存储

8086CPU:

  • 字节:Byte,8bit
  • 字:两个字节,就是16位,分别是高位字节和低位字节

几条汇编指令

《汇编语言》——王爽第三版笔记(1-3章)

汇编指令和寄存器名称不区分大小写。
《汇编语言》——王爽第三版笔记(1-3章)
《汇编语言》——王爽第三版笔记(1-3章)

检测: 检测点2.1

物理地址

CPU访问内存单元时,要给出内存单元的地址,所有内存单元给同的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,这个地址就是物理地址。

CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。而这个物理地址,不同的CPU有不同的形成方式。

8086CPU(16位结构的CPU)

16位的CPU(16位机,字长为16位),意味着:

  • 运算器一次最多可以处理16位数据
  • 寄存器最大宽度为16位
  • 寄存器和运算器之间的最大通路为16位

也就是说,在8086内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。

8086CPU给出物理地址的方法

8086CPU有20位的地址总线,达到1MB的寻址能力,8086CPU又是16位的结构,如果从内部发出的话,也只能发出16位,8086CPU用段地址+偏移地址的方法来形成一个20位的物理地址。

《汇编语言》——王爽第三版笔记(1-3章)

物理地址=段地址*16 + 偏移地址

乘16也就意味着16进制数左移一位,也就是16位的2进制数变成了20 位的2进制数,再加上这个偏移地址,就形成了可以确定的20位的物理地址。

段的概念

要注意的是,内存其实没有分段,是CPU搞出来的段地址。

下面两张图:

可以认为左边的10000H-100FFH组成一个段,起始地址为10000H,段地址为1000H,大小为100FFH-10000H = 100H

可以认为右边的10000H-1007FH组成一个段,10080H-100FFH组成一个段,大小都为80H。

《汇编语言》——王爽第三版笔记(1-3章)

可以看出,起始地址=段地址*16,必然是16的倍数。

在8086CPU中,偏移地址是16位,最大寻址是64KB,0000H-FFFFH,想要两个段接得上,段的长度应该是64KB。

总结

在8086PC机中,存储单元的地址用两个元素来描述,段地址和偏移地址。

数据在21F60H内存单元中,一般不这么说,要说:

  • 数据在2000:1F60单元中
  • 数据在2000段中的1F60H单元

检测: 检测点2.2

段寄存器

8086CPU在访问内存时需要段地址与偏移地址,送入地址加法器合成物理地址。这里就是由寄存器提供地址,段寄存器提供段地址。

8086CPU有4个段寄存器:

  • CS(Code Segment)
  • DS(Data Segment)
  • SS(Stack Segment)
  • ES(Extra Segment)

CS和IP

IP(instruction point):指令指针寄存器

8086PC机中,CS中的内容为M,IP中的内容为N,8086将从M*16 + N的内存单元开始,读取一条指令并执行。

IP执行完当前指令后会自动移到下一条指令的位置。如果当前指令是3个字节那就加3,如果是两个字节就加2。

8086CPU工作过程:

  1. 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
  2. IP = IP+所读取的指令的长度, 从而指向下一条指令
  3. 执行指令。转到步骤1,重复这个过程

在8086CPU加电启动或复位,CS = FFFFH,IP = 0000H,FFFF0H是开机后的第一条指令。

CPU将CS、IP中的内容当作指令的段地址和偏移地址

修改CS、IP

程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令。

jmp 段地址:偏移地址 

用指令中给出的段地址修改CS,偏移地址修改IP

jmp 偏移地址

改变IP

CPU只认被CS:IP指向的内存单元中的内容为指令。

检测: 检测点2.3

实验1

第三章:寄存器(内存访问)

第二章从CPU如何执行指令的角度讲解了8086CPU的逻辑结构、形成物理地址的方法、相关寄存器以及一些指令。

这一章从访问内存角度学习寄存器。

内存中的存储

数据和程序在内存中,都是二进制文件,能访问的地址也就是一个字节,用16进制来表示。CPU中,用16位寄存器来存储一个字,高8位存放高字节,低8位放低字节。
《汇编语言》——王爽第三版笔记(1-3章)

《汇编语言》——王爽第三版笔记(1-3章)

上图的0,1,2,3……就是能访问到的地址,用16进制来表示一个字节,比如20H,4EH等等。

由于内存单元是字节单元,则一个字就要用两个连续的内存单元来存。图中0、1两个内存单元存放数据4E20H,0是低地址单元,1是高地址单元。

:字单元:存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成,高地址内存单元中存放字型数据的高位字节,低地址内存单元存放字型数据的低位字节。

以起始地址为N的字单元简称N地址字单元。

DS和address

CPU要读写一个内存单元时,必须先给出这个内存单元的地址,在8086PC中,内存地址由段地址和偏移地址组成。

8086CPU中有一个DS寄存器用于存放段地址(注意DS寄存器也应该是16位的,不是20位的)

mov bx, 1000H
mov ds, bx
mov al, [0]
//将1000:0中的数据读到al中

为什么不能是

mov ds 1000H

因为8086CPU不支持将数据直接送入段寄存器(设计缺陷)

传送多少的数据是由最后的通用寄存器决定的,如果是ax、bx就传16位,最大也就只能传16位,而如果是al、ah,那就传送8位。

字的传送

8086CPU是16位结构,一次传送16位数据。

mov bx, 1000H
mov ds, bx
mov ax, [0]
mov [0], cx

16进制数一个数字代表四个二制数,4个数就是16个二进制数,也就是16位。

高位在高地址,低位在低地址

mov、add、sub指令

  1. mov 指令可以对寄存器,数据,内存单元之间的随意赋值
  2. add、sub指令不可以用于段寄存器(以s结尾的寄存器segment)

数据段

可以将一组长度为N<=64KB、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间。

ds中存放数据段的段地址,再自己根据需要访问段中的单元。

栈是一个存储空间,据有特殊的访问方式。先进后出,First in last out

由图形来看的话就也是一段空间,如下图,但是注意这段空间高地址在下面,低地址在上面。

《汇编语言》——王爽第三版笔记(1-3章)

检测: 检测点3.1

CPU提供的栈机制

ss:sp在任意时刻都指向栈顶元素,push入栈,pop出栈

在刚开始时,栈的长度是sp所决定的,ss为段地址,也就是低地址,在图上来说就是在上方,而sp始终指向栈顶,当栈为空时,栈顶应该在栈的最底部的下面。也就是最高地址的后面。按上图10000H~1000FH来说,ss=1000H,sp=10H。长度就是16byte。

栈顶越界问题

如果一直push肯定总有一天会满栈然后越界,如果一直pop,肯定总有一天会空栈然后也越界。要求编程人员自己注意。

push、pop指令

  • push
push 寄存器 将寄存器中的数据入栈
  1. sp = sp-2,先让sp指向当前栈顶前面的单元,也就是将要送入数据的单元
  2. 将寄存器中的内容送入ss:sp指向的内存单元,此时ss:sp就指向新栈顶
  • pop
pop 寄存器 将栈中的数据送入寄存器
  1. 将ss:sp指向的内存单元中的数据送入到寄存器中

  2. sp = sp+2,让sp指向当前栈顶下面的内存单元,以这个单元为新的栈顶

8086CPU是16位的CPU,所以一次操作16位二进制数据,也就是4位16进制数据。一个内存单元中的数据是一个字节,也就是8位数据,在push和pop时,一次改变两个内存单元。

栈段

栈段就是当作栈来使用的一段空间。显然sp<=64KB(ffff),所以栈段最大不超过64KB

比如 10010H~1001FH,这是一个16字节的内存单元。

检测: 检测点3.2

相关标签: 汇编 汇编语言