令人敬畏的汇编,狠人才能学得会

文章目录

引言

  • 汇编语言是直接在硬件之上工作的编程语言,首先要了解硬件系统的结构,才能有效的应用汇编语言对其编程。
  • 汇编课程的研究重点放在如何利用硬件系统的编程结构和指令集有效灵活的控制系统进行工作。

第一章 基础知识

1.1 机器语言

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

1.2 汇编语言的产生

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

机器指令:1000100111011000
操作:寄存器BX的内容送到AX中
汇编指令:MOV AX,BX
汇编这样的写法与人类语言接近,便于阅读和记忆。

  • 寄存器:简单的讲是CPU中可以存储数据的器件。
    AX,BX是其中的一个寄存器的代号

1.3 汇编语言的组成

  • 汇编语言由以下3类组成:
    • 汇编指令(机器码的助记符)
    • 伪指令(由编译器执行)
    • 其它符号
  • 汇编语言的核心是汇编指令,它决定了汇编语言的特性

1.4 存储器

  • CPU 是计算机的核心部件,它控制整个计算机的运作并进行运算,要想让一个CPU工作,就必须向它提供指令和数据
  • 指令和数据在存储器中存放,也就是平时所说的内存
  • 在一台PC机中内存的作用仅次于CPU
  • 离开了内存,性能再好的CPU也无法工作
  • 磁盘不同于内存,磁盘上的数据或程序如果不读到内存中,就无法被CPU使用

1.5 指令和数据

  • 指令和数据是应用上的概念
  • 在内存或磁盘上,指令和数据没有任何区别,都是二进制信息

二进制信息:1000100111011000------>89D8H(数据)
------->MOV AX,BX(程序)

1.6 存储单元

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

例如:一个存储器有128个存储单元,编号从0-127。

  • 对于大容量的存储器一般还用以下单位来计量容量(以下用B来代表Byte):
    • 1KB=1024B
    • 1MB=1024KB
    • 1GM=1024MB
    • 1TB=1024GB

磁盘的容量单位同内存的一样,实际上以上单位是微机中常用的计量单位。

1.7 CPU对存储器的读写

  • CPU要想进行数据的读写,必须和外部器件(标准说法是芯片)进行三类信息的交互
    1. 存储单元的地址(地址信息)
    2. 器件的选择,读或写命令(控制信息)
    3. 读或写的数据(数据信息)

那么CPU是通过什么将地址、数据和控制信息传到存储芯片中的呢?

  • 电子计算机能处理、传输的信息都是电信号,电信号当然要用导线传送
  • 在计算机中专门有连接CPU和其它芯片的导线,通常称为总线
    • 物理上:一根根导线的集合
    • 逻辑上划分为:地址总线、数据总线、控制总线

1.8 地址总线

对于8086CPU,下面的机器码能够完成从3号单元读数据:

  • 机器码:101000000000001100000000
  • CPU是通过地址总线来指定存储单元的
  • 地址总线上能传送多少个不同的信息,CPU就可以对多少个存储单元进行寻址
  • 一个CPU有N根地址总线,则可以说这个CPU的地址总线宽度为N
  • 这样的CPU最多可以寻找2N个内存单元

1.9 数据总线

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

1.10 控制总线

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

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

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

1.11 内存地址空间(概述)

什么是内存地址空间?

  • 一个CPU的地址线宽度为10,那么可以寻址1024个内存单元,这1024个可寻到的内存单元就构成这个CPU的内存地址空间

1.12 主板

  • 在每一台PC机中,都有一个主板,主板上有核心器件和一些主要器件。
  • 这些器件通过总线(地址总线、数据总线、控制总线)相连

1.13 接口卡

  • 计算机系统中所有可用程序控制其工作的设备,必须受到CPU的控制
  • CPU对外部设备不能直接控制,如显示器、音响、打印机等。直接控制这些设备进行工作的是扩展插槽上的接口卡。

1.14 各类存储器芯片

  • 从读写属性上看分为两类:随机存储器(RAM)和只读存储器(ROM)
  • 从功能和连接上分类:
    • 随机存储器RAM
    • 装有BIOS的ROM
      BIOS:Basic Input/Output System,基本输入输出系统
      BIOS是由主板和各类接口卡(如:显卡、网卡等)厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的输入输出。在主板和某些接口卡上插有存储相应BIOS的ROM
    • 接口卡上的RAM

1.15 内存地址空间(详解)

上述器件都有以下两点相同:

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

将各类存储器看作一个逻辑存储器:

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

不同的计算机系统的内存地址空间分配情况是不同的

内存地址空间:

  • 最终运行程序的是CPU,我们用汇编编程的时候,必须要从CPU角度考虑问题
  • 对CPU来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受CPU寻址能力的限制。这个逻辑存储器即是我们所说的内存地址空间。

小结

  1. 汇编指令是机器指令的助记符,同机器指令一一对应。
  2. 每一种CPU都有自己的汇编指令集。
  3. CPU可以直接使用的信息在存储器中存放。
  4. 在存储器中指令和数据没有任何区别,都是二进制信息。
  5. 存储单元从零开始顺序编号
  6. 一个存储单元可以存储8个bit(用作单位写成"b"),即8位二进制数
  7. 1B=8b 1KB=1024B 1MB=1024KB 1GB=1024MB
  8. 每一个CPU芯片都有许多管脚,这些管脚和总线相连。也可以说,这些管脚引出总线。一个CPU可以引出三种总线的宽度标志了这个CPU的不同方面的性能:1、地址总线的宽度决定了CPU的寻址能力; 2、数据总线的宽度决定了CPU与其它器件进行数据传送时的一次数据传送量; 3、控制总线宽度决定了CPU对系统中其它器件的控制能力。

第二章 寄存器(CPU工作原理)

2.1 通用寄存器

CPU概述
一个典型的CPU由运算器、控制器、寄存器等器件组成,这些器件靠内部总线相连。
区别
内部总线实现CPU内部各个器件之间的联系。
外部总系实现CPU和主板上其它器件的联系。

寄存器概述
8086CPU有14个寄存器,它们的名称为:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
8086CPU所有的寄存器都是16位的,可以存放两个字节。
AX、BX、CX、DX通常用来存放一般性数据被称为通用寄存器

2.2 字在寄存器中的存储

一个字可以存在一个16位寄存器中,这个字的高位字节和地位字节自然就存在这个寄存器的高8位寄存器和低8位寄存器中。
关于数制的讨论

  • 由于一个内存单元可以存放8位数据,CPU中的寄存器又可以存放n个8位数据也就是说,计算机中的数据大多是由1~N个8位数据构成。
  • 用十六进制来表示数据可以直观的看出这个数据是由哪些8位数据构成的。每两位对应一个八进制!

2.3 几条汇编指令

汇编指令不区分大小写。

汇编指令 控制CPU完成的操作 用高级语言的语法描述
mov ax,18 将18送入AX AX=18
mov ah,78 将78送入AH AH=78
add ax,8 将寄存器AX中的数值加上8 AX=AX+8
mov ax,bx 将寄存器BX中的数据送入寄存器AX AX=BX
add ax,bx 将AX,BX中的内容相加,结果存在AX中 AX=AX+BX

2.4 物理地址

  • CPU访问内存单元时要给出内存单元的地址。所有的内存单元构成的存储空间是一个一维的线性空间。
  • 我们将这个唯一的地址称为物理地址。

2.5 16位架构CPU

  • 概括的讲,16位结构描述了一个CPU具有以下几个方面特征:
  1. 运算器一次最多可以处理16位的数据
  2. 寄存器的最大宽度为16位
  3. 寄存器和运算器之间的通路是16位的

2.6 8086CPU给出物理地址的方法

  • 8086有20位地址总线,可传送20位地址,寻址能力为1M。
  • 8086内部为16位结构,它只能传送16位的地址,表现出的寻址能力却只有64K(216=64K)。
  • 8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

2.7 “段地址X16+偏移地址=物理地址”的本质含义

“段地址X16”有一个更为常用的说法就是数据左移4位。(二进制位)
把十六进制的数乘于16就相当于左移一位。

2.8 段的概念

错误的认识:
内存被划分成了一个一个的段,每一个段有一个段地址。
其实:
内存并没有分段,段的划分来自于CPU,由于8086CPU用“段地址X16+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。

以后,在编程时可以根据需要,将若干地址连续的单元看作一个段,用段地址X16定位的起始地址(基础地址),用偏移地址定位段中的内存单元。

两点需要注意

  1. 段地址X16必然是16的倍数,所以一个段的起始地址也一定是16的倍数;
  2. 偏移地址为16位,16位地址的寻址能力为64K,所以一个段的长度最大为64K。

内存单元地址小结

  • CPU访问内存单元时,必须向内存提供内存单元的物理地址
  • 8086CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址。

在8086PC机中,存储单元的地址用两个元素来描述,即段地址和偏移地址。
“数据在21F60H内存单元中。”对于8086PC机的两种描述:

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

可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段。

2.9 段寄存器

段寄存器就是提供段地址的。
8086CPU有4个段寄存器:CS、DS、SS、ES
当8086CPU要访问内存时,由这4个段寄存器提供内存单元的段地址。

2.10 CS和IP

CS和IP是8086CPU中最关键的寄存器,它们指示了CPU当前要读取指令的地址。
CS为代码段寄存器
IP为指令寄存器

  • 在8086CPU加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=FFFFH,IP=0000H
  • 即在8086PC机刚启动时,CPU从内存FFFF0H单元中读取指令执行。
  • FFFF0H单元中的指令是8086PC机开机后执行的第一条指令
  • 在任何时候,CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。
  • 如果说,内存中的一段信息曾被CPU执行过的话,那么,它所在的内存单元必然被CS:IP指向过。

2.11 修改CS、IP的指令

  • 在CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制。
  • CPU从何处执行指令是由CS、IP中的内容决定的,程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令。

mov指令可以改变8086CPU大部分寄存器的值,被称为传送指令。
但是mov指令不能用于设置CS、IP的值,8086CPU没有提供这样的功能。

8086CPU为CS、IP提供了另外的指令来改变它们的值:转移指令
转移指令
同时修改CS、IP的内容:
jmp 段地址 :偏移地址
jmp 2AE3:3
jmp 3:0B16
功能:用指令中给出的段地址修改CS,偏移地址修改IP。

2.12 代码段

  • 对于8086PC机,在编程时,可以根据需要,将一组内存单元定义为一个段。
  • 可以将长度为N(N<=64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,这段内存是用来存放代码的从而定义了一个代码段。
  • 将一段内存当作代码段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就自动地将我们定义得代码段中的指令当作指令来执行。
  • CPU只认被CS:IP指向的内存单元中的内容为指令

小结

段地址在8086CPU的寄存器中存放。当8086CPU要访问内存时,由寄存器提供内存单元的段地址。8086CPU有4个段寄存器,其中CS用来存放指令的段地址。
CS存放指令的段地址,IP存放指令的偏移地址。
8086机中,任意时刻,CPU将CS:IP指向的内容当做指令执行。

8086CPU的工作过程:

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

8086CPU提供转移指令修改CS、IP的内容。jmp

DEBUG

在win10要下载其它文件才能使用,所以我开了台win7的虚拟机来测试。

  • R命令查看、改变CPU寄存器的内容;
  • D命令查看内存中的内容;
  • E命令改写内存中的内容;
  • U命令将内存中的机器指令翻译成汇编指令;
  • T命令执行一条机器指令;
  • A命令以汇编指令的格式在内存中写入一条机器指令;
    在这里插入图片描述
    书中的实验 mov ax,1
    add ax,ax
    jmp 2000:0003
    在这里插入图片描述

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

3.1 内存中字的存储

任何两个地址连续的内存单元,N号单元和N+1号单元,可以将它们看成两个内存单元,也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。

3.2 DS和[address]

  • CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址;
  • 在8086CPU中,内存地址由段地址和偏移地址组成。
  • 8086CPU中有一个DS寄存器,通常用来存放要访问的数据的段地址。

mov al,[0]
已知的mov指令可完成的两种传送功能:

  1. 将数据直接送入寄存器;
  2. 将一个寄存器中的内容送入另一个寄存器中。

除此之外,mov指令还可以将一个内存单元中的内容送入一个寄存器。

将内存单元送到寄存器中mov指令的格式:
mov 寄存器名,内存单元地址
“[…]”表示一个内存单元,“[…]”中的0表示内存单元的偏移地址。

主要过程:数据==》通用寄存器==》段寄存器

3.3 字的传送

因为8086CPU是16位结构,有16根数据线,所以,可以一次性传送16位的数据,也就是一次性传送一个字。

3.4 mov、add、sub指令

已学mov指令的几种形式:
mov 寄存器,数据
mov 寄存器,寄存器
mov 寄存器,内存单元
mov 内存单元,寄存器
mov 段寄存器,寄存器

add、sub和mov指令一样,都有两个操作对象

3.5 数据段

我们可以将一组长度为N(N<=64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。

将一段内存当作数据段,是我们在编程时的一种安排,我们可以在具体操作的时候,用DS存放数据段的段地址,再根据需要,用相关指令访问数据段中的具体单元。

小结

  • 字在内存中存储时,要用两个地址连续的内存单元存放,字的低位字节存放在低地址单元中,高位字节存放再高地址单元中
  • 用mov指令要访问单元,可以在mov指令中给出单元的偏移地址,此时,段地址默认在DS寄存器中
  • [address]表示一个偏移地址为address的内存单元
  • 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器、低地址单元和低8位寄存器相对应
  • mov、add、sub是具有两个操作对象的指令。jmp是具有一个操作对象的指令
  • 可以根据自己的推测,在Debug中实验的新格式,winxp有,win10要装插件

3.6 栈

栈是一种具有特殊的访问方式的存储空间。它的特殊性就在于,最后进入这个空间的数据,最先出去。
入栈和出栈
LIFO,Last In First Out

3.7 CPU提供的栈机制

现今CPU中都有栈设计

指令:
PUSH
POP

寄存器CS和IP中存放着当前指令的段地址和偏移地址。
8086CPU中有两个寄存器,段寄存器SS:存放栈顶的段地址
寄存器SP:存放栈顶的偏移地址
任意时刻,SS:SP指向栈顶元素。

任意时刻,SS:SP指向栈顶元素,当栈为空的时候,栈中没有元素,也就不存在栈顶元素
所以SS:SP只能指向栈的最低部单元下面的单元,该单元的偏移地址为栈最底部的字单元的偏移地址+2
栈最底部字单元的地址为1000:000E,所以栈空时SP=0010H。

3.8 栈顶超界的问题

栈顶超界是危险的

8076CPU的工作原理,只考虑当前的情况:

  • 当前栈顶在何处
  • 当前要执行的指令是哪一条

3.9 push、pop指令

push和pop指令是可以在寄存器和内存之间传送数据的。
push、pop等栈操作指令,修改的只是SP。也就是栈顶的变化范围最大为:0~FFFFH
SS、SP指栈顶;改变SP后写内存的入栈指令;读内存后改变SP的出栈指令。
这就是8086CPU提供的栈操作机制。
用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
PUSH、POP实质上是一种内存传送指令,注意它们的灵活运用。

3.10 栈段

跟数据段一样,栈段。

将一段内存当作栈段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就在执行push、pop等栈操作指令时就自动地将我们定义的栈段当作栈空间来访问。

  • 栈为空,就相当于栈中唯一的元素出栈,出栈后,SP=SP+2。
  • SP原来为FFFEH,加2后SP=0,所以,当栈为空的时候,SS=1000H,SP=0。

不管我们如何安排,CPU将内存中的某段内存当作栈,是因为CS:IP指向那里;CPU将某段内存当作栈,是因为SS:IP指向了那里。
要非常的清楚CPU的工作机理,才能控制CPU来按照我们的安排,运行的时候做到游刃有余。
一段内存,可以既是代码的存储空间,又是数据空间,还可以是栈空间,也可以什么也不是。


第四章 第一个程序

一个源程序从写出到执行的过程

编写==》编译连接==》执行

源程序

  • 汇编指令
    • 有对应的机器码的指令,可以被编译为机器指令,最终为CPU所执行。
  • 伪指令
    • 伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作

定义一个段

segment和ends是一对成对使用的伪指令,这是在写可被编译器编译的汇编程序时,必须要用到的一对伪指令。

segment和ends的功能是定义一个段,segment说明一个段开始,ends说明一个段结束。

一个段必须有一个名称来标识,使用格式为:
段名 segment
段名 ends

一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。

一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。

End

End是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了伪指令end,就结束对源程序的编译。

如果程序写完了,要在结尾处加上伪指令end。否则,编译器在编译程序时,无法知道程序在何处结束。

切记不要把end和ends搞错

assume

含义为假设,它假设某一段寄存器和程序中的某一个用segment…ends定义的段相关联。

通过assume说明这种关系,在需要的情况下,编译程序可以将段寄存器和某一个具体的段相联系。

源程序中的“程序”

汇编源程序:伪指令(编译器处理)、汇编指令(编译为机器码)
程序:源程序中最终由计算机执行、处理的指令或数据

注意:我们可以将源程序文件中的所有内容称为源程序,将源程序中最终由计算机执行处理的指令或数据,称为程序。
程序最先以汇编指令的形式存在源程序中经过编译、连接后转变为机器码,存储在可执行文件中。

标号

  • 一个标号指代了一个地址
  • codesg:放在segment的前面,作为一个段的名称,这个段的名称最终将被编译、连接程序处理为一个段的段地址

DOS中的程序运行

DOS是一个单任务操作系统。

  • 一个程序P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载如内存后,将CPU的控制权交给P2,P2才得以运行。P2开始运行后,P1暂停运行。
  • 而当P2运行完毕后,应该将CPU的控制权交还给使它得以运行的程序P1,此后,P1继续运行。
    程序返回
    一个程序结束后,将CPU的控制权交还给使它得以运行的程序,我们称这个过程为:程序返回

编译 and 连接

连接的作用:

  • 当程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件;

  • 程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生产的目标文件连接到一起,生成一个可执行文件;

    编辑器(Edit)、编译器(masm)、连接器(link)、调试工具(debug)等工具

可执行文件中的程序装入内存并行的原理

  • 一个程序P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载如内存后,将CPU的控制权交给P2,P2才得以运行。P2开始运行后,P1暂停运行。
  • 而当P2运行完毕后,应该将CPU的控制权交还给使它得以运行的程序P1,此后,P1继续运行。

程序执行的跟踪

操作系统的外壳

操作系统是由多个功能模块组成的庞大、复杂的软件系统。任何同用的操作系统,都要提供一个称为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统工作。

第五章 [BX]和loop指令

[bx]

我们要完整地描述一个内存单元,需要两种信息:

  1. 内存单元地地址
  2. 内存单元地长度(类型)

我们用[0]表示一个内存单元时,0表示单元的偏移地址,段地址默认在ds中,单元的长度(类型)可以由具体指令中的其它操作对象(比如说寄存器)指出,如前边的AX,AL。

[bx]同样也表示一个内存单元,它的偏移地址在bx中。

Loop指令

指令的格式是:loop标号,CPU执行loop指令的时候,要进行两步操作:

  1. [cx]=[cx]-1
  2. 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行

计算22,结果存放在ax中。

assume cs:code
code segment
start:	mov ax,2
	add ax,ax

	mov ax,4c00h
	int 21h
code ends
end start

计算23

assume cs:code
code segment
start:	mov ax,2
	add ax,ax
	add ax,ax

	mov ax,4c00h
	int 21h
code ends
end start

计算212,使用loop简化代码

assume cs:code
code segment
start:	mov ax,2
	mov cx,11
	s: add ax,ax
	loop s

	mov ax,4c00h
	int 21h
code ends
end start

分析s为标号,它表示了一个地址,指令的格式是:loop标号,CPU执行loop指令的时候,要进行两步操作:

  1. [cx]=[cx]-1
  2. 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行

总结

  1. 在cx中存放循环次数
  2. loop指令中的标号所标识地址要在前面
  3. 要循环执行的程序段,要写在标号和loop指令的中间

框架如下:
mov cx,循环次数
s: 循环执行的代码段
loop s

注意

  • 在汇编源程序中,数据不能以字母开头,所以要在前面加0
  • [bx]的作用:作为偏移地址与DS配合
  • loop和cx合作

一段安全的空间

在8086模式中,随意向一段内存空间写入内容是很危险的,因为这段空间中可能存放着重要的系统数据或代码

我们在纯DOS方式(实模式)下,可以不理会DOS,直接用汇编语言去操作真实的硬件,因为运行在CPU实模式下的DOS,没有能力对硬件系统进行全面而严格的管理。
但在Windows XP\2000、UNIX这些于CPU保护模式下的操作系统中,不理会操作系统,用汇编语言去操作真实的硬件,是根本不可能的。

硬件已被这些操作系统利用CPU保护模式所提供的功能全面而严格地管理。
在一般地PC机中,DOS方式下,DOS和其它合法程序一般都不会使用0:200~0:2FF的256个字节的空间。所以,我们使用这段空间是安全的

以下总结:

  • 我们需要直接向一段内存中写入内容
  • 这段内容不应该存放系统或其它程序的数据或代码,否则写入操作很可能引发错误。
  • DOS方式下,一般情况,0:200~0:2FF空间中没有系统或其它程序的数据或代码
  • 以后,我们需要直接向一段内存中写入内容时,就使用0:200~0:2FF这段空间

第六章 包含多个段的程序

在代码段中使用数据

  • dw是定义字型数据。dw即define word。
  • end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。

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

8086CPU不允许将一个数值直接送入段寄存器中。
mov ds,data中的data将被编译器处理为一个表示段地址的数值。

我们在源程序的最后用“end start”说明了程序的入口,这个入口将被写入可执行文件的描述信息,可执行文件中的程序被加载入内存后,CPU的CS:IP被设置指向这个入口,从而开始执行程序中的第一条指令。

标号“start”在code段中,这样CPU就将code段中的内容当作指令来执行了。

第七章 更灵活的定位内存地址的方法

and和or指令

and指令:逻辑与指令,按位进行与运算。
如 :
mov al,01100011B
and al,00111011B
执行后:al = 00100011B

通过该指令可将操作对象的相应位设为0,其它位不变。
例如:
将al的第6位设为0:and al, 10111111B
将al的第7位设为0:and al, 01111111B
将al的第0位设为0:and al, 11111110B

or指令:逻辑或指令,按位进行或运算。

mov al,01100011B
and al,00111011B
执行后:al = 01111011B
可以通过该指令将操作对象的相应为设为1,其它位不变。
例如:
将al的第6位设为1:and al, 0100000B
将al的第7位设为1:and al, 1000000B
将al的第0位设为1:and al, 0000001B

关于ASCII码

世界上有很多编码方案,有种方案叫做ASCII编码,是在计算机系统中通常被采用的,utf-8也是。
简单地说,所谓编码方案,就是一套规则,它约定了用什么样地信息来表示现实对象。

大小写转换的问题

大写字母ASCII码的第六位为0,小写字母的第六位为1

[bx+idata]

[bx+idata]表示一个内存单元,它的偏移地址为[bx]+idata(bx中的数值加上idata)

用[bx+idata]的方式进行数组的处理

C/C++等高级语言定位方式:a[i],b[i]
汇编语言定位方式:0[bx],5[bx]

SI和DI

SI和DI是8086CPU中和bx功能相近的寄存器,但是SI和DI不能分成两个8为寄存器来使用。

[bx+si]和[bx+di]

这两个表示一个内存单元,它的偏移地址为[bx]+[si](di),也就是bx中的数值加上si(di)中的数值

[bx+si+idata]和[bx+di+idata]

都表示一个内存单元,它的偏移地址为[bx]+[si]+idata,原理同上

不同的寻址方式的灵活应用

  • [idata]用一个常量来表示地址,可用于直接定位一个内存单元
  • [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元
  • [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元
  • [bx+si]用两个表示地址
  • [bx+si+idata]用两个变量和一个常量表示地址。

第八章 数据处理的两个基本问题

bx、si、di、bp

在8086CPU中只有这4个寄存器(bx、bp、si、di)可以用在“[…]”中进行内存单元的寻址。

在“[…]”中,这四个可以单独出现,或只能以四种组合出现
bx和si、bx和di、bp和si、bp和di

只要在“[…]”中使用寄存器bp,而指令中没有显性的给出段地址,段地址就默认在ss中。

机器指令处理的数据所在的位置

指令在执行前,所要处理的数据可以在三个地方:CPU内部、内存、端口

汇编语言中用三个概念来表达数据的位置。

  1. 立即数
  2. 寄存器
  3. 段地址(SA)和偏移地址(EA)

立即数,是指直接包含在机器指令中的数据(执行前在CPU的指令缓冲器中),在汇编语言中称为:立即数(idata),在汇编指令中直接给出。

寄存器,指令要处理的数据在寄存器中,在汇编指令中给出相应的寄存器名。

段地址(SA)和偏移地址(EA),指令要处理的数据在内存中,在汇编指令中可用[x]的格式给出EA,SA在某个段寄存器中。
存放段地址的寄存器可以是默认的
也可以是显性的给出

寻址方式

  • 直接寻址
  • 寄存器间接寻址
  • 寄存器相对寻址
  • 基址变址寻址
  • 相对基址变址寻址

指令要处理的数据

8086CPU的指令,可以处理两种尺寸的数据,byte和word。所以在机器指令中要指明,指令进行的是字操作还是字节操作。

寻址方式的综合应用

一般来说,我们可以用[bx+idata+si]的方式来访问结构体中的数据。用bx来定位整个结构体,用idata定位结构体中的某一个数据项,用si定位数组项中的每一个元素。为此,汇编语言提供了更为贴切的书写方式。

div指令

是除法指令(division),使用div作除法的时候:
除数:8位或16位,在寄存器或内存单元中
被除数:(默认)放在AX或DX和AX中

除数 被除数
8位 16位(AX)
16位 32位(DX+AX)

伪指令 dd

dd是用来定义dword(double word双字)型数据的

dup

是一个操作符,在汇编语言中同db、dw、dd等一样,也是由编译器识别处理的符号。
它是和db、dw、dd等数据定义伪指令配合使用的,用来进行数据的重复。

第九章 转移指令的原理

操作符offset

8086CPU的转移指令分为以下几类:

  • 无条件转移指令(如:jmp)
  • 条件转移指令
  • 循环指令(如:loop)
  • 过程
  • 中断

操作符offset在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址。

jmp指令

无条件转移,可以只修改IP,也可以同时修改CS和IP。

jmp指令要给出两种信息:

  • 转移的目的地址
  • 转移的距离(段间转移、段内转短移,段内近转移)

jmp short 标号
这种指令格式是段内短转移,它对IP的修改范围为-128~127,也就是说,它向前转移时可以最多越过128个字节,向后转移可以最多越过127个字节。

转移的目的地址在指令中的jmp指令

指令“jmp far ptr”实现的是段间转移,又称为远转移

转移地址在内存中的jmp指令

jmp dword ptr 内存单元地址(段间转移)

jcxz指令

为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址,对IP的修改范围都为-128~127

指令格式:jcxz 标号

loop指令

为循环指令,所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。

对IP的修改范围都为-128~127

指令格式:loop 标号

待续待续

原创文章 42 获赞 38 访问量 8761

猜你喜欢

转载自blog.csdn.net/weixin_44350891/article/details/105452471