X86 汇编/FASM 语法
FASM采用Intel语法, 符号名分大小写.
一个FASM源码文件由命令行, 标签行, 指示符行, 注释行组成. 注释可单独一行, 也可尾于其他行. 行尾符不分Windows或Linux. 行尾反斜杠'\'用于续行.
源码由词构成. 词用于各种命名. 组成词的字符分三种:
- 单符: +-*/= <>() []{} :, |&~# ` 每个单独成词, 不与其它字符结合成词
- 引符: 单引号和双引号. 成对使用内含单符或名符构成字串. 连续多个单引号或双引号视为一个
- 名符: 单符和引符之外所有符号, 用于构词. 词首尾以空格或单符为界与他者分开.
命令语法
编辑每个命令行含:
助记符 零个或多个操作数(Operand) ; 注释, 这是命令行的一般形式
这些操作数隔以逗号加零个或多个空格. 操作数可以是暂存器, 立即数或内存数, 前置以尺寸符来限定大小, 但暂存器名字蕴尺寸, 不可前置以尺寸符. 立即数可为任何算式. [内存地址, 可为任何算式] 表示取该地址内的数. 也可用 ptr 内存地址 的方式. 例
mov word [0x55aa55aa], 0x12345678
等价于
mov word ptr 0x55aa55aa, 0x12345678
尺寸符 | 位数 | 字节数 |
---|---|---|
byte | 8 | 1 |
word | 16 | 2 |
dword | 32 | 4 |
fword | 48 | 6 |
pword | 48 | 6 |
qword | 64 | 8 |
tbyte | 80 | 10 |
tword | 80 | 10 |
dqword | 128 | 16 |
xword | 128 | 16 |
qqword | 256 | 32 |
yword | 256 | 32 |
类 | 位数 | 名 | |||||||
---|---|---|---|---|---|---|---|---|---|
通用 | 8 | al | cl | dl | bl | ah | ch | dh | bh |
16 | ax | cx | dx | bx | sp | bp | si | di | |
32 | eax | ecx | edx | ebx | esp | ebp | esi | edi | |
段 | 16 | es | cs | ss | ds | fs | gs | ||
控制 | 32 | cr0 | cr2 | cr3 | cr4 | ||||
除障 | 32 | dr0 | dr1 | dr2 | dr3 | dr6 | dr7 | ||
FPU | 80 | st0 | st1 | st2 | st3 | st4 | st5 | st6 | st7 |
MMX | 64 | mm0 | mm1 | mm2 | mm3 | mm4 | mm5 | mm6 | mm7 |
SSE | 128 | xmm0 | xmm1 | xmm2 | xmm3 | xmm4 | xmm5 | xmm6 | xmm7 |
AVX | 256 | ymm0 | ymm1 | ymm2 | ymm3 | ymm4 | ymm5 | ymm6 | ymm7 |
AVX-512 | 512 | zmm0 | zmm1 | zmm2 | zmm3 | zmm4 | zmm5 | zmm6 | zmm7 |
Opmask | 64 | k0 | k1 | k2 | k3 | k4 | k5 | k6 | k7 |
界 | 128 | bnd0 | bnd1 | bnd2 | bnd3 |
内存格
编辑CPU处理数据时, 暂存器容量有限, 大部分数据都是存在记忆体中. 那怎样存取记忆体中的数据呢? 可以想像记忆体中有各种尺寸的格子, 就叫内存格好了. 格之最小单元为一字节. 计算机非常灵活, 可以定义和预留任何尺寸的格. 常见格尺寸与暂存器尺寸一样, 方便数据交换. 大格常用于跟硬盘交换数据, 主要是文件.
1. 内存格的定义:
- 定义单个或多个数据:
数据定义指示符 一个或多个算式 ;算式值即格之内容
例
db 0x55, 0xaa, 0x55 ;定义三个字节格值分别为0x55, 0xaa, 0x55
- 定义字串:
数据定义指示符 任意长字串 ;字串即格之内容, 数据定义指示符db定义字节串; du定义词串, 每个词高字节为0
- 定义长指针:
数据定义指示符 算式1:算式2 ;此处数据定义指示符为dp, df, dd, dt之一, 用于定义指针.
例
dp或df 式1:式2 ;定义之长指针高字=式1, 低双字=式2
dd 式1:式2 ;定义之长指针高字=式1, 低字=式2
dt 式1:式2 ;定义之长指针高字=式1, 低四字=式2
当dt只带一个算式时, 此算式值用于FPU扩展双精度浮点值.
- 定义多个备份:
数据定义指示符 备份数 dup 一个或(多个算式, 算式间隔以逗号) ;定义多个备份, 定义<备份数>个<一个或(多个算式, 算式间隔以逗号)>备份.
- 从文档中取内容:
file '档名'{:档内偏移, 默认档首},{要取字节数, 默认取至档尾} ;算式值即格之内容, 花括号参数可选
例
file '雪山飞狐' ;取文档'雪山飞狐'全部内容
file '雪山飞狐':100h, 1024 ;从'雪山飞狐'偏移100h处往后取1024字节
2. 内存格预留:
数据预留指示符 格尺寸; 格尺寸可为任何算式
数据定义指示符和数据预留指示符统称数据指示符. FASM中的数据指示符见下表.
尺寸/字节 | 定义符 | 预留符 |
---|---|---|
1 | db,file | rb |
2 | dw,du | rw |
4 | dd | rd |
6 | dp,df | rp,rf |
8 | dq | rq |
10 | dt | rt |
值, 恒量, 标签, 特殊符号与算式
编辑算式
编辑算式可以是单独的值, 恒量, 标签, 也可以是值, 恒量, 标签, 算符(算术符和位算符)和括号构成的算数表达式. 算式值在源码编译时确定, 靶容器溢出或超出FASM能力会有编译错误提示. 算符有不同的优先级, 可被括号改变. 在下面的算符优先级表中, 数值大优先级高.
算符 | 优先级 |
---|---|
+ - | 0 |
* / | 1 |
mod | 2 |
and or xor | 3 |
shl shr | 4 |
not | 5 |
bsf bsr | 6 |
rva plt | 7 |
表中算符含义:
- +,-,*,/为标准算术符, mod为取余
- and, or, xor, shl, shr, bsf, bsr 和 not为位算符, 操作同同名汇编指令
- rva和plt为特殊单目算符, 用于各类地址转换, 限用于极少汇编输出程序中, 具体操作与上下文相关.
值
编辑- 整数默认为十进制表示. 二进制后缀以b, 八进制后缀以o, 十六进制后缀以h或前缀以0x(C语言风格)或$(Pascal风格, 不建议使用)
- 算式中的字串被转换成整数, 权序从左至右升高, 与日常书写顺序相反.
- FASM不支持编译时进行浮点数运算, 算式中只能含单独的单精度浮点数, 后缀以f, 或含小数点, 或书以科学计数法. 如2f, 2.0, 2E0表示同一浮点数, 而2是整数.
特殊符号
编辑4个可用于算式中的特殊符号:
- $ 当前偏移
- $$ 当前供数空间基址
- % 循环源码当前循环次数
- %t 编译时之时戳
恒量与标签
编辑过多数值会造成程序难读. 对数值取名, 即得恒量与标签.
- 定义恒量
恒量名=算式 ;可定义多次, 用式取其前面行中该恒量名最近一次定义. 若只定义一次, 可在其定义的源码文件中任何位置引用, 不分前后
例:
身高=165 ;
- 定义标签. 标签只可定义一次, 可在其定义的源码文件中任何位置引用, 不分前后. 标签实为指针.
1. 码段中的标签用于标记码位:
标签名: {指令行} ;标签名后缀以冒号即定义了该标签, 其值为所在码中此处地址, 用于标记码位. 花括号命令行可选.
例:
开始: ;
2. 数段中的标签用于标记数值首地址:
标签名 数据指示符 一个算式或(多个算式隔以逗号) ;标签名即该处算式编译后数值内存首址, 为指针名, 类型由数据指示符确定. 见例.
例
身高 db 165, 170, 181 ; 定义了标签身高, 身高存储的是165的地址, 乃字节指针
mov ax,身高 ; 地址搬入ax
mov al,[身高] ; 165搬入al
mov al,ptr 身高 ; 165搬入al
mov ax,[身高] ; 编译错, 源靶尺寸不匹配
mov ax,word [身高] ; 165, 170搬入ax, al=165, ah=170
3. 用 label 指示符定义标签
label 标签名 {:} {尺寸符} {at} {算式, 其值乃标签之内容} ; 最灵活的标签定义方式, 若无参数算式, 则标签值为当前地址
例
label 双高 word at 身高 ; '身高'为上例之标签, '双高'定义为始于'身高'地址的16位值(两个字节)的标签
mov ax, [双高] ; 等价于 mov ax,word [身高]
4. 特殊标签:
- 局部标签(层次标签)
- 前缀以'.'(点)之标签名为局部标签, 前缀以其前面最近的全局标签构成此标签全名, 其简名可在下一个全局标签前随处使用
- 前缀以'..'(双点)之标签名为全局标签的引用, 不能用于局部标签的新前缀
- 无名标签
- @@ 无名标签, 数目不限
- @b,@r 引用前面最近的无名表情 (b-before, 前面)
- @f 引用后面最近的无名标签 (f-follow, 随后)
跳转与呼叫
编辑跳转或呼叫 尺寸符 远近符 [地址算式] ; 远近符: short, near, far
例:
jmp dword [0] ; 16位模式中默认为远跳, 32位模式中默认为近跳, 可用远近符修改
jmp near dword [0] ; 强制为近跳
jmp far dword [0] 强制为远跳
跳转或呼叫 尺寸符 立即数 ; 默认生成最短跳, 除非用远近符修改
尺寸设定
编辑默认生成指令之规则为最小资源化, 除非有尺寸符明确指定.
指令 {尺寸符} [地址] ; 无尺寸符时默认以最短位移生成最小指令
指令 操作数, {尺寸符} 立即数 ; 这里指令为adc, add, and, cmp, or, sbb, sub 和 xor, 无尺寸符时, 若立即数可表为8位有符号数, 则16-位或32-位操作数默认生成为8位. imul指令尾操作数为立即数时遵循同样规则
push {尺寸符} 立即数 ; 无尺寸符时, 此立即数于16位模式中当作词, 32位模式中作双词, 若可行则生成8位式指令. 尺寸符word或dword强制生成push长式指令
pushw或pushd强制fasm生成16位或32位码而非长式指令.