二、寄存器

水滴石穿

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

内部总线实现CPU内部各个器件之间的联系,外部总线实现CPU和主板上其他器件的联系

简单说,在CPU中:

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

对于一个汇编程序员来说,CPU的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。

程序员可以通过改变各种寄存器中的内容来实现对CPU的控制。

不同的CPU,寄存器个数、结构是不相同的。

8086CPU有14个寄存器,每个寄存器都有一个名称。

分别是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、PSW

2.1 通用寄存器

  • 8086CPU的所有寄存器都是16位的,可以存放两个字节

  • AX、BX、CX、DX这四个寄存器通常用来存放一些一般性的数据,被称为通用寄存器

  • 8086CPU的上一代CPU中的寄存器都是8位的,为了保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上

  • 8086CPU的AX、BX、CX、DX这四个寄存器都可以分为两个独立使用的8位寄存器来用:

    • AX可分为AH和AL;
    • BX可分为BH和BL;
    • CX可分为CH和CL;
    • DX可分为DH和DL;
  • AX的低8位(0位~7位)构成了AL寄存器

  • AX的高8位(8位~15位)构成了AH寄存器

  • AH和AL寄存器是可以独立使用的8位寄存器

2.2 字在寄存器中的存储

出于对兼容性的考虑,8086CPU可以一次性处理以下两种尺寸的数据

  • 字节:记为Byte,一个字节有8个bit组成,可以存在8位寄存器中
  • 字:记为word,一个字由两个字节组成,这两个字节分别称为这个字的高位字节低位字节

例如:一个字型数据20000(4E20H)存放在AX寄存器中

  • 高位字节AH寄存器中:78(4EH)

  • 低位字节AL寄存器中:32(20H)

2.3 几条汇编指令

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

写一条汇编指令或一个寄存器的名称时,不区分大小写

1、程序段中指令执行情况之一(原AX中的值:0000H,原BX中的值:0000H)

程序段中的指令指令执行后AX中的数据指令执行后BX中的数据
mov ax,4E20H4E20H0000H
add ax,1406H6226H0000H
mov bx,2000H6226H2000H
add ax, bx8226H2000H
mov bx,ax8226H8226H
add ax,bx?8226H
问题2.1 :16位寄存器高位溢出

指令执行后AX中的数据为多少?思考后看分析

044CH,由于AX物理结构决定只能容纳16位,因此高位溢出需要舍弃。

分析:程序段中的最后一条指令 add ax,bx,在执行前 ax和 bx中的数据都为 8226H,相加后所得的值为:1044CH,但是ax为16位存器,只能存放4位六进制的数据,所以最高位的1不能在ax中保存,ax中的数据为:044CH。

2、程序段中指令执行情况之二

程序段中的指令指令执行后AX中的数据指令执行后BX中的数据
mov al,001AH001AH0000H
mov bx,0026H001AH0026H
add al,bl0040H0026H
add ah,bl2640H0026H
add bh,al2640H4026H
mov ah,00040H4026H
add al,85H00C5H4026H
add al,93H?4026H
问题2.2:8位寄存器高位溢出

指令执行后AX中的数据为多少?思考后看分析

0058H,由于al是8位寄存器,进行的是8位运算,因此进位值不能在8位寄存器中保存。

分析:程序段中的最后一条指令 add al,93H,在执行前,al中的数据为C5H,相加后所得的值为:158H,但是al为8位寄存器,只能存放两位十六进制的数据,所以最高位的1丢失,ax中的数据为:0058H。(这里的丢失,指的是进位值不能在8位寄存器中保存,但是CPU并不真的丢弃这个进位值,关于这个问题,我们将在后面的课程中讨论。

注意,此时 al是作为一个独立的8位寄存器来使用的,和ah没有关系,CPU在执行这条指令时认为 ah和al是两个不相关的寄存器。不要错误地认为,诸如 add al,93H 的指令产生的进位会存储在ah中,add al,93H进行的是8位运算。
如果执行 add ax,93H,低8位的进位会存储在 ah中,CPU 在执行这条指令时认为只有一个 16 位寄存器 ax,进行的是 16位运算。指令 add ax,93H 执行后,ax 中的值为:0158H。此时,使用的寄存器是16位寄存器ax,add ax,93H相当于将ax中的16 位数据00c5H和另一个16位数据0093H相加,结果是16位的0158H。

**在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的,**例如:

mov ax bx
mov bx,cx
mov ax,18H
mov al,18H
add ax,bx
add ax20000

等都是正确的指令,而:

mov ax,bl     (在8位寄存器和16位寄存器之间传送数据)
mov bh ax     (在16位寄存器和8位寄存器之间传送数据)
mov al,20000  (8位寄存器最大可存放值为255的数据)
add al,100H   (将一个高于8位的数据加到一个8位寄存器中)

等都是错误的指令,错误的原因都是指令的两个操作对象的位数不一致。

检测点2.1

(1)写出每条汇编指令执行后相关寄存器中的值

汇编指令汇编指令执行后寄存器的值
mov ax,62627AX = F4A3H
mov ah,31HAX = 31A3H
mov al,23HAX = 3123H
add ax,axAX = 6246H
mov bx,826CHBX = 826CH
mov cx,axCX = 6246H
mov ax,bxAX = 826CH
add ax,bxAX = 04D8H
mov al,bhAX = 0482H
mov ah,blAX = 6C82H
add ah,ahAX = D882H
add al,6AX = D888H
add al,alAX = D810H
mov ax,cxAX = 6246H

(2)只能用目前学过的汇编指令,最多使用4条指令,编程计算2的4次方

mov ax,2
add ax,ax
add ax,ax
add ax,ax

2.4 物理地址

CPU访问内存单元时,要给出内存单元的地址。

所有内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址。

这个唯一的地址称为物理地址、

CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。

在CPU向地址总线发出物理地址之前,必须要在内部先形成这个物理地址。

不同CPU可以有不同形成物理地址的方式。

下面讨论8086CPU如何在内部形成内存单元的物理地址的

2.5 16位结构的CPU

概括地讲,16位结构(16位机、字长为16位等常见说法,与16位结构的含义相同)

描述了一个 CPU 具有下面几方面的结构特性:

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

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

内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放,对于16位 CPU,能一次性处理、传输、暂时存储16位的地址。

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

8086CPU有20位地址总线,可以传送20位地址,达到1MB寻址能力。

8086CPU是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。

从8086CPU的内部结构来看,如果将地址从内部简单地发出,那么它只能送出16位的地址,表现出的寻址能力只有 64KB。

8086CPU 采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。

8086CPU相关部件的逻辑结构

如图2.6所示,当8086CPU要读写内存时:

  • CPU 中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;
  • 段地址和偏移地址通过内部总线送入一个称为地址加法器的部件:
  • 地址加法器将两个16位地址合成为一个20位的物理地址;
  • 地址加法器通过内部总线将20位物理地址送入输入输出控制电路;
  • 输入输出控制电路将20位物理地址送上地址总线;
  • 20位物理地址被地址总线传送到存储器

物理地址 = 段地址X16 + 偏移地址

地址加法器的工作过程

2.7 地址加法的本质含义

“段地址x16+偏移地址=物理地址”的本质含义是:

  • CPU在访问内存时,用一个基础地址(段地址x16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
  • 更一般地说,8086CPU的这种寻址功能是“基础地址+偏移地址=物理地址”寻址模式的一种具体实现方案。8086CPU中,段地址x16可看作是基础地址。

2.8 段的概念

内存并没有分段,段的划分来自于CPU,由于8086CPU用“基础地址(段地址x16)+偏移地址=物理地址"的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。例如:数据段、代码段等由人为划分,逻辑上划分,有利于我们灵活编程。

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

有两点需要注意:段地址x16必然是16的倍数,所以一个段的起始地址也一定是16的倍数:偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的长度最大为64KB。

内存地址单元小结

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

(1)观察下表,思考一下有什么结论

物理地址段地址偏移地址
21F6H2000H1F60H
2100H0F60H
21F0H0060H
21F6H0000H
1F00H2F60H

结论:

CPU可以用不同的段地址和偏移地址形成同一个物理地址。

比如 CPU 要访问 21F60H 单元,则它给出的段地址 SA偏移地址 EA满足 SAX16+EA=21F60H 即可。

段地址:Segment Address

偏移地址:Offset Address

有效地址:Effective Address

(2) 如果给定一个段地址,仅通过变化偏移地址来进行寻址,最多可定位多少个内存单元?

结论:

偏移地址16位,变化范围为0-~FFFFH,仅用偏移地址来寻址最多可寻64KB个内存单元。
比如给定段地址1000H,用偏移地址寻址,CPU的寻址范围为:10000H~1FFFFH。

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

“数据在 21F60H内存单元中。”这句话对于8086PC机一般不这样讲,取而代之的是两种类似的说法:

  • ①数据存在内存2000:1F60单元中;
  • ②数据存在内存的2000H段中的1F60H单元中。

这两种描述都表示“数据在内存21F60H单元中”

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

检测点2.2

(1)给定段地址为 0001H,仅通过变化偏移地址寻址,CPU的寻址范围为 到 。

段地址x16 + 偏移地址

偏移地址范围:0~FFFFH

故CPU的寻址范围为00010H~1000FH

(2)有一数据存放在内存 20000H单元中,现给定段地址为 SA,若想用偏移地址寻到此单元。则 SA应满足的条件是:最小为 ,最大为 。

提示,反过来思考一下,当段地址给定为多少,CPU无论怎么变化偏移地址都无法寻到 20000H 单元?

偏移地址为最大值 FFFFH 时,段地址x16最小为20000H - FFFFH = 10001H,16进制右移1位,SA = 1001H

偏移地址为最小值 0H 时,段地址x16最大值为20000H,16进制右移1位,SA = 2000H

2.9 段寄存器

8086CPU在访问内存时,要由相关部件提供内存单元的段地址和偏移地址,送入地址加法器合成物理地址

段地址在8086CPU的段寄存器中存放

8086CPU有4个段寄存器:CS、DS、SS、ES

CS(Code Segment):代码段寄存器;

DS(Data Segment):数据段寄存器;

SS(Stack Segment):堆栈段寄存器;

ES(Extra Segment):附加段寄存器

2.10 CS和IP

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

在8086PC机中,任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU将从内存 Mx16+N 单元开始,读取一条指令并执行。
也可以这样表述:8086机中,任意时刻CPU将CS:IP指向的内容当作指令执行

指令执行流程:

  1. CPU根据CS:IP提供的基址和偏址(基址x16+偏址)在内存中读取到要执行的指令
  2. CS:IP中的内容送入地址加法器
  3. 地址加法器将物理地址送入输入输出控制电路
  4. 输入输出控制电路将物理地址送上地址总线
  5. 找到对应物理地址上的机器指令通过数据总线送入CPU
  6. 输入输出控制电路将机器指令送入指令缓冲器
  7. IP中的值自动增加(读取到一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令;读取指令多长,IP加上多少)
  8. 执行控制器执行指令

总结:

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

现在我们可以回到之前的问题上,在内存中,数据和指令都表现为二进制的形式,二者没有区别。

学习了CS:IP后,我们可以认为,CPU将CS:IP指向的内存单元中的内容看作指令。

因为任何情况下,CPU将CS、IP中的内容当做指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码,执行。

2.11 修改CS、IP的指令

在CPU中,程序员能够使用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制。

CPU从何处执行指令是由CS、IP中的内容决定的,程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令:转移指令。

例如:jmp指令

  1. **jmp 段地址:偏移地址 :**用指令中给出的段地址修改CS,偏移地址修改IP
  2. **jmp (某一合法)寄存器:**用寄存器中的值修改IP,jmp ax = mov IP,ax
问题2.3

在这里插入图片描述

分析:

(1)先找CS:IP指向的地址:CPU的初始状态CS=2000H,IP=0000H;指向20000H,取出指令B8 22 66(mov ax,6622H),IP=IP+3=0003H

(2)指令执行后,CS=2000H,IP=0003H;指向20003H,取出指令EA 03 00 00 10(jmp 1000:3),跳转到1000:3,CS=1000H,IP=0003H

(3)指令执行后,CS=1000H,IP=0003H;指向10003H,取出指令B8 00 00(mov ax,0000),IP=IP+3=0006H

(4)指令执行后,CS=1000H,IP=0006H;指向10006H,取出指令8B D8(mov bx,ax),IP=IP+2=0008H

(5)指令执行后,CS=1000H,IP=0008H;指向10008H,取出指令FF E3(jmp bx),IP=IP+2=000AH

(6)指令执行后,CS=1000H,IP=0000H;CPU从内存10000H处读取指令······

经分析后,可知指令执行序列为:

(1)mov ax,6622H

(2)jmp 1000:3

(3)mov ax,0000

(4)mov bx,ax

(5)jmp bx

(6)mov ax,0123H

(7)转到第3步执行

2.12 代码段

代码段是人为在逻辑上定义的,将一段内存地址视作为一个代码段

CPU并不能知道代码段,CPU只是按照CS:IP执行指令

小结

(1)段地址在8086CPU的段寄存器中存放。当8086CPU要访问内存时,由段寄存器提供内存单元的段地址。8086CPU有4个段寄存器,其中CS用来存放指令的段地址。
(2)CS存放指令的段地址,IP存放指令的偏移地址。
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。
(3)8086CPU的工作过程:
①从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
②IP指向下一条指令;
③ 执行指令。(转到步骤①,重复这个过程。)
(4)8086CPU提供转移指令修改CS、IP的内容。

检测点2.3

下面的3条指令执行后,CPU 几次修改 IP?都是在什么时候?最后IP中的值是多少?

mov ax,bx
sub ax,ax
jmp ax

分析:

(1)IP为初始状态,CS:IP指向第一条指令的位置:mov ax,bx

(2)指令执行完成后,IP=IP+3,CS:IP指向第二条指令的位置:sub ax,ax

(3)指令执行完成后,IP=IP+3,CS:IP指向第三条指令的位置:jmp ax

(4)指令执行完成后,IP=IP+2,IP=ax=0000H

实验一 查看CPU和内存

debug的安装

安装教程直接百度,大致分为两部分:dosbox和masm

自动挂载:在dosbox的dos-0.74-3.conf配置文件的末尾,加上

Mount C E:\dosbox\DOSBox-0.74-3\masm //masm路径下
C:

debug的命令

命令对应英文单词说明
RRegister查看/修改 CPU 寄存器的内容
DDump查看内存中的内容(十六进制转储)
EEnter改写内存中的内容(逐字节输入)
UUnassemble将机器指令反汇编成汇编指令(反编译)
TTrace单步执行一条机器指令(跟踪执行)
AAssemble以汇编格式在内存中写入机器指令(汇编)
PProceed执行子程序/循环直到返回(过程步进)

补充说明:

  • P (Proceed):用于执行 CALL、LOOP、INT 等指令时,直接运行完整个子程序/中断/循环并停在返回后的下一条指令(与 T 的单步区分)。
  • 历史背景:这些命令缩写源于 1980 年代的 DOS DEBUG 工具,至今仍在 x86 调试器(如 Turbo Debugger、GDB)中广泛使用。
1、R命令

用R命令修改寄存器AX中的内容

C:>>debug	//进入debug模式
-r	//查看CPU寄存器内容
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0100 NU UP EI PL NZ NA PO NC
073F:0100 0000 		 ADD    [BX+SI],AL 					   DS:0000=CD
-r ax //查看并修改AX寄存器内容,此时AX=0000
AX 0000
:1111
-r	//查看是否修改成功,此时AX=1111
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0100 NU UP EI PL NZ NA PO NC
073F:0100 0000 		 ADD    [BX+SI],AL 					   DS:0000=CD

用R命令修改寄存器CS和IP中的内容

-r ip	//修改IP寄存器的值
IP 0100
:200
-r
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=O73F IP=0200 NU UP EI PL NZ NA PO NC
073F:0100 0000 		 ADD    [BX+SI],AL 					   DS:0000=CD
-r cs	//修改CS寄存器的值
CS O73F
:0B39
-r
AX=1111 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=O73F ES=O73F SS=O73F CS=0B39 IP=0200 NU UP EI PL NZ NA PO NC
073F:0100 0000 		 ADD    [BX+SI],AL 					   DS:0000=CD
2、D命令

用D命令查看内存10000H处的内容,“d 段地址:偏移地址”

Debug会列出1000:0~1000:7F,从指定的内存单元开始的128个内存单元的内容

在这里插入图片描述

(1)中间部分是从指定地址开始的128个内存单元的内容

例如:地址1000:0的内存单元内容为72;

​ 地址1000:1的内存单元内容为64;

(2)左边部分是每行的起始地址

(3)右边是每个内存单元中的数据对应的可显示的ASCII码字符

“d 段地址:起始偏移地址 结尾偏移地址”

如:查看1000:0~1000:9的内容

“d 1000:0 9”

3、E命令

用E命令改写内存中的内容

(1)一次性改写:e 起始地址 数据 数据 数据 …

要将1000:0~1000:9单元中的内容分别写为0、1、2、3、4、5、6、7、8、9

用E命令修改从1000:0开始的10个单元的内容

C:>>debug	//进入debug模式
-d 1000:0 f
1000:0000  72 64 73 20 63 6F 6D 6D-65 6E 74 73 20 28 72 65 rds comments (re
-
-e 1000:0 0 1 2 3 4 5 6 7 8 9
-d 1000:0 f
1000:0000  00 01 02 03 04 05 06 07-08 09 74 73 20 28 72 65 ..........ts (re
-

(2)一个个改写:提问式填写

用E命令修改从1000:10开始的4个单元的内容

-d 1000:10 19
1000:0010  6D 61 72 6B 73 29 20 69-6E 20     marks> in
-e 1000:10
1000:0010  6D.0		61.1   72.2   6B.1C

填0就空格,填其他,直接改写

(3)直接写入字符: - e 地址 字符 字符…

C:>debug
-e 1000:0 1 'a' 2 'b' 3 'c'
-
-d 1000:0 f
1000:0000 01 61 02 62 03 63 00 00-00 00 00 00 00 00 00 00  .a.b.c............
-C:>debug
-e 1000:0 1 "a+b" 2 "c++" 3 "IBM"
-
-d 1000:0 f
1000:0000 01 61 02 62 03 63 2B 2B-03 49 42 4D 00 00 00 00  .a+b.c++.IBM.......
-
4、E、U、T命令结合

(1)写入汇编指令——E命令

练习:如何向内存中写入机器码呢?

我们可以用E命令将机器码写入内存,比如我们要从内存1000:0单位开始写入这样一段机器码:

机器码				  对应的汇编指令
b80100				 mov ax,0001
b90200				 mov cx,0002
01c8				 add ax,cxC:\>debug
-e 1000:0 b8 01 00 b9 02 00 01 c8
-

(2)查看汇编指令——U命令

C:\>debug
-e 1000:0 b8 01 00 b9 02 00 01 c8
-
-d 1000:0 1f //查看内存的内容,显示的是机器码
1000:0000 B8 01 00 B9 02 00 01 C8-03 49 42 4e 00 00 00 00 ..........IBM....
1000:0010 00 02 01 1C 00 00 00 00-00 00 00 00 00 00 00 00 .................-u 1000:0	//将内存中的机器码反汇编成汇编语言
1000:0000 B80100 	MOV 	AX,0001
1000:0003 B90200 	MOV 	CX,0002
1000:0006 01C8		ADD 	AX,CX
1000:0008 ...省略

(3)执行写入的汇编代码——T命令

  • 改CS:IP指向1000:0000
-r cs	//修改CS寄存器的值
CS 0B39
:1000
-
-r ip	//修改IP寄存器的值
IP 0100
:0
-r		//CS:IP成功指向1000:000
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0000 NU UP EI PL NZ NA PO NC
1000:0000 B80100 		 MOV    AX,0001	
  • -t 一步步追踪执行
-t 		//寄存器AX赋值为1,IP自动加3,上条指令的长度为3,CS:IP始终指向当前要执行的指令
AX=0001 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0003 NU UP EI PL NZ NA PO NC
1000:0003 B90200 		 MOV    CX,0002	
-t 		//寄存器BX赋值为2,IP自动加3,上条指令的长度为3
AX=0001 BX=0000 CX=0002 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0006 NU UP EI PL NZ NA PO NC
1000:0006 01C8 		 	 ADD    AX,CX
-t 		//寄存器AX赋值为3,IP自动加2,上条指令的长度为2
AX=0003 BX=0000 CX=0002 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=1000 IP=0008 NU UP EI PL NZ NA PO NC
1000:0008 40 		 	 INC    AX
5、A命令

在前面我们写入汇编指令时,是以机器码的形式写入,这明显不利于程序员进行编写汇编程序。

因此,这里可以引入A命令来帮助我们。

用A命令以汇编指令的形式在内存中写入机器指令。

C:\>debug
-a 1000:0
1000:0000	这里可以输入汇编指令,输入mov ax,1,按enter键继续
1000:0003	再按一次enter键结束
-示例:
-a 1000:0
1000:0000	mov ax,1
1000:0003	mov bx,2
1000:0006 	mov cx,3
1000:0009	add ax,bx
1000:000B 	add ax,cx
1000:000D 	add ax,ax
1000:000F	enter键退出
-
-u 1000:0 //查看汇编指令

实验任务

任务1

使用Debug,将下面的程序段写入内存,逐条执行,观察每条指令执行后CPU中相关寄存器中内容的变化。

机器码				  汇编指令
b8 20 4e			mov ax,4E20H
05 16 14			add ax,1416H
bb 00 20			mov bx,2000H
01 d8				add ax,bx
89 c3				mov bx,ax
01 d8				add ax,bx
b8 1a 00			mov ax,001AH
bb 26 00			mov bx,0026H
00 d8				add al,bl
00 dc				add ah,bl
00 c7				add bh, al
b4 00				mov ah,0
00 d8				add al,bl
04 9c				add al,9CH

提示,可用E命令和A命令以两种方式将指令写入内存。注意用T命令执行时,CS:IP 的指向。

(1)用dosbox写入汇编指令:从2000:0写入,-a写入,-u查看

-a 2000:0
2000:0000 mov ax,4E20
2000:0003 add ax,1416
2000:0006 mov bx,2000
2000:0009 add ax,bx
2000:000B mov bx,ax
2000:000D add ax,bx
2000:000F mov ax,001A
2000:0012 mov bx,0026
2000:0015 add al,bl
2000:0017 add ah,bl
2000:0019 add bh,al
2000:001B mov ah,0
2000:001D add al,bl
2000:001F add al,9C
-
-u 2000:0
2000:0000 	b8 20 4e			mov ax,4E20H
2000:0003 	05 16 14			add ax,1416H
2000:0006 	bb 00 20			mov bx,2000H
2000:0009	01 d8				add ax,bx
2000:000B	89 c3				mov bx,ax
2000:000D	01 d8				add ax,bx
2000:000F	b8 1a 00			mov ax,001AH
2000:0012	bb 26 00			mov bx,0026H
2000:0015	00 d8				add al,bl
2000:0017	00 dc				add ah,bl
2000:0019	00 c7				add bh, al
2000:001B	b4 00				mov ah,0
2000:001D	00 d8				add al,bl
2000:001F	04 9c				add al,9CH

(2)更改CS:IP指向2000:0000

-r cs	//修改CS寄存器的值2000
CS 1000
:2000
-
-r ip	//修改IP寄存器的值0000
IP 000F
:0
-r		//CS:IP成功指向2000:0000
AX=0000 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0000 NU UP EI PL NZ NA PO NC
2000:0000 B8204E			 MOV    AX,4E20	

(3)-t 追踪指令执行

-t		//寄存器AX赋值为4E20,IP自动加3,上条指令的长度为3,IP=0003
AX=4E20 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0003 NU UP EI PL NZ NA PO NC
2000:0003 051614			 ADD    AX,1416	-t		//寄存器AX+1416为6236,IP自动加3,上条指令的长度为3,IP=0006
AX=6236 BX=0000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0006 NU UP EI PL NZ NA PO NC
2000:0006 051614			 MOV    BX,2000	-t		//寄存器BX赋值为2000,IP自动加3,上条指令的长度为3,IP=0009
AX=6236 BX=2000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0009 NU UP EI PL NZ NA PO NC
2000:0009 01D8			 	 ADD    AX,BX	-t		//寄存器AX+2000为8236,IP自动加2,上条指令的长度为2,IP=000B
AX=8236 BX=2000 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000B NU UP EI PL NZ NA PO NC
2000:000B 89C3			 	 MOV    BX,AX	-t		//寄存器AX的内容复制到BX为8236,IP自动加3,上条指令的长度为3,IP=000D
AX=8236 BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000D NU UP EI PL NZ NA PO NC
2000:000D 01D8			 	 ADD    AX,BX-t		//寄存器BX的内容加到AX为046C,IP自动加2,上条指令的长度为2,IP=000F
AX=046C BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=000F NU UP EI PL NZ NA PO NC
2000:000F B81A00			 MOV    AX,001A-t		//寄存器AX赋值为为001A,IP自动加3,上条指令的长度为3,IP=0012
AX=001A BX=8236 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0012 NU UP EI PL NZ NA PO NC
2000:0012 B81A00			 MOV    BX,0026-t		//寄存器BX赋值为为0026,IP自动加3,上条指令的长度为3,IP=0015
AX=001A BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0015 NU UP EI PL NZ NA PO NC
2000:0015 00D8			 	ADD    AL,BL-t		//寄存器BX的低4位加到AX的低四位为26+1A=40,IP自动加2,上条指令的长度为2,IP=0017
AX=0040 BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0017 NU UP EI PL NZ NA PO NC
2000:0017 00DC			 	ADD    AH,BL-t		//寄存器BX的低4位加到AX的高四位为00+26=26,IP自动加2,上条指令的长度为2,IP=0019
AX=2640 BX=0026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0019 NU UP EI PL NZ NA PO NC
2000:0019 00C7			 	ADD    BH,AL-t		//寄存器AX的低4位加到BX的高四位为40+00=40,IP自动加2,上条指令的长度为2,IP=001B
AX=2640 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001B NU UP EI PL NZ NA PO NC
2000:001B B400			 	MOVE    AH,00-t		//寄存器AX的高4位赋值为00,IP自动加2,上条指令的长度为2,IP=001D
AX=0040 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001D NU UP EI PL NZ NA PO NC
2000:001D 00D8			 	ADD    AL,BL-t		//寄存器BX的低4位加到AX的低4位为26+40=66,IP自动加2,上条指令的长度为2,IP=001F
AX=0066 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=001F NU UP EI PL NZ NA PO NC
2000:001F 049C			 	ADD    AL,9C-t		//寄存器AX的低4位加上9C即66+9C=102,但是这里的1是溢出的因此会被截断,只剩下02//IP自动加2,上条指令的长度为2,IP=0021
AX=0002 BX=4026 CX=0000 DX=0000 SP=OOFD BP=0000 SI=0000 DI=0000
DS=0B39 ES=0B39 SS=0B39 CS=2000 IP=0021 NU UP EI PL NZ NA PO NC
2000:0021
任务2

将下面3条指令写入从2000:0开始的内存单元中,利用这3条指令计算2的8次方。

mov ax,1
add ax,ax
jmp 2000:0003

这里就不多赘述了,通过jmp跳转指令,循环执行ax+ax实现2的8次方效果

任务3

查看内存中的内容。PC机主板上的ROM中写有一个生产日期,在内存FFFOOH~FFFFFH的某几个单元中,请找到这个生产日期并试图改变它。

提示,如果读者对实验的结果感到疑惑,.请仔细阅读第1章中的1.15节。

-d fff0:0 ff

在这里插入图片描述

这里是生产日期

因为生产日期是在ROM中,只读不能写,不能改变数据;

任务4

向内存从B8100H开始的单元中填写数据,

如:-e B810:0000 01 01 02 02 03 03 04 04

请读者先填写不同的数据,观察产生的现象;再改变填写的地址,观察产生的现象。

提示,如果读者对实验的结果感到疑惑,请仔细阅读第1章中的1.15节。

这里会出现一些有颜色的形状,但是dosbox好像看不到

在这里插入图片描述

这里在虚拟机中配置了一个windows xp,可以看到

这段内存区域估计是显存地址空间,在显存写入数据就会有图案出现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87698.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87698.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/87698.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java——初始guava(1)

基于 Google Guava 官方教程的解答 📚 Guava 提供了哪些 JDK 不具备的 API? Guava 扩展了 JDK 的集合框架,提供了多种 JDK 没有的实用 API: 不可变集合(Immutable Collections) ImmutableList、ImmutableSet、ImmutableMap 等特性:创建后不可修改,线程安全,性能优于…

day53

import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset import numpy as np from sklearn.preprocessing import MinMaxScaler from sklearn.datasets import load_iris import warnings # 忽略不必要的警…

c++ python 共享内存

一、目的 是为了c来读取并解码传递给python,Python做测试非常方便,c 和 python之间必须定好协议,整体使用c 来解码,共享内存传递给python 二、主类 主类,串联decoder,注意decoder并没有直接在显存里面穿…

react函数组件的props,ref,state。

react开发我们会把页面分为一个个组件,组件是独立而且可复用的重复代码片段。具体来说组件可以是一个按钮,一个输入框。react组件有两种定义方法,一种是函数组件,一种是类组件。我们这里说一下函数组件之间父子之间如何传递props参…

基于ARM+FPGA实现的BISS-C协议解决方案,适用于高精度光栅位移传感器等

模块简介 本资源提供了专为FPGA设计的BISS-C接口协议发送模块源码。BISS-C模式作为一种高速、同步的串行通信协议,广泛应用于高精度光栅位移传感器的数据传输中,特别适用于需要精确位置信息的应用场景。此模式遵循主从架构,其中FPGA作为主控制…

spring中@Transactional注解和事务的实战理解附代码

文章目录 前言一、事务是什么?二、事务的特性2.1隔离性2.2事务的隔离级别 三、Transactional注解Transactional注解简介基本用法常用属性配置事务传播行为事务隔离级别异常处理与回滚性能优化建议 四、 事务不生效的可能原因方法访问权限非public自调用问题异常被捕…

替代进口SCA7606【智芯微】国产高精度电流传感器 工业新能源电网专用

SCA7606(智芯微)产品解析与推广文案一、产品概述SCA7606 是 智芯微电子(ZXMICRO) 推出的一款 高精度数字隔离式电流传感器芯片,采用 霍尔效应数字输出 技术,专为 工业控制、新能源、智能电网 等领域的电流检…

Java 与 Vue 全栈开发:“一课一得“ 学习笔记系统实战

一、项目背景与核心价值 "一课一得" 是一个面向学习者的笔记管理平台,旨在帮助用户系统化记录、整理和回顾学习内容。项目采用前后端分离架构:前端基于 Vue.js 构建交互式界面,后端使用 Java Spring Boot 实现业务逻辑&#xff0c…

百度文心大模型 4.5 开源深度测评:技术架构、部署实战与生态协同全解析

声明:本文只做实际测评,并非广告 1.前言 2025 年 6 月 30 日,百度做出一项重大举措,将文心大模型 4.5 系列正式开源,并选择国内领先的开源平台 GitCode 作为首发平台。该模型也是百度在2025年3月16日发布的自研的新一…

力扣_链表_python版本

一、206. 反转链表代码: class Solution:def reverseList(self, head):dummy ListNode()cur headwhile cur:last cur.nextcur.next dummy.nextdummy.next curcur lastreturn dummy.next二、92. 反转链表 IIclass Solution:def reverseBetween(self, head: Opt…

[netty5: WebSocketProtocolHandler]-源码分析

在阅读这篇文章前,推荐先阅读:[netty5: MessageToMessageCodec & MessageToMessageEncoder & MessageToMessageDecoder]-源码分析 WebSocketProtocolHandler WebSocketProtocolHandler 是 WebSocket 处理的基础抽象类,负责管理 Web…

[2025CVPR]一种新颖的视觉与记忆双适配器(Visual and Memory Dual Adapter, VMDA)

引言 多模态目标跟踪(Multi-modal Object Tracking)旨在通过结合RGB模态与其他辅助模态(如热红外、深度、事件数据)来增强可见光传感器的感知能力,尤其在复杂场景下显著提升跟踪鲁棒性。然而,现有方法在频…

理想汽车6月交付36279辆 第二季度共交付111074辆

理想汽车-W(02015)发布公告,2025年6月,理想汽车交付新车36279辆,第二季度共交付111074辆。截至2025年6月30日,理想汽车历史累计交付量为133.78万辆。 在成立十周年之际,理想汽车已连续两年成为人民币20万元以上中高端市…

MobileNets: 高效的卷积神经网络用于移动视觉应用

摘要 我们提出了一类高效的模型,称为MobileNets,专门用于移动和嵌入式视觉应用。MobileNets基于一种简化的架构,利用深度可分离卷积构建轻量级的深度神经网络。我们引入了两个简单的全局超参数,能够有效地在延迟和准确性之间进行…

SDP服务发现协议:动态查询设备能力的底层逻辑(面试深度解析)

SDP的底层逻辑揭示了物联网设备交互的本质——先建立认知,再开展协作。 一、SDP 核心知识点高频考点解析 1.1 SDP 的定位与作用 考点:SDP 在蓝牙协议栈中的位置及核心功能 解析:SDP(Service Discovery Protocol,服务发现协议)位于蓝牙协议栈的中间层,依赖 L2CAP 协议传…

CppCon 2018 学习:GIT, CMAKE, CONAN

提到的: “THE MOST COMMON C TOOLSET” VERSION CONTROL SYSTEM BUILDING PACKAGE MANAGEMENT 这些是 C 项目开发中最核心的工具链组成部分。下面我将逐一解释每部分的作用、常见工具,以及它们如何协同构建现代 C 项目。 1. VERSION CONTROL SYSTEM&am…

使用tensorflow的线性回归的例子(五)

我们使用Iris数据,Sepal length为y值而Petal width为x值。import matplotlib.pyplot as pltimport numpy as npimport tensorflow as tffrom sklearn import datasetsfrom tensorflow.python.framework import opsops.reset_default_graph()# Load the data# iris.d…

虚幻基础:动作——蒙太奇

能帮到你的话,就给个赞吧 😘 文章目录 动作——蒙太奇如果动作被打断,则后续的动画通知不会执行 动作——蒙太奇 如果动作被打断,则后续的动画通知不会执行

[工具系列] 开源的 API 调试工具 Postwoman

介绍 随着 Web 应用的复杂性增加,API 测试已成为开发中不可或缺的一部分,无论是前端还是后端开发,确保 API 正常运行至关重要。 Postman 长期以来是开发者进行 API 测试的首选工具,但是很多基本功能都需要登陆才能使用&#xff…

【力扣 简单 C】746. 使用最小花费爬楼梯

目录 题目 解法一 题目 解法一 int min(int a, int b) {return a < b ? a : b; }int minCostClimbingStairs(int* cost, int costSize) {const int n costSize; // 楼顶&#xff0c;第n阶// 爬到第n阶的最小花费 // 爬到第n-1阶的最小花费从第n-1阶爬上第n阶的花费…