• 简述MASM宏汇编


    Hello , 我是小恒不会java。今天写写x86相关底层的东西

    在这里插入图片描述

    寄存器

    8086由BIU和EU组成
    8088/8086寄存器有14个。8通用,4段,1指针,1标志
    8个通用寄存器:这些寄存器可以用来存储任意类型的数据,包括整数、地址等。8086有8个通用寄存器,分别是:
    AX(Accumulator):累加器,用于存储计算结果和中间结果。
    BX(Base Register):基址寄存器,用于存储基址。
    CX(Count Register):计数寄存器,用于存储循环次数和计数。
    DX(Data Register):数据寄存器,用于存储乘法和除法操作的数据。
    SI(Source Index):源索引寄存器,用于存储源操作数的地址。
    DI(Destination Index):目标索引寄存器,用于存储目标操作数的地址。
    BP(Base Pointer):基址指针寄存器,用于存储基址指针。
    SP(Stack Pointer):堆栈指针寄存器,用于存储堆栈顶部的地址。
    4个段寄存器:这些寄存器用于存储内存段的地址。8086有4个段寄存器,分别是:
    CS(Code Segment):代码段寄存器,用于存储代码段的地址。
    DS(Data Segment):数据段寄存器,用于存储数据段的地址。
    SS(Stack Segment):堆栈段寄存器,用于存储堆栈段的地址。
    ES(Extra Segment):附加段寄存器,用于存储附加段的地址。
    1个指针寄存器:
    IP(Instruction Pointer):指令指针寄存器,用于存储下一条指令的地址。
    1个标志寄存器:
    FLAGS:标志寄存器,用于存储指令执行过程中产生的状态信息,如进位、溢出、零等。

    寄存器具体隐式用法我在此不多赘述

    物理地址

    物理地址 (PA) = (CS << 4) + IP
    
    • 1

    常见指令

    数据传输指令:

    mov:移动数据,从一个寄存器到另一个寄存器,或从内存到寄存器,反之亦然。
    push:将数据压入栈。 pop:从栈中弹出数据。
    xchg:交换两个寄存器或一个寄存器和内存位置的内容。
    lea:加载有效地址,通常用于计算内存偏移。
    算术和逻辑指令:

    add:加法。
    sub:减法。
    mul:无符号乘法。
    imul:有符号乘法。
    div:无符号除法。
    idiv:有符号除法。
    inc:递增寄存器或内存位置的内容。
    dec:递减寄存器或内存位置的内容。
    neg:取负数。
    and:按位与。
    or:按位或。
    xor:按位异或。
    not:按位非。
    shl/sal:左移。
    shr/sar:右移(逻辑右移/算术右移)。
    控制流指令:
    jmp:无条件跳转。
    call:调用子程序。
    ret:从子程序返回。
    je/jz:如果相等/为零则跳转。
    jne/jnz:如果不等于/不为零则跳转。
    jg/jnle:如果大于/不小于等于则跳转。
    jge/jnl:如果大于等于/不小于则跳转。
    jl/jnge:如果小于/不大于等于则跳转。
    jle/jng:如果小于等于/不大于则跳转。
    test:测试寄存器或内存位置的内容,常用于条件跳转。
    字符串处理指令:
    lods:从字符串中加载字节/字/双字。
    stos:存储字节/字/双字到字符串。
    cmps:比较字符串。 scas:扫描字符串。
    输入/输出指令:
    in:从端口读取数据。
    out:向端口写入数据。 系统指令:
    syscall:执行系统调用。
    int:触发中断。
    iret:从中断返回。

    MOV 指令
    mov 是“Move”的缩写,用于在汇编语言中执行数据传输操作,即从一个源(source)复制数据到一个目标(destination)。其基本语法是:

    mov dst, src
    
    • 1

    其中:

    • dst 是目标操作数,可以是寄存器、内存位置(通过地址表达式指定)或其他可寻址的数据对象。
    • src 是源操作数,同样可以是寄存器、内存位置、立即数(常数值)等。

    mov 指令的主要功能是将 src 中的值直接拷贝到 dst,实现数据的移动或赋值。例如:

    mov eax, ebx       ; 将 ebx 寄存器的值复制到 eax 寄存器
    mov [esp], 0x1234  ; 将立即数 0x1234 存储到 esp 指向的内存位置
    mov eax, [0x1000]  ; 从内存地址 0x1000 处读取数据并存入 eax 寄存器
    
    • 1
    • 2
    • 3

    LEA 指令
    lea 是“Load Effective Address”的缩写,它的功能不是直接传送数据,而是计算并获取源操作数所代表的内存地址,并将这个地址(而非地址处的数据)存放到目标寄存器中。其基本语法是:

    lea dst, src
    
    • 1

    这里的 dst 仍然是目标寄存器,而 src 是一个地址表达式,通常由一个基址寄存器加上一个偏移量(可以是常数或寄存器)构成。lea 指令并不访问内存,它仅仅计算地址表达式的值并将其存入目标寄存器。

    使用 lea 的典型场景包括:

    • 快速计算数组元素的地址,无需额外的算术运算。
    • 在不实际加载数据的情况下获取变量或数据结构成员的地址。
    • 作为某种形式的算术运算(如简单的加法或乘法)的替代,特别是在地址计算中。

    例如:

    lea eax, [ebx + 4*ecx]  ; 计算 ebx 加上 4 倍 ecx 的值所对应的地址,并将该地址存入 eax
    lea edi, [ebp - 8]      ; 获取当前栈帧中偏移量为 -8 的局部变量的地址,存入 edi
    
    • 1
    • 2

    mov 指令用于数据的直接复制,而 lea 指令则用于获取和存储内存地址

    代码片段

    基本结构
    DATAS SEGMENT
        ; 数据定义
    DATAS ENDS
    
    CODES SEGMENT
        ASSUME CS:CODES, DS:DATAS
        ; 主程序和子程序
    CODES ENDS
    
    END START
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    常用结构
    
    .MODEL SMALL
    
    ; 定义堆栈段
    .STACK
    
    ; 数据段声明
    .DATA
    
    
    ; 代码段声明
    .CODE
    
    ; 程序入口点
    .STARTUP
    
    ; 结束程序执行
    .EXIT
    
    ; 定义子程序PRINT_STRING
    
    ; 程序结束标记
    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    定义程序模式:练习的话用小内存模式
    .MODEL SMALL
    ; 使用`MODEL SMALL`定义程序模式,指定小模式内存模型,程序段(代码和数据)不超过64KB。
    
    • 1
    • 2
    定义字符串类型数据
     STRING  DB  'Hello World!',13,10,'$';
     ; 声明一个字符串变量STRING,内容为'Hello World!\r\n$'
     ; 其中,'\r'代表回车(Carriage Return,ASCII码13),'\n'代表换行(Line Feed,ASCII码10)
     ; '$'字符作为字符串结束符,某些情况下用于标识字符串的结尾
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    创建子程序
    NAME PROC
        ; 子程序主体代码
        ; ...
    
        ; 子程序返回
        RET
    
    NAME ENDP
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    子程序调用
     CALL NAME
    
    • 1
    计算两个数的和:
    MOV AX, NUM1
    ADD AX, NUM2
    MOV SUM, AX
    
    • 1
    • 2
    • 3
    比较两个数:
    MOV AX, NUM1
    CMP AX, NUM2
    JG GREATER
    JL LESS
    JE EQUAL
    
    • 1
    • 2
    • 3
    • 4
    • 5
    输出字符串到屏幕:
    LEA DX, STRING;STRING为变量名
    MOV AH, 9
    INT 21H
    
    • 1
    • 2
    • 3
    读取字符:
    MOV AH, 1
    INT 21H
    
    • 1
    • 2
    输出字符:
    MOV AH, 2
    MOV DL, 'A'
    INT 21H
    
    • 1
    • 2
    • 3

    打印字符串实例

    ; 使用`MODEL SMALL`定义程序模式,指定小模式内存模型,程序段(代码和数据)不超过64KB。
    
    .MODEL SMALL
    
    ; 定义堆栈段
    .STACK
    
    ; 数据段声明
    .DATA
        ; 声明一个字符串变量STRING,内容为'Hello World!\r\n$'
        ; 其中,'\r'代表回车(Carriage Return,ASCII码13),'\n'代表换行(Line Feed,ASCII码10)
        ; '$'字符作为字符串结束符,某些情况下用于标识字符串的结尾
        STRING  DB  'Hello World!',13,10,'$'
    
    ; 代码段声明
    .CODE
    
    ; 程序入口点
    .STARTUP
        ; 调用子程序PRINT_STRING,输出字符串
        CALL PRINT_STRING
    
    ; 结束程序执行
    .EXIT
    
    ; 定义子程序PRINT_STRING
    PRINT_STRING PROC
    
        ; LEA (Load Effective Address)指令将STRING变量的地址加载到DX寄存器
        LEA  DX, STRING
    
        ; 将AH寄存器设置为9,这是DOS中断INT 21H的功能号,表示要执行"显示字符串"操作
        MOV  AH, 9
    
        ; 调用DOS中断INT 21H,执行显示字符串功能。此时DX寄存器保存了待显示字符串的地址
        INT  21H
    
        ; 子程序返回
        RET
    PRINT_STRING ENDP
    
    ; 程序结束标记
    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    子程序创建实例

    ; 使用`MODEL SMALL`定义程序模式,指定小模式内存模型,程序段(代码和数据)不超过64KB。
    
    .MODEL SMALL
    
    ; 定义堆栈段
    .STACK
    
    ; 数据段声明
    .DATA
        ; 声明一个字符串变量STRING,内容为'Hello World!\r\n$'
        ; 其中,'\r'代表回车(Carriage Return,ASCII码13),'\n'代表换行(Line Feed,ASCII码10)
        ; '$'字符作为字符串结束符,某些情况下用于标识字符串的结尾
        STRING  DB  'Hello World!',13,10,'$'
    
    ; 代码段声明
    .CODE
    
    ; 程序入口点
    .STARTUP
        ; 调用子程序PRINT_STRING,输出字符串
        CALL PRINT_STRING
    
    ; 结束程序执行
    .EXIT
    
    ; 定义子程序PRINT_STRING
    PRINT_STRING PROC
    
        ; LEA (Load Effective Address)指令将STRING变量的地址加载到DX寄存器
        LEA  DX, STRING
    
        ; 将AH寄存器设置为9,这是DOS中断INT 21H的功能号,表示要执行"显示字符串"操作
        MOV  AH, 9
    
        ; 调用DOS中断INT 21H,执行显示字符串功能。此时DX寄存器保存了待显示字符串的地址
        INT  21H
    
        ; 子程序返回
        RET
    PRINT_STRING ENDP
    
    ; 程序结束标记
    END
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    AH实例

    AH 寄存器是 8086 汇编语言中的一个 8 位寄存器,属于 16 位寄存器 AX 的高 8 位部分

    在 DOS 操作系统中,通过调用中断 21H 可以执行各种功能。这些功能由 AH 寄存器的值确定。例如,AH 寄存器的值设置为 9 表示调用 DOS 的输出字符串功能,值设置为 4CH 表示调用 DOS 的退出功能。

    以下是一个简单的汇编程序示例,演示了如何使用 AH 寄存器调用 DOS 的输出字符功能:

    .MODEL SMALL
    .STACK
    .DATA
        CHAR DB 'A'
    .CODE
    .STARTUP
        MOV AH,2 ; 设置 AH 寄存器的值为 2,表示调用 DOS 的输出字符功能
        MOV DL,CHAR ; 将 CHAR 变量的值加载到 DL 寄存器
        
        
        INT 21H ; 调用 DOS 中断
    .EXIT
        END
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这个示例中,程序首先将 AH 寄存器的值设置为 2,表示调用 DOS 的输出字符功能。然后,将 CHAR 变量的值加载到 DL 寄存器,最后使用 INT 21H 指令调用 DOS 中断。这将在屏幕上输出字符 ‘A’。

    求和案例

    ;完整段的求3+5的和
    DATAS  SEGMENT
        FIVE  DB    5
    DATAS  ENDS
    
    STACKS  SEGMENT
          DB  128 DUP (?)
    STACKS  ENDS
    
    CODES  SEGMENT
    
    
         ASSUME    CS:CODES,DS:DATAS,SS:STACKS
    START:
        MOV AX,DATAS
        MOV DS,AX
        MOV AL,FIVE
        ADD AL,3
        ADD AL,30H
        MOV DL,AL
        
        MOV AH,2
        INT 21H
        
        MOV AH,4CH
        INT 21H
        
    CODES  ENDS
    
        END  START
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    调用宏库案例

    
    
    INCLUDE  MACROOUT.LIB;调用库
    
    DATAS SEGMENT
    
        STRING  DB 'Hello World',13,10,'$';定义字符串数据
    
    DATAS ENDS
    
    CODES SEGMENT
    
        ASSUME CS:CODES,DS:DATAS
    
    START:
    
        MOV AX,DATAS
    
        MOV DS,AX
    
        OUTPUT STRING;使用output库内方法
    
     
    ;使用寄存器中断程序
      MOV AH,4CH
    
        INT 21H
    
    CODES ENDS
    
        END START
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Qt 游戏场景 & 图元
    在互联网寒冬,我们应届生应如何提高竞争力?
    牛视源码定制,抖音矩阵系统,别和谐啊、、、
    Python整数规划— 0−1型规划
    若依前端使用
    Vue-中央事件总线(bus)
    【服务器数据恢复】IBM服务器raid5两块硬盘离线数据恢复案例
    【Java】线程池源码解析
    基于stm32单片机的电压报警系统Proteus仿真
    网络编程 tcp/ip下的c/s模型介绍
  • 原文地址:https://blog.csdn.net/2302_81578551/article/details/138172074