简述MASM宏汇编

发布于:2024-04-29 ⋅ 阅读:(37) ⋅ 点赞:(0)

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

常见指令

数据传输指令:

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

其中:

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

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

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

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

lea dst, src

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

使用 lea 的典型场景包括:

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

例如:

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

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

代码片段

基本结构
DATAS SEGMENT
    ; 数据定义
DATAS ENDS

CODES SEGMENT
    ASSUME CS:CODES, DS:DATAS
    ; 主程序和子程序
CODES ENDS

END START
常用结构

.MODEL SMALL

; 定义堆栈段
.STACK

; 数据段声明
.DATA


; 代码段声明
.CODE

; 程序入口点
.STARTUP

; 结束程序执行
.EXIT

; 定义子程序PRINT_STRING

; 程序结束标记
END
定义程序模式:练习的话用小内存模式
.MODEL SMALL
; 使用`MODEL SMALL`定义程序模式,指定小模式内存模型,程序段(代码和数据)不超过64KB。
定义字符串类型数据
 STRING  DB  'Hello World!',13,10,'$';
 ; 声明一个字符串变量STRING,内容为'Hello World!\r\n$'
 ; 其中,'\r'代表回车(Carriage Return,ASCII码13),'\n'代表换行(Line Feed,ASCII码10)
 ; '$'字符作为字符串结束符,某些情况下用于标识字符串的结尾
 
创建子程序
NAME PROC
    ; 子程序主体代码
    ; ...

    ; 子程序返回
    RET

NAME ENDP
子程序调用
 CALL NAME
计算两个数的和:
MOV AX, NUM1
ADD AX, NUM2
MOV SUM, AX
比较两个数:
MOV AX, NUM1
CMP AX, NUM2
JG GREATER
JL LESS
JE EQUAL
输出字符串到屏幕:
LEA DX, STRING;STRING为变量名
MOV AH, 9
INT 21H
读取字符:
MOV AH, 1
INT 21H
输出字符:
MOV AH, 2
MOV DL, 'A'
INT 21H

打印字符串实例

; 使用`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

子程序创建实例

; 使用`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

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

在这个示例中,程序首先将 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

调用宏库案例



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


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


网站公告

今日签到

点亮在社区的每一天
去签到