当前位置: 首页 > news >正文

二进制安全-汇编语言-02-寄存器

二、寄存器

水滴石穿

一个典型的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.dtcms.com/a/268066.html

相关文章:

  • CPT208-Human-Centric Computing: Field Study and Analytics实地研究与分析
  • 【网络安全基础】第六章---Web安全需求
  • 小菜狗的云计算之旅,学习了解rsync+sersync实现数据实时同步(详细操作步骤)
  • QML 使用QtObject定义私有变量
  • 基于springboot的社区生鲜团购系统
  • 数据结构---B+树
  • 高效管理UI控件:PyQt5容器控件深度解析
  • 黑马python(二十六)
  • python通过openai接口与配置文件.env使用通义千问API
  • EPLAN 电气制图:建立自己的部件库,添加部件(三)下
  • vue3.4中的v-model的用法~
  • 深度学习 必然用到的 线性代数知识
  • HarmonyOS学习4 --- 创建一个页面
  • 多模态偏好数据集生成与混合偏好优化(MPO)方法
  • 计算机网络1.1:什么是Internet?
  • 自定义指令
  • 一条 SQL 语句的内部执行流程详解(MySQL为例)
  • 进程控制中URL攻击与修复方法
  • ether0 大语言推理模型生成SMILES 的分子
  • java并发编程--可见性、原子性、有序性
  • 进程终止:exit()与_exit()深度解析
  • 模块化汽车基础设施的正面交锋---区域架构与域架构
  • 电信、移动、联通、广电跨运营商网速慢原因
  • QML与C++交互之QML端信号绑定C++端槽函数
  • uniapp实现的多种时间线模板
  • jmm,`as - if - serial` 与 `happens - before` 原则
  • Dubbo 3.x源码(31)—Dubbo消息的编码解码
  • 容声W60以光水离子科技实现食材“主动养鲜”
  • 创客匠人深度剖析:家庭教育赛道创始人 IP 打造与知识变现的破局之道
  • 【算法刷题记录(简单题)003】统计大写字母个数(java代码实现)