MASM伪指令速查表–变量
初学MASM时, 常常看不懂db
, dup(?)
等汇编指令的含义, 教材中也缺乏系统的解释。与机器指令不同,这些指令叫伪指令, 在编译(汇编)的时候被MASM编译器处理, 而在运行时计算机不会真正的执行这些指令。这篇文章可以系统的解决对MASM伪指令的困扰。 MASM学习到这一块才叫真正的MASM,之前学习的机器指令都属于各种汇编语言都支持的8086指令集, 而这些伪指令只有MASM有, 别的汇编语言比如NASM等是不支持这些伪指令的。
文章目录
- MASM伪指令速查表--变量
- 一. 数值型参数(常量)和表达式
- 1. 常量(常数)定义`equ`或`=`
- 2. 数值表达式
- 二. 变量定义伪指令
- 1. `db/dw/dd/df/dq/dt`
- 2. 初值表和`dup`
- 3. 定位伪指令`org`,`even`,`allign`
- (1) `org`
- (2) `even/align`
- 三. 变量的地址和类型
- 1. 地址操作符 `offset` `seg`
- 2. 地址操作符`:`, `[]`, `$`
- 3. 类型操作符`ptr`, `this`, `type`
- (1) `ptr`
- (2) `this`
- (3) `TYPE`, `lengthof`, `sizeof`
一. 数值型参数(常量)和表达式
1. 常量(常数)定义equ
或=
格式:
[常量名] equ [值]
或者[常量名] = [值]
举例:
myid equ 1234 numofchina =1 ;一个中国 calldos equ <int 21h> ;[值]可以是字符串, 但是字符串要拿<>括起来
注意:
这里定义的是常量, 在内存中没有分配空间, 因此和高级语言(如c语言)的常量一样
myid equ myid+1
这种语句是不允许的
2. 数值表达式
masm6.x支持多种运算符, 对的你没有看错, MASM还可以支持运算符, 但是仅限常量和立即数的计算(和c语言的宏同理, 就是在编译的时候算好), 不能运行时计算
运算符类型 | |
---|---|
算术运算符 | +, -, *, /, MOD(取余) |
逻辑运算符 | AND, OR, XOR(异或), NOT |
移位运算符 | SHL(左移), SHR(右移) |
关系运算符 | EQ(equal相等), NE(not equal不相等), GT(greater than大于), LT(less than小于), GE(大于等于), LE(小于等于) |
高低分离符 | HIGH(高字节), LOW(低字节), HIGHWORD(高字), LOWWORD(低字) |
举例:
mov ax, 1*1+2 ; 等价于mov ax, 3
mov al, 0101b shl (2*2) ; 等价于 mov al, 01010000b(0101b左移四位)
mov ah, high 8765h ; 等价于 mov ah, 87h(8765h的高字节)
二. 变量定义伪指令
1. db/dw/dd/df/dq/dt
db是以字节(8比特)为单位, dw是以字为单位(16比特), dd是双字, df是三字, dq是四字, dt是十字
格式:
[变量名] db [初值表]
功能: 定义以字节为单位的变量,变量的起始地址为[变量名], 值为[初值表]中每个逗号隔开的元素, [变量名]可以省略
示例:
.data X db 'A', -5 db 2dup(100), ? Y db 'ABC' Z dw 'ABC'
说明:
db和dw是以某个长度为单位
Y在内存中为: 41h, 42h, 43h
Z在内存中为: 41h, 42h, 43h, 00h(因为以字为单位所以会有一个字节空出来)
2. 初值表和dup
初值表: 由逗号隔开的参数, 可以由数值, 表达式或"?", "dup"组成, "?"代表初值不确定即未赋值, 下面解释dup
格式:
[次数]dup([初值])
功能: 定义[次数]个初值为[初值]的变量
示例:
.data X db 1, 3dup(0), 1 ; 在内存中就是01 00 00 00 01h Y db 2dup(?) ; 在内存中就是 ?? ?? h (?就是初值不确定,就是定义的时候我不在意初始值是多少,至于具体的值和编译器和版本有关, 大部分版本的MASM初始化?为0)
3. 定位伪指令org
,even
,allign
(1) org
格式:
org [偏移地址]
功能: 使他后面的数据或指令从指定的偏移地址开始
示例:
org 100h array db 12, 34, 56 ;12开始的偏移地址是100h, 或者说array的偏移地址是100hlen equ $-array
解释: $的含义就是当前偏移地址的值例如
用途: 更细粒度的规划内存的空间, 可以任意指定程序和数据在虚拟内存中的结构,这是高级语言做不到而汇编能做到的. 比如开机时操作系统的引导程序(引导程序就是把操作系统逐步加载到内存中, 并进行一些初始化的程序), BIOS规定要将引导程序加载到07c00h这个地址上, 这样细粒度的内存空间管理只有汇编能做到, 这也是为什么操作系统的引导模块都会含有汇编程序, 而这样的功能就是用
org 07c00h
实现的
(2) even/align
功能:
even
使后面的数据或指令地址从偶数开始
align [n]
使后面的数据或地址从n的整数倍开始, 举例:align 4
用途:
用于数据对齐, 学过计算机组成原理的应该知道, 目的就是让数据对的更齐, 这样能最大减少取数据时总线传输次数消耗尽量少的总线时钟周期,通俗来讲就是取数据更快
三. 变量的地址和类型
1. 地址操作符 offset
seg
格式:
offset [标号/变量名]
seg [标号/变量名]
功能:
offset
:取[标号/变量名]的偏移地址,seg
:取[标号/变量名]的段基址举例:
.model small ; 套话org 100h ; 代码段的偏移地址设定为100h, 也就是hello的偏移地址为100h .data hello db 'ABC' ; hello是变量名.code org 200h ; 设定nihao的偏移地址为200h nihao: ; nihao是标号 mov ax, offset hello ; 等价于 mov ax, 100h(hello的偏移地址) mov ax, seg nihao ; 等价于 mov ax, cs(因为nihao在代码段, seg是返回段基址)
2. 地址操作符:
, []
, $
[]
:
$
格式举例 [ax+4300h]
cs:[bx+1]
mov ax, $+1
功能 []表示将括号里面的表达式作为存储器地址的指针 :表示用:前的段寄存器作为段超越的段寄存器, 段超越就是指不使用默认的段寄存器 $表示当前位置的数据/指令的偏移地址
3. 类型操作符ptr
, this
, type
(1) ptr
格式:
[类型名] ptr [名字/标号/内存地址]
功能: 可以简单理解成C语言中的强制类型转换, 指定[名字/标号/内存地址]的类型为[类型名] (和高级语言的类型的含义不同,这里的变量类型就是指数据的宽度, 不过其实c语言区分变量类型的方法其实就是通过数据的宽度, 但是其他语言尤其是面向对象的语言比如python并不是靠数据宽度区分变量类型的)
举例:
.model small ; 套话 .data ; 定义数据段 w_var dw 01h ; 定义字(16比特)变量w_war.code ; 定义代码段 .startup ; 代码执行开始位置 mov al, byte ptr w_var ; w_var是字变量, byte ptr使得 w_var被当做字节变量 mov ah, bye ptr [1000h] ; 内存单元是以字为单位的, byte ptr使得 [1000h]的内存单元被当做字节变量 .exit 0 ; 套话 进程返回和中断
[类型名]还可以是:
byte(字节8比特), word(字16比特), dword(双字), fword(三字), qword(四字), tbyte(十比特), near(段内转移, 一般说明某个转移内存地址是比较近的), far(段间转移, 一般说明某个转移内存地址在别的段, 或者在本段非常远的位置), struct(结构体, 后面会细讲), record(记录, 学过数据库或者计算机组成原理应该会知道是什么意思, 不知道可以百度), union(联合体, 和c语言的union几乎一样)
(2) this
强制类型转换可以用
PTR
来实现.但是,如果程序中经常要以同一个数据宽度访问变量, 每次访问都要加上ptr
操作符, 很麻烦,
于是,汇编语言提供了另外一种操作符:THIS
,它为一个变量取了别名,该别名具有指定的和元变量不同的数据宽度,但是段地址和偏移量和原来的变量一致(也就是用固定用另外一种数据长度来访问原变量)举例:
.data char equ this byte ; 这样写就可以通过char这个名字固定以字节为单位访问string, 想用字为单位访问就用string这个名字 string dw 'ABCDEFG' ; 定义以字为单位的变量string
(3) TYPE
, lengthof
, sizeof
sizeof
可以简单理解成c语言中的sizeof()
关键字,sizeof = lengthof * type
type的返回值
类型 返回值 变量 每个数据占用的字节数 结构体 结构体每个元素占用的字节数 常数 0 标号 代号(如near 为 0ff02h) 寄存器 寄存器宽度的字节数 举例
.data b_var equ this byte ; b_var是w_var的别名, 和w_var不一样的是, b_var以字节为单位访问 w_var dw 10 dup(0) ; 定义w_var是一个以字为单位有10个元素(值为0)的数组.code mov ax, type w_var ; 等价于 mov ax, 2(两个字节, 也就是一个字) mov ax, type b_var ; 等价于 mov ax, 1(一个字节)