學習 nasm 語言
學習 nasm 語言
3. nasm assembly 語法
- 3.1 nasm 是匹分大小寫
- 3.2 內存操作數表達式
- 3.2.1 在 nasm 語法裏,對 memory 操作數需要加 [] 括號
- 3.2.2 給 memory 操作數提供一個 displacement 值
- 3.2.3 指明 memory 操作數的 operand size
- 3.2.4 提供一個 segment
- 3.2.5 指明 memory 操作數的 address size
- 3.3 nasm 偽指令
- 3.3.1 nasm 定義的 7 種數據 size
- 3.3.2 定義初始化數據:db 家族
- 3.3.3 定義非初始化數據:resb 家族
- 3.3.4 包含 binary 文件
- 3.3.5 使用 equ 定義常量
- 3.3.6 使用 times 重複寫數據或指令
- 3.4 常量值
- 3.4.3 nasm 中的轉義字符
- 3.4.4 字符串常
- 3.4.5 Unicode 字符串
- 3.4.6 浮點數常量
3.1 nasm 是區分大小寫
例如:符號 foo 與 FOO 是兩個不同的標識符。
3.2 內存操作數表達式
3.2.1 在 nasm 語法裏,對 memory 操作數需要加 [ ] 括號
下麵的代碼:
foo equ 1 bits 32 mov eax, foo |
第 2 指令的意圖是:將 bar 內 的值賦給 ebx 寄存器。但這樣是錯誤的,nasm 隻會把 bar 當作是 immediate 賦給 ebx
00000000 0200 ; bar 變量 |
因此,需要將 bar 用 [ ] 括起來
mov eax, foo |
nasm 就編譯出正確的代碼:
00000000 0200 ; bar |
3.2.2 給 memory 操作數提供一個 displacement 值
下麵代碼展示了 [base + disp] 的尋址方式:
section .bss buffer resb 10
bits 32 mov byte [buffer + 0x01], 'a' |
3.2.3 指明 memory 操作數的 operand size
下麵展示了為 memory 操作數提供一個 size 情況:
mov byte [buffer + 0x01], 'a' |
代碼中使用 byte 關鍵字對 memory 操作數進行了修飾,指明 memory 操作數的大小為 byte
在這方麵,nasm 的語法與微軟的 masm 的語法(Intel 語法)有些不同,masm 的語法是:
mov byte ptr [buffer + 0x01], 'a' |
在 masm 語法中需配合 ptr 指示字。
3.2.4 提供一個 segment
大多數 指令/內存操作數 缺省的 segment 是 DS,x86/x64 允許為 memory 操作數提供另一個 segment 進行 segment override
在 nasm 語法中,如下:
mov byte [es:buffer + 0x01], 'a' |
nasm 語法中,在 [ ] 括號內提供 segment,不能在 [ ] 括號外提供 segment
而 masm 的語法中是在 [ ] 括號外提供 segment,如下:
mov byte ptr es:[buffer + 0x01], 'a' |
3.2.5 指明 memory 操作數的 address size
有些情況下必須指明 memory 操作數的 address size,否則編譯結果可能不是你想要的結果。下麵的例子說明,如何為 memory 操作數指明address size
例 1:
section .bss buffer resb 10
bits 64 mov rax, [qword buffer] ; 指明 64 位的 address size(絕對地址) |
在 nasm 中,對於 絕對地址 形式,缺省是 32 位的,因此,需要明確使用 qword 來指明 64 位的 address size
這段代碼編譯後為:
00000000 48A11400000000000000 mov rax,[qword 0x14] ; 64 位地址 |
它們的區別就是一個使用了 64 位地址,一個使用了 32 位地址。
例 2:
section .bss buffer resb 10
bits 16 mov byte [es:dword buffer + 0x01], 'a' ; 指明為 32 位地址 |
上麵代碼是 16 位代碼,使用了 dword 指明 memory 操作數是 32 位的地址。
它被編譯為:
00000000 2667C6051D000000 mov byte [dword es:0x1d],0x61 |
16 位的 address size 被 override 為 32 位地址。
3.3 nasm 偽指令
偽指令不是 x86/x64 機器的真實指令,偽指令是用於給編譯器指示如何進行編譯。
3.3.1 nasm 定義的 7 種數據 size
- byte : 8 位
- word : 16 位
- dword : 32 位
- qword : 64 位
- tword : 80 位
- oword : 128 位
- yword : 256 位
oword 可以對應 Microsoft MASM 的 xmmword 類型,yword 對應 Microsoft MASM 的 ymmword 類型。
tword, oword 以及 yword 使用在 非整型 數據,使用在 float 和 SSE 型數據。
3.3.2 定義初始化數據:db 家族
nasm 定義了用於初始化上麵 7 種 size 的 db 家族,它們用於定義初化常量值。
- db : define byte
- dw :define word
- dd :define doubleword
- dq :define quadword
- dt :define tword
- do :define oword
- dy :define yword
正如前麵所說的:dt, do, dy 不接受整型數值常量,它們被使用在定義 float 或 SSE 數據常量。dt 可以定義 extended-precision float 數據,do 可以定義 quad-precision float,dy 可定義 ymm 數據。而 dq 可以定義 double-precision float 數據,dd 可以定義 single-precision float 數據。
下麵是 NASM Manual 上的例子:
db 0x55 ; just the byte 0x55 |
3.3.3 定義非初始化數據:resb 家族
程序中使用到的非初始化數據通常放在 bss section 裏,bss 代表 uninitialized storage space
nasm 使用了 resb(reserve byte) 家族來定義非初始化數據。
- resb :reserve byte
- resw :reserve word
- resd :reserve doubword
- resq :reserve quadword
- rest :reserve tword
- reso :reserve oword
- resy :reserve yword
resb 相當於 Microsoft MASM 語法中的 db ?
下麵是 NASM Manual 的例子:
buffer: resb 64 ; reserve 64 bytes |
3.3.4 包含 binary 文件
nasm 提供了一種包含 binary(二進製)文件的方法:使用 incbin 偽指令。incbin 偽指令包含的 binary 文件將直將寫入輸出文件中。此偽指令的作用是包含 graphics 以及 sound 這類數據文件。
incbin "file.dat" ; include the whole file |
3.3.5 使用 equ 定義常量
equ 用來為標識符定義一個 整型 常量,它的作用類似 C 語言中的 #define
a equ 0 ; OK
string db 'hello,word',0 section .text _entry: |
例子中: b 定義為常量 'abcd' 它將是字符串的 ASCII 碼序列,‘abcdefghi' 常量將會被截斷,整型常量最長為 quadword(8 bytes),而 d 企圖被定義為一個 float 常量,這產生會錯誤。len 和 textlen 被定義為編譯期確定的數值。
3.3.6 使用 times 重複寫數據或指令
times 是一個比較實用偽指令,用來重複定義數據或指令。
下麵是一個經典的使用例子:
times 510-($-$$) db 0 |
這段代碼經常出現在 boot 磁盤 MBR 引導代碼中,目的是除了最後 2 個字節和 code 代碼外的區域全部寫 0 值。
times 還可以使用在重複寫某一條指令,如下:
times 10 nop |
這段代碼結果是重複填入了 10 條 nop 指令:
00000000 90 nop |
3.4 常量值
nasm 下可以接受 4 種常量:整型常量,字符常量,字符串常量以及浮點常量
3.4.1 整型常量
在 nasm 中,常用的整型進製有 4 種:
- decimal :十進製數
- hex :十六進製
- binary :二進製數
- octal :八進製數
每一種進製都有前綴和後綴表示法。當數值無前綴和後綴時,它是十進製數。因為缺省是十進製。
3.4.1.1 十進製數表示方法
看一看,下麵的例子:
mov ax,200 ; decimal |
十進製的前綴是:0d, 後綴是:d
3.4.1.2 十六進製數表示方法
十六進製使用 0123456789ABCDEF 來表示 16 個數值。類似地,它的前綴是:0h 或 0x (c/c++ 風格)以及 $0(pascal 風格),後綴是:h
mov ax, 0c8h ; hex |
上麵例子中的 hex 數,表明:當以 h 後綴結尾時,如果含有字母,必須要以 0 開頭。
mov ax,$0c8 ; hex again: the 0 is required |
上麵是 pascal 風格的十六進製表示法,使用前綴 $0 (0 是必須的)
mov ax,0xc8 ; hex yet again |
上麵是使用 0h 前綴和 C/C++ 風格的 0x 表示十六進製數。
3.4.1.3 八進製數表示方法
八進製的前綴可以是:0o 或 0q 後綴可以是:o 或 q
mov ax,310q ; octal |
3.4.1.4 二進製數表示方法
類似地,二進製的前綴是:0b 後綴是:b
mov ax,11001000b ; binary |
3.4.2 字符常量
在 nasm 中,可以使用 3 種引號來提供字符
- '...'(單引號)
- "..."(雙引號)
- `...`(反引號)
如下示例,它們的結果是一樣的:
db 'abcd' |
3.4.2.1 提供字符常量
下麵看看如何提供字符量:
mov eax, 'a' ; eax = 0x61 |
第 3 條企圖賦超過 4 bytes 的字符常量給 eax, 編譯器會截斷為 4bytes 再賦給 eax, 而第 4 條是另一種字符常量表示法,使用轉義字符表示。
可見:字符常量是以 little-endian 排列
3.4.3 nasm 中的轉義字符
在 nasm 中使用 c 風格的轉義字符,在 \ (反斜杠符)後麵跟 轉義碼:\ escape-code
轉義碼(escape-code)包括:字符轉義碼, 八進製轉義碼, 十六進製轉義碼
注意:nasm 中的轉義符必須要用 ` `(反引號)來引用
db `\x61` ; right! 'a' |
第 1 個用反引號來包含轉義符是正確的。而第 2 個用單引號來包含轉義符,nasm 卻視它為一般的字符串對待
3.4.3.1 字符轉義碼
下麵是一些例子:
\' single quote (') |
3.4.3.2 八進製轉義碼
\ 後麵最多可以跟著 3 位數字,構成八進製轉義碼,如下所示:
\377 Up to 3 octal digits - literal byte |
3.4.3.3 十六進製轉義碼
十六進製轉義碼以 x 或 X 開頭,如下所示:
db `\x61` ; 'a' |
上麵所示:十六進製轉義碼可以連串提供。
3.4.4 字符串常量
字符串是逐個逐個提供字符,看以下例子:
db 'hello' ; string constant |
提供字符串常量,是從左到右依次寫入到內存。
這裏要注意的是:字符常量與字符串常量的區別,看一看下麵的例子
buffer db 'hello' ; 字符串常量 mov eax, 'hello' ; 字符常量 |
字符常量與字符串常量最大區別就是:字符常以 littlen-endian 存儲,而字符串常量是從左到度
3.4.5 Unicode 字符串
nasm 定義了兩個操作數符來定義 Unicode 字符串:
- __utf16__
- __utf32__
下麵是 nasm 裏的例子:
%define u(x) __utf16__(x) |
3.4.6 浮點數常量
浮點數變量可以使用 DB, DW, DD, DQ, DT 以及 DO,浮點數常量使用 __float8__, __float16__, __float32__, __float64__, __float80m__,__float80e__, __float128l__ 以及 __float128h__ 來定義。
下麵是 nasm 提供的例子:
db -0.2 ; "Quarter precision" |
3.5 表達式
在 nasm 裏的表達式很像 C 表達式,對於熟悉 C 表達式的人來說幾乎可以馬上上手。
3.5.1 $ 與 $$ 標號
$ 標號表示 nasm 編譯後當前指令位置
$$ 標號表示當前 section 起始位置
看看下麵的例子:
bits 64 section .rdata |
它的編譯結果是:
00000000 48B8000000000000 mov rax,0x0 |
3.5.2 位運算符
與 C 一樣,包括下麵:
位運算符
|
描述
|
&
|
位與: AND
|
|
|
位或:OR
|
~
|
位非: NOT
|
^
|
位異或: XOR
|
<<
|
左移
|
>>
|
右移
|
3.5.3 算術運算符
下麵是 nasm 所支持的算術運算符
算術運算符
|
描述
|
+
|
加
|
-
|
減
|
*
|
乘
|
/
|
除(無符號數)
|
//
|
除(符號數)
|
%
|
取模(無符號數)
|
%%
|
取模(符號數)
|
版權 mik 所有,轉載請注明出處!
最後更新:2017-04-04 07:03:16