马上要期末考试了,汇编还没怎么学,看书又看不懂,更不想学了,今天做了一下上机作业,发现还是从代码入手学的快。整理了一下学习笔记
汇编debug是在干嘛:在汇编语言中,Debug 模式是一种强大的调试工具,可以逐条执行汇编指令,并观察寄存器和内存的变化。
出现提示符“-” ,表示已进入DEBUG调试状态。
代码理解
任务1
#指示编译器使用“小型”内存模型。小型内存模型假定代码段和数据段都小于64KB。
.MODEL SMALL
#定义栈的大小为256字节(100h)。
.STACK 100h
#数据段,定义了变量:
.DATA
- #X DW 30 定义一个16位变量 X,初始值为30。
- #Y DW 15 定义一个16位变量 Y,初始值为15。
- #Z1 DW ? 定义一个16位变量 Z1,未初始化,用于存储 X + Y 的结果。
- #Z2 DW ? 定义一个16位变量 Z2,未初始化,用于存储 X - Y 的结果。
- #Z3 DW ? 定义一个16位变量 Z3,未初始化,用于存储 X * Y 的结果。
X DW 30 ; 定义变量X,值为30
Y DW 15 ; 定义变量Y,值为15
Z1 DW ? ; 定义变量Z1,用于存储X + Y的结果
Z2 DW ? ; 定义变量Z2,用于存储X - Y的结果
Z3 DW ? ; 定义变量Z3,用于存储X * Y的结果
#代码段,包含程序的指令。
.CODE
#程序的入口点
START:
#将数据段地址加载到 AX 寄存器。
MOV AX, @DATA
#将 AX 中的数据段地址加载到 DS 寄存器,使数据段寄存器 DS 指向数据段。
MOV DS, AX
MOV AX, X ; 将X的值加载到AX寄存器
ADD AX, Y ; 计算X + Y
MOV Z1, AX ; 将结果存储到Z1中
MOV AX, X ; 将X的值加载到AX寄存器
SUB AX, Y ; 计算X - Y
MOV Z2, AX ; 将结果存储到Z2中
MOV AX, X ; 将X的值加载到AX寄存器
MOV BX, Y ; 将Y的值加载到BX寄存器
IMUL BX ; 计算X * Y
MOV Z3, AX ; 将结果存储到Z3中
; 结束程序
MOV AX, 4C00H
INT 21H
END START
总结
- 变量的定义
Z3 DW ? 即没有初始值
DW:数据定义指令,代表Defined world。在8086汇编中,一个字(Word)通常是16位的数据,所以 X 被定义为一个16位的变量,可以存储的值的范围是 0 到 65535(2^16 - 1)。
- 寄存器
AX与DS寄存器
在8086汇编语言中,AX 寄存器和 DS 寄存器都是通用寄存器,用于存储数据和地址。下面是它们的简要介绍:
### AX 寄存器(累加器寄存器)
- **名称**:AX(Accumulator)
- **大小**:16位
- **作用**:主要用作算术和逻辑操作的累加器。许多算术运算(例如加法、减法、乘法、除法)的结果都存储在 AX 中。此外,它还用于存储函数的返回值。
- **部分**:AX 可以分为两个 8 位的寄存器:AL 和 AH。AL 存储 AX 的低 8 位(低字节),AH 存储 AX 的高 8 位(高字节)。
对于高八位和低八位的划分
这句话解释了AX寄存器在实际存储时的结构。在8086汇编语言中,AX寄存器是16位的,也就是说,它可以存储16个二进制位的数据。但有时候,需要对AX寄存器的内容进行更精细的操作,例如分别处理AX的高8位和低8位。为此,AX寄存器可以被看作由两个独立的8位寄存器组成,这两个寄存器分别是AL和AH。
- AL 寄存器:存储AX的低8位,也就是AX寄存器的低字节。
- AH 寄存器:存储AX的高8位,也就是AX寄存器的高字节。
这样的划分使得程序员可以方便地处理AX寄存器中的部分数据,而不需要对整个16位的数据进行操作。例如,如果需要将AX寄存器中的数据分别传送到另外两个寄存器中,可以使用MOV指令将AX的低8位传送到一个寄存器中,将AX的高8位传送到另一个寄存器中。
### DS 寄存器(数据段寄存器)
- **名称**:DS(Data Segment)
- **大小**:16位
- **作用**:用于存储数据段的地址。在实模式下(8086处理器工作在实模式下时),数据段寄存器 DS 存储着数据段的基址,用于访问程序中的数据。DS 寄存器中的地址加上偏移量就能够访问到内存中的特定数据。
- **用途**:当程序需要访问存储在数据段中的变量或数组时,DS 寄存器会指示 CPU 数据的位置。
在汇编语言编程中,常常会用到这两个寄存器来操作内存中的数据。AX 用于存储操作数和结果,DS 用于指示数据的存储位置。
地址与寻址
访问内存中的数据的地址通常是由两部分组成的:段地址和偏移地址。段地址由段寄存器(比如DS)提供,而偏移地址则是在指令中直接给出的。CPU会将段地址和偏移地址进行合并,得到实际的内存地址,然后访问该地址的数据。
采用分段方式的原因:
在早期的x86架构中,采用了分段的内存管理方式。这种方式是为了满足当时硬件和软件的需求而设计的。下面是一些采用分段内存管理方式的原因:
1. **内存保护**:通过分段,可以实现内存保护,防止程序意外地访问或修改其他程序的数据。每个段都有自己的访问权限,这样可以限制程序对内存的访问。
2. **地址空间扩展**:通过分段,可以将大于64KB的内存划分成多个段,从而扩展了地址空间,使得程序可以访问更多的内存。
3. **代码段和数据段分离**:通过将代码和数据分别放置在不同的段中,可以提高程序的安全性和可靠性。例如,可以将只读的代码放在一个只读的代码段中,这样可以避免程序意外地修改代码。
4. **动态链接**:分段内存管理方式也为动态链接提供了支持。通过将函数和数据放置在不同的段中,可以实现动态链接库(DLL)等功能。
虽然分段内存管理方式在一定程度上解决了早期计算机系统的需求,但它也存在一些缺点,比如容易产生碎片、难以管理等。随着计算机技术的发展,现代操作系统普遍采用了分页和分段页表等更为先进的内存管理方式,但分段的概念仍然在一些特定的场景中有所应用。
MOV AX, @DATA理解
在实模式下的8086汇编语言中,数据段的段地址可以通过 @DATA 伪操作符来获取
实际上,@DATA 伪操作符表示数据段的段地址,它是编译器在编译时将其解析为一个常量值,这个常量值就是数据段的段地址。然后,MOV AX, @DATA 指令将这个常量值加载到 AX 寄存器中,这样 AX 寄存器就存储了数据段的段地址,从而可以通过段地址来访问数据段中的数据。
乘法运算
MOV AX, X ; 将X的值加载到AX寄存器
MOV BX, Y ; 将Y的值加载到BX寄存器
IMUL BX ; 计算X * Y
MOV Z3, AX ; 将结果存储到Z3中
为什么是IMUL BX:
IMUL是乘法指令,默认一个乘数存在AX寄存器中,所以不用写AX
任务二
#方法一
.MODEL SMALL
.STACK 100h
.DATA
; 定义变量来存储交换前后的寄存器值
- #A DW 1234h 定义一个名为 A 的变量,初始值为 1234h(十六进制)。
- B DW 5678h 定义一个名为 B 的变量,初始值为 5678h(十六进制)。
A DW 1234h ; 示例值,16位寄存器A
B DW 5678h ; 示例值,16位寄存器B
.CODE
START:
MOV AX, @DATA
MOV DS, AX
MOV AX, A ; 将变量A的值加载到AX寄存器
MOV BX, B ; 将变量B的值加载到BX寄存器
; 使用XCHG指令交换AX和BX的值
XCHG AX, BX
; 将交换后的值存储回变量
MOV A, AX
MOV B, BX
; 结束程序
MOV AX, 4C00H
INT 21H
END START
方法二
.MODEL SMALL
.STACK 100h
.DATA
; 定义变量来存储交换前后的寄存器值
A DW 1234h ; 示例值,16位寄存器A
B DW 5678h ; 示例值,16位寄存器B
.CODE
START:
MOV AX, @DATA
MOV DS, AX
MOV AX, A ; 将变量A的值加载到AX寄存器
MOV BX, B ; 将变量B的值加载到BX寄存器
; 使用XOR指令交换AX和BX的值
XOR AX, BX
XOR BX, AX
XOR AX, BX
; 将交换后的值存储回变量
MOV A, AX
MOV B, BX
; 结束程序
MOV AX, 4C00H
INT 21H
END START
MOV AX, 4C00H 和 INT 21H 这两条指令的作用是结束程序并返回到操作系统。
具体说明
MOV AX, 4C00H:
-
- MOV 指令将一个立即数(4C00H)加载到AX寄存器。
- 4C00H是一个16位的值,其中4CH是DOS中断21H功能号,用于终止程序。
- 00H是程序的返回码,表示程序正常终止。返回码可以用来指示程序的退出状态,00H通常表示成功。
INT 21H:
-
- INT 指令用于触发中断。
- 21H是DOS中断号,用于调用DOS服务。
- 当AX寄存器中包含4CH时,调用中断21H会终止当前程序并返回到操作系统。