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. 特殊標籤:

  1. 局部標籤(層次標籤)
    1. 前綴以'.'(點)之標籤名為局部標籤, 前綴以其前面最近的全局標籤構成此標籤全名, 其簡名可在下一個全局標籤前隨處使用
    2. 前綴以'..'(雙點)之標籤名為全局標籤的引用, 不能用於局部標籤的新前綴
  2. 無名標籤
    1. @@ 無名標籤, 數目不限
    2. @b,@r 引用前面最近的無名表情 (b-before, 前面)
    3. @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位码而非长式指令.