• 汇编语言快速入门(非常详细)


    1.内容的定义

    1.1.数据段的定义

    汇编语言程序以段为单位进行书写,一般把数据定义在数据段里,程序写在代码段中。下面给出段的定义语法:

    段名  SEGMENT
    ...(段的内容)...
    段名  ENDS
    
    • 1
    • 2
    • 3

    注意事项:

    汇编语言不区分字母的大小写。
    ②汇编语言中一行只能有一条语句。
    ③段的名字用字母或下划线开头,需要做到含义清晰且不能与保留字重名。
    ④汇编语言中用英文分号后的内容表示程序注释。
    ⑤不能在一个段的内部定义另一个段,也就是各个段之间相互独立。

    1.2.数据的定义

    数据的定义是指对给出的数据分配存储单元,并将它们以标准的格式存放到数据段中。数据定义的语句元素包括DB DW DD DQ DT等。

    1.2.1.定义字节数据DB

    给出下面的汇编程序段

    DATA  SEGMENT
    X     DB   -1,255,'A',3+2,?
          DB   "ABC",0FFH,11001010B
    Y     DB   3 DUP(?)
    DATA  ENDS
    
    • 1
    • 2
    • 3
    • 4
    • 5

    下面对上面的代码段进行解释:

    ①变量的定义:X和Y称为变量名,表示程序员定义了两个变量X和Y。与高级语言不同,汇编语言中的变量实际上是后面第一个数据的地址,变量名代表了后面的若干个数据。
    ②字节数据的定义:DB表示定义的数据类型都是字节类型。DB可以用于定义整数(包括正数和负数,可以使用十进制、十六进制或二进制)以及字符。
    ③求值表达式:定义数据时可以出现简单的求值表达式的结果。如上方的DB 3+2相当于 DB 5。
    ④未知值的定义:用问号表示一个暂时还不确定的值,一般先用0进行这个单元的填充。
    ⑤多个字符的定义:可以出现用双引号括起来的多个字符,这些字符将分开并按照顺序进行存储。
    ⑥重复定义相同数据:DUP表示重复定义多个相同的数据。语法如下:
    ⑦隔行定义:如果数据太多一行写不下,则可以另起一行继续定义。不需要重新写变量名,但是需要重新写DB伪指令。

    DB 数据个数 DUP(数据值)
    
    • 1
    1.2.2.定义字数据DW

    字数据的位数为16位,只需要将上面字节定义的语法中的DB修改为DW即可。

    1.2.3.定义双字数据DD

    双字数据为32字节,只需要将上面字节定义的语法中的DB修改为DD即可。
    需要注意的是,数据的高位存放在地址较大的单元里,数据的低位存放在地址较小的单元里。

    1.2.4.定义八字节和十字节数据DQ DT

    只需要将DB伪指令修改为DQ和DT即可。

    2.数据的传送

    2.1.指令语句的格式

    指令语句是指与一条机器指令相对应的代码语句,其一般格式如下:

    [标号:]  操作码 [操作数] [;注释]
    
    • 1

    语法解释:

    ①标号是指程序员为这一条指令语句所起的名字。大多数指令语句都不需要标号,只有一些特殊的指令语句需要用到。
    ②操作码指定本条指令的操作类型,所有的操作码都是保留字。
    ③操作数可以是0-3个,有多个操作数时彼此之间用逗号分隔。右边的操作数为源操作数,最左边的操作数为目的操作数。

    2.2.操作数的分类

    操作数可以分为寄存器操作数、立即数操作数和存储器操作数三类。关于寄存器操作数,需要注意的是寄存器IP和FLAGS不能作为操作数出现在指令中;关于立即数操作数,需要注意的是立即数操作数不能用作目的操作数。下面着重介绍存储器操作数,先介绍两点基础知识:

    ①存储器操作数表示对一个存储器单元进行访问,需要给出这个存储单元的段基址和偏移地址两部分才能进行。
    ②大多数情况下,指令将自动使用DS寄存器中的内容作为操作数的段基址,因此,编写汇编语言源程序时首先要做的事情就是把数据段的段基址放入DS寄存器

    既然我们已经设置好了段基址,那么只需要有偏移地址即可找到内存中正确的存储单元。给出偏移地址的方法有直接和间接两种方法。直接法是指直接在指令中写出存储单元的偏移地址,间接法则是把存储单元的偏移地址事先装入一个寄存器中,需要时通过这个寄存器中的值来找到这个存储单元。

    ①直接法语法

    MOV  目的寄存器,  变量名[+字节偏移量]
    
    • 1

    此语句的作用是以DS寄存器中的内容作为段基址,以数据段中指定变量名的偏移量(与字节偏移量)的和作为偏移地址,将指定存储单元中的值放入目的寄存器中。

    ②间接法语法:

    MOV  间接寻址寄存器,  OFFSET 变量名
    (下面是需要使用偏移地址时的语句)
    MOV  目的寄存器,     间接寻址寄存器
    
    • 1
    • 2
    • 3

    语法解释:

    ①OFFSET是保留字,表示取出后面变量的偏移地址
    ②间接寻址寄存器只能是BX BP SI DI中的一个。如果没有另外说明,那么使用BX、SI和DI时自动以DS中的内容作为段基址,使用BP时自动使用SS的值作为段基址。

    2.3.程序段的定义

    程序段的一般格式如下:

    CODE SEGMENT
      ASSUME  CS:CODE, DS:DATA
    START: MOV  AX, DATA
           MOV  DS, AX
           ...(其他指令部分)...
           MOV  AX, 4C00H
           INT  21H
    CODE ENDS
           END  START
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    语法解读:

    ①程序开始的两条指令都是用于装载数据段寄存器DS的。进入程序后,代码段寄存器CS中的值已经由操作系统自动设置为代码段的段基址,数据段的段基址则需要程序员手动装入DS中。
    ②ASSUME伪指令用于指定每一个数据段所对应的段基址寄存器。如上面的代码中CODE段的段基址寄存器为CS,DATA段的段基址寄存器为DS。
    ③INT 21H表示调用由操作系统提供的21H号服务程序。服务的种类由AH中的功能号决定,本例中4CH表示返回操作系统的操作;AL中的代码称为返回代码,用返回代码00H表示正常返回。
    ④END伪指令标志整个程序的结束。END语句下面书写的任何代码都不会被汇编。END后的标号表示程序的入口地址,也就是汇编程序开始执行的地方。

    2.4.基本传送指令

    基本传送指令是使用最频繁的指令,需要熟练掌握。格式如下:

    MOV  目的操作数, 源操作数
    
    • 1

    语法解释:

    ①源操作数和目的操作数的类型必须相同。如果不相同只有使用强制类型转换后才能进行传送。强制类型转换语法可以见下方。
    ②源操作数和目的操作数不能同时是存储器操作数,也不能同时是段寄存器
    ③目的操作数不能是立即数
    ④代码段基址寄存器CS不能作目的操作数
    ⑤使用立即数作为源操作数时,立即数会按照目的操作数的类型进行扩展。

    强制类型转换语法(要谨慎使用)

    数据类型  PTR[变量名]
    
    • 1

    3.堆栈

    3.1.堆栈的定义

    堆栈也是用户使用的存储器的一部分,用于存放临时性的数据和一些其他信息。
    堆栈段的定义语法如下:

    堆栈名  SEGMENT  STACK
           (堆栈内容)
    堆栈名  ENDS
    
    • 1
    • 2
    • 3

    语法解释:

    ①堆栈定义和一般段的定义的唯一区别在于使用了STACK
    ②对于堆栈段,系统会在装入程序时自动把SSEG的段基址放入SS寄存器中,堆栈中的字节数自动置入SP寄存器中。
    ③堆栈段中的内容从较大的地址开始分配和使用
    ④对于8086CPU,进出堆栈的只能是2字节的数据。

    3.2.堆栈的使用方法

    常用的堆栈相关指令包括PUSH POP PUSHF和POPF,语法如下:

    PUSH 源操作数              ;将指定操作数入栈保护
    POP 目的操作数              ;将栈顶操作数恢复到指定位置
    PUSHF                     ;标志寄存器内容入栈保护
    POPF                      ;标志寄存器出栈恢复
    
    • 1
    • 2
    • 3
    • 4

    4.常用操作数表达式

    4.1.符号定义伪指令

    符号定义相当于C语言中的#define编译预处理,用于进行符号的等价替换,符号定义的语法如下所示:

    符号名   EQU   表达式
    
    • 1

    语法解释:

    ①在进行汇编时,对EQU定义的符号名用对应的表达式进行等价替换。
    ②对用EQU定义的符号名不允许重复定义。

    另一种进行符号定义的方式是使用“=”符号,具体语法如下:

    符号名   =   常数表达式
    
    • 1

    语法解释:

    使用等号定义符号时只能使用常量表达式。

    4.2.取段基址

    可以使用SEG来取地址表达式所在段的段基址,具体使用方法为:

    SEG 地址表达式
    
    • 1

    5.算术运算

    5.1.加法指令

    对于两个操作数相加应该使用ADD指令,指令语法如下:

    ADD   目的操作数, 源操作数
    
    • 1

    语法解释:

    ①该指令将目的操作数与源操作数相加,结果存放在目的操作数原先的存放位置。
    ②ADD指令执行后会刷新CPU的状态标志位。

    除此之外,还有一条INC指令实现操作数的自增,语法如下:

    INC   操作数
    
    • 1

    语法解释:

    ①增量执行执行后不影响CPU的状态标志位。
    ②增量指令常常用于修改计数器以及存储器指针的值。

    5.2.减法指令

    减法指令和加法指令的使用是对称的。
    加法中的ADD对应减法中的SUB;
    加法中的INC对应减法中的DEC。

    5.3.乘法指令和除法指令

    乘法指令为MUL,除法指令为DIV,使用方法和加减法类似。
    由于乘除法使用较少,因此不过多介绍。

    6.循环

    循环指令的语法如下:

    LOOP   标号
    
    • 1

    语法解释:

    ①循环的次数由寄存器CX中的值决定。每一次循环后CX寄存器中的值会自减1,当CX=0时循环终止,因此CX也被称为计数器。
    ②装载寄存器CX的过程应该在循环开始之前完成。
    ③每一次循环成功则回到标号处的语句。

    7.逻辑运算

    逻辑运算有AND OR XOR和NOT四种,使用语法如下:

    逻辑运算操作码   目的操作数   源操作数
    
    • 1

    使用情况:

    ①AND指令主要用于对操作数的各位有选择地清零;
    ②OR指令主要用于对操作数各位有选择地置一;
    ③XOR指令主要用于对操作数各位有选择地取反;
    ④NOT指令主要用于对操作数整体取反。

    8.中断调用

    所有的DOS系统功能调用都是通过软中断指令INT 21H来实现的。
    INT 21H是一个具有90多个子功能的中断服务程序。
    INT 21H对每一个子功能都进行了编号,这个编程成为功能号。

    DOS系统功能调用方法:

    MOV 功能号   ;把功能号放入寄存器AH中
    ......
    (在其他寄存器中放入该功能要求的入口参数)
    ......
    INT 21H     ;调用DOS系统功能
    
    • 1
    • 2
    • 3
    • 4
    • 5

    常用功能:

    8.1.键盘输入单字符

    功能号1,输入字符以ASCII码的形式存放在累加器AL中同时显示出来。

    MOV AH 01
    INT 21H
    
    • 1
    • 2

    8.2屏幕显示单字符

    功能号2,屏幕显示存放在DL寄存器中的字符。

    MOV AH 02
    MOV DL 待显示字符
    INT 21H
    
    • 1
    • 2
    • 3

    8.3.屏幕显示字符串

    功能号9,用于在显示器上显示一个存放在寄存器DX中的字符串,被显示的字符串必须以’$'作为结束符。

    MOV AH 09
    MOV DX 待显示字符串首地址
    INT 21H
    
    • 1
    • 2
    • 3

    8.4.返回DOS

    一个程序执行完成后使得程序正常退出并返回DOS的功能,功能号为4CH。

    MOV AH 4CH
    INT 21H
    
    • 1
    • 2

    9.子程序的定义和调用

    9.1.定义子程序

    子程序名 PROC
    ...
           RET   ;表示子程序返回
    子程序名 ENDP ;表示子程序段定义结束
    
    • 1
    • 2
    • 3
    • 4

    9.2.调用子程序

    CALL 子程序名
    
    • 1

    10.对接口中的端口进行读写

    MOV DX 端口地址
    ......
    (其他寄存器初始化)
    ......
    OUT DX 需要传输到端口的数据所在的寄存器
    
    • 1
    • 2
    • 3
    • 4
    • 5

    11.空指令延时

    使用NOP表示执行一条空指令,不进行任何操作。当指令之间需要有延时时,可以插入NOP指令。

    NOP
    
    • 1

    12.选择结构

    1.CMP指令

    CMP指令格式如下:

    CMP 目的操作数,源操作数
    
    • 1

    语法解释:

    ①CMP用于比较两个同类型的操作数的大小。
    ②指令执行的结果不会修改两个操作数,而是修改标志位。
    ③CMP指令常常与下列指令结合使用:

    JGE 前>=后     Jump if  greater or equal
    JG 前>后       Jump if  greater
    JLE 前<=后     Jump if  less or equal
    JL 前<后       Jump if  less
    JNE 前不等于后  Jump if not equal
    JE 前等于后     Jump if equal
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    独立站怎么搭建?搭建一个独立站的10个建议和步骤
    电脑被删除的文件怎么恢复?2023年数据恢复方法分享
    【计算机网络】(谢希仁第八版)第三章课后习题答案
    python基础知识整理 08-多任务:进程
    优雅地记录http请求和响应的数据
    怎么让英文大语言模型支持中文?--构建中文tokenization--继续预训练--指令微调
    P1141 01迷宫(dfs+染色联通块)
    QT day4
    update:将另一表里查询的数据,拼接赋值
    第十九章 Nacos统一配置中心详解
  • 原文地址:https://blog.csdn.net/hanmo22357/article/details/127883179