一日速成汇编[1]
环境搭建
本文使用VSCODE 环境
在拓展商城中选择 MASM/TASM
点开拓展选项
我的设置是这样的
在asm文件界面右键可以调用
点运行和调试都是可以的
从代码开始讲起
Hello world?
DSEG SEGMENT ;datasegment,datasg,data...
MESS DB 'Hello, World!',0DH,0AH,24H
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG
BEGIN:
MOV AX,DSEG ;INT MAIN()
MOV DS,AX
MOV DX,OFFSET MESS
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
CSEG ENDS
END BEGIN
这段代码运行的结果是Hello, World!
如何运行得来呢?
注释语法
汇编语言的注释通常以分号 ;
开始,并在同一行的代码之后
; 这是一个示例注释
MOV AX, 1234h ; 将值1234H移动到AX寄存器
SEGMENT 语法
SEGMENT 相当于 函数 , 类似于 python
中的 def()
类型
可以将其作为函数来理解
SEGMENT 的 代码 在 SEGMENT
和 ENDS
中间
XXX SEGMENT ; XXX 代表 段名
;DO SOMETHING
XXX ENDS
字符串声明 语法
怎么存储
Hello world
?
声明变量
汇编语言中变量的声明一般是
变量名 变量类型 初始值
例如
MESS DB 'Hello, World!',0DH,0AH,24H
就等同于 C++中的
string MESS="Hello, World!\n";
回车,换行
后面的0DH,0AH
代表着回车 和 换行
回车和换行是两个ASCII控制字符,它们在文本处理和排版中起着不同的作用,有以下区别:
- 回车(0x0D):
- 回车字符通常用于将光标(或打印头)移动到行的开头,以便在同一行上继续文本输入或输出。
- 在许多操作系统中,回车通常与换行一起使用,形成回车换行(CRLF)序列,表示新行的开始。例如,Windows操作系统使用CRLF作为文本文件中行的分隔符。
- 在某些系统中,仅使用回车,而没有换行,可能会导致文本在同一行上连续输出,而不换行。
- 换行(0x0A):
- 换行字符通常用于将光标(或打印头)向下移动到下一行,以便在新行上继续文本输入或输出。
- 换行字符通常与回车一起使用,以便在文本文件中表示新行的开始,如CRLF序列所示。
- 在类Unix操作系统中,通常只使用换行(LF)来表示新行的开始,而不使用回车。
终止
24H
在汇编语言中,字符串通常会以特殊的方式终止,以便在处理字符串时能够知道字符串的结束位置。在ASCII编码中,十六进制值 24H
对应字符 $
,通常用于表示字符串的终止符。
主函数?
在汇编程序中有很多SEGMENT段
那么哪里是程序运行的入口呢?
答案是标签(label)
在上面的程序中
入口点被定义为 BEGIN
标签
在程序开始执行时,操作系统或汇编器将控制权传递给这个入口点。
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG
BEGIN: ;没错 ,就是我
MOV AX,DSEG ;INT MAIN()
MOV DS,AX
MOV DX,OFFSET MESS
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
CSEG ENDS
END BEGIN ;出口
ASSUME
ASSUME
是一个汇编语言中的指令,用于建立寄存器和段寄存器之间的关联,以告诉汇编器如何解释寄存器中的值。具体来说:
ASSUME
是一个伪指令,用于建立寄存器和段寄存器之间的关联。
常用寄存器的种类
- AX:累加寄存器(Accumulator)。
- BX:基址寄存器(Base Register)。
- CX:计数寄存器(Count Register)。
- DX:数据寄存器(Data Register)。
这些寄存器通常用于执行通用计算操作,存储临时数据和地址。
SEGMENT的调用
我们将Hello world
存储在了 DSEG 段寄存器中
我们如何在段中 调用其他段呢
我们可以用上面的ASSUME
将其他段和寄存器相关联
例如
ASSUME CS:CSEG, DS:DSEG
就将 DSEG 段和 DS 寄存器相关联了
段 寄存到寄存器
MOV AX,DSEG ;INT MAIN()
MOV DS,AX
DS
寄存器不支持直接的立即数赋值,因此需要使用通用寄存器(如 AX
)作为中继
MOV AX,DSEG
:- 这行代码的目的是将
DSEG
数据段的地址(偏移地址)加载到通用寄存器AX
中。注意,这里的DSEG
是一个标签或标识符,用于指示数据段的位置。 - 通用寄存器
AX
可以直接用于存储16位地址。 MOV DS,AX
:- 一旦
AX
寄存器中包含了数据段地址,这行代码将AX
寄存器的内容复制到数据段寄存器DS
,以确保DS
寄存器指向了正确的数据段。 - 数据段寄存器
DS
用于确定数据操作的默认段,所以将DS
设置为正确的段非常重要,以便程序可以正确访问和操作数据。
MS-DOS[段调用的前置知识]
MS-DOS功能调用的编号通常由 AH
寄存器中的值确定。不同的编号对应不同的功能或服务。具体的功能调用编号会根据所需的操作而有所不同,但以下是一些常见的MS-DOS功能调用编号的示例:
- 文件操作:
AH = 3DH
:打开文件AH = 3FH
:创建文件AH = 3EH
:关闭文件AH = 3FH
:写入文件AH = 3FH
:读取文件AH = 10H
:删除文件- 等等…
- 目录操作:
AH = 1AH
:创建子目录AH = 2FH
:读取目录条目AH = 39H
:删除目录AH = 2AH
:设置当前目录- 等等…
- 屏幕和键盘操作:
AH = 02H
:在屏幕上显示字符AH = 06H
:从键盘获取字符AH = 0AH
:从键盘获取字符并将其存储在缓冲区AH = 09H
:在屏幕上显示字符串- 等等…
- 程序控制:
AH = 00H
:程序结束AH = 4CH
:程序正常退出AH = 31H
:获取程序返回码- 等等…
OFFSET
具体来说,OFFSET
是一个操作符,用于获取标签或变量的内存偏移地址,而不是它的实际值。偏移地址是变量相对于其所在段的起始地址的偏移量。这个偏移地址可以用于访问内存中的数据。
调用段内的内容
我们可以执行下面的代码将 所需要输出的字符串地址偏移量寄存到DX
中
MOV DX,OFFSET MESS
然后设置 AH
寄存器的值 来进行相应的操作
INT 21H
:
- 这行代码是一个中断调用指令。它会触发MS-DOS中断21h,这是一个用于执行各种MS-DOS功能的中断服务例程。具体来说,
INT 21H
用于执行字符串输出操作。 - 在执行时,MS-DOS会查看
AH
寄存器中的值(即9
),以确定要执行的操作。在这种情况下,9
表示要执行字符串输出操作。然后,MS-DOS会查找其他寄存器或内存中的参数来执行相应的输出操作,通常是在DS:DX
段地址偏移指针中指定要输出的字符串
由此便可以输出字符串
程序与输出
DSEG SEGMENT ;datasegment,datasg,data...
MESS DB 'Hello, World!',0DH,0AH,24H
MESS1 DB 'TEST, World!',0DH,0AH,24H
DSEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG, DS:DSEG
BEGIN:
MOV AX,DSEG ;INT MAIN()
MOV DS,AX
MOV DX,OFFSET MESS
MOV AH,9
INT 21H
MOV DX,OFFSET MESS1
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
CSEG ENDS
END BEGIN
输出
爱死你了