[原]nasm语法
工具:
nasm 匯編
gcc? 編譯c
ld??? 進行鏈接
kscope 查看源代碼
make 工程管理
khexedit? 分析二進制文件
一:
nasm源文件布局:
像其他匯編器一樣, nasm源文件包含四個域的組合。(除了宏, 或者預編譯器指示, 或者匯編指示 )
label標號: 指令 操作數 ;注釋
通常, 這些域是可選的。 當然, 操作數域是根據指令的要求來放置,或者去掉的。
nasm使用/作為行鏈接符, 如果一行以/結尾, 下一行認為是本行的繼續.
nasm對于空格沒有限制; 標號可以在前面包含空格, 或者指令前可以沒有空格. 標號后的冒號是可選的. (可以使用-w+orphan-label選項來提示某行只有標號).
標號中的字符包括字母, 數字, _$#@~.?? 可以字母開頭,? . (.有特殊的含義!), _和? 也可以作為頭部. 一個標識符可能也有$前綴, 表明是作為標識符讀取的, 并不是保留字; 因此, 如果你鏈接的其他模塊定義了符號eax, 你可以通過$eax去區分符號和寄存器. 標識符最大的長度為4095.
指令域可能包含任何機器指令: 奔騰指令, 奔6指令, FPU指令, MMX指令, 甚至未文檔化的指令,都可以被支持. 指令可能包含前綴LOCK, REP, REPE, REPZ, 或者REPNZ, REPNE. 顯式的地址大小和操作數大小前綴A16, A32, A64, O16 和O32, O64 也被提供了. 一個使用他們的例子在10章.
你可以使用段寄存器名字作為指令前綴: 編碼 es mov [bx], ax 等價于 mov [es:bx], ax.? 但是對于LODSB等類似指令, 沒有操作數, 但是也需要一個段寄存器, 除了es lodsb 沒有其他辦法.
一個指令一下情況需要前綴: 前綴是cs, a32, lock, repe可以獨立出現在一行, nasm會生成帶前綴的代碼.
另外, 對于實際的機器指令, nasm支持偽指令.
指令操作數有很多形式: 寄存器, 有效地址, 常數, 或者表達式.
對于x87浮點指令, nasm接受叫大范圍的語法, 使用雙操作數, 或者使用nasm本地單操作數.例如
fadd st1
fadd st0, st1
fadd st1, st0
fadd to st1
幾乎所有x87引用內存的浮點指令都使用前綴DWORD, QWORD, TWORD, 表明內存操作數的大小.
2偽指令:
?DB DW DD DQ DT DY; 他們的未初始化對應物是RESB RESW RESD RESQ REST RESO和 RESY, INCBIN命令, EQU命令, TIMES前綴.
2.1DB聲明初始化數據
db? 0x55?? db 0x55, 0x56, 0x57
db 'a', 0x55
db 'hello', 13, 10, '$'
dw 0x1234
dw 'a'?? ;數字
dw 'abc' ;對其二字節?
dd 0x12345678
dd 1.234567e20
dq 0x1234567abc
dq 1.23456e20
dt? 1.2345e20
DT, DO, DY 不接受數字常量作為操作數
2.2RESB? 聲明為初始化數據
RESB RESW RESQ RESD REST RESO RESY 用來聲明模塊的BSS區域: 聲明為初始化的存儲區域(block start by symbol). 每個產生一個操作, 字節數, 字數, 雙字數, 或者其他要保留的大小. RESB類型偽指令是一個重要的表達式.
例如:
buffer:? resb 64
wordvar: resw 1
realarray: resq 10
ymmval: resy? 1 在ymm寄存器中
2.3INCBIN包含外部二進制文件:
INCBIN從早期的DevPac匯編器中借來的: 包含一個二進制文件verbatim到輸出文件中去. 這可以便于包含圖形文件, 聲音文件直接到一個游戲執行文件中去. 可以有一下3種調用方式:
incbin "file.dat"?? 整個文件
incbin "file.dat", 1024? 忽略頭1024字節
incbin "file.dat", 1024, 512 忽略頭1024字節, 最多包含512字節
INCBIN即是指示, 也是宏.
2.4EQU:定義常數
EQU定義一個符號賦值常數: 當使用EQU, 源代碼必須包含標號.
message? db? 'hello'
mslen?? equ?? $-message
2.5TIMES: 重復指令或者數據
TIMES前綴引起指令匯編多次. 等價于DUP
zerobuf:?? times? 64? db 0
或者類似; 但是TIMES功能更多. times的參數不僅僅是數字常量, 也可以是表達式
buffer: db? 'hello'
times? 64? -$+buffer? db ' '
將會保存足夠的空間, 使buffer達到64. 最后, times可以應用到一般指令, 你可以編碼平凡非回轉循環在其中:
times? 100? movsb
注意到: times 100 resb? 1 和 resb 100沒有區別, 除了后者可以更快的匯編.
times的操作數是重要的表達式.
注意到times不能應用到宏中: 原因是times在宏階段后處理, 允許times使用參數包含表達式, 例如64-$+buffer.
為了重復多余一行的代碼, 或者復雜宏, 使用預編譯指令%rep
3有效地址:
一個有效地址是任何操作數, 在指令中引用內存. 有效地址, 在nasm中有很簡單的語法: 由表達式組成, 等價于期望的地址, 被方括號包圍:
wordvar? dw 123
mov?? ax , [wordvar]
mov?? ax, [word+1]
mov?? ax, [es:wordvar +bx]
任何不符合這個規則的東西都不是有效的內存引用.例如: es:wordvar[bx]
更復雜的有效地址, 例如包含多個寄存器:
mov? eax , [ebx*2 + ecx + offset]
mov ax, [bp + di + 8]
nasm有能力對這些有效地址作代數運算, 因此這些看起來不合法的表達式, 是正確的:
mov? eax, [ebx*5] ;匯編為 ebx*4 + ebx
mov? eax, [label1*2-label2] ;匯編為: label1 + (label1 - label2)
一些形式是有效地址, 含有超過一種匯編形式; 大多數情況下, nasm會生成最小的形式. 例如對于[eax*2 + 0]和[eax + eax], 有兩種不同的匯編形式, nasm會生成后者.
nasm有一個提示機制, 可以使[eax+ebx] 和[ebx+eax]生成不同的代碼; 這個偶爾有用, 因為[esi+ebp]和[ebp+esi]有不同的默認段寄存器.
然而, 你可以強制nasm生成有效地址以特殊形式, 通過使用關鍵字BYTE, WORD, DWORD, NOSPLIT. 如果你使用[eax+3]匯編成雙字偏移, 而不是單字節, 你可以使用[dword eax+3].
類似的, 你可以強制nasm使用單字節偏移對一個小的數值, 沒有在第一遍中發現.,[byte eax+offset].
作為特例, [byte eax]編碼[eax+0], 使用一個字節偏移0, [dword eax]編碼雙字偏移. 正常形式[eax]沒有偏移域.
以上描述的在你從16位代碼中訪問32位段中的數據時也是有用的. 可以查看10.2混合大小尋址章.
特別地, 如果訪問已知偏移的數據比當前16位值大, 如果你不指明這是個dword偏移, nasm將會使偏移的高字節丟失.
類似的, nasm會分割[eax*2]為[eax+eax]因為允許偏移部分被省略, 空間節省; 事實上, 他也會分割[eax*2 + offset]為[eax+eax +offset]. 你可以通過使用NOSPLIT來抵抗這種行為: [nosplit eax*2]強制按字面生成[eax*2 + 0].
64位模式下, nasm會默認生成絕對地址. rel關鍵字使之生成rip相關地址.
3.5常數:
nasm理解四種形式的常數:數字, 字符, 字符串, 浮點數.
4.1數字常數:
nasm允許你指定數字以各種進制: 你可以添加后綴H, X, Q, O, B用于16進制, 8進制, 2進制, 你也可以使用0x, 或者前綴$.
當前nasm使用0h 0o 0q 0b只是16, 8 ,2進制.
例如:
mov? ax? , 200
mov? ax, 0200
mov? ax, 0200d
mov ax, 0d200
mov ax, 0c8h
mov ax, $0c8
mov ax 310o
mov ax, 11001000b
4.2字符串:
字符串由"", '', ``包含. 單引號, 雙引號等價的, 反引號用于特殊字符.
db? `/u263a`
db `/xe2/x98/xba`
db 0e2h, 098h, 0bah
4.3字符常量
mov? eax, 'abcd'
4.4字符串常量
db? 'hello'
4.6浮點數
db? -0.2
dw -0.5
dd? 1.2
dd 1.222222222
dd 0x1p+2
dq 1.e10
5表達式:
nasm表達式類似于c. 表達式等價于64為整數, 將會在后來被調整到合適大小.
nasm支持兩種表達式詞法記號, 允許在當前匯編位置計算: $和$$詞法記號. $計算匯編位置, 在包含行的開始; 所以你可以編碼無限循環 JMP $. $$計算當前段開始; 所以你可以通過$-$$得知在當前段中的位置.
nasm提供算術操作:
|位或, ^異或 &位與 << >>位移 + - 加減, * / // % %% 乘法和除法
/無符號乘法, //有符號除法, %無符號, %%有符號求模操作.
nasm不提供對于有符號的求模操作符的強力操作的保證.
因為%字符被宏預編譯擴展使用, 你應該保證被空格后接有符號, 無符號求模操作符.
單操作符: + - ~ ! SEG
~求補, !求反, SEG求操作數段地址.
6SEG WRT
當寫16位大程序, 必須被分割為多個小段, 因此很有必要去定位段的地址的一部分, 通過一個符號. NASM支持seg操作符, 來完成這個功能.
seg操作符返回符號所在的段的基址, 定義段基地址相對于符號的偏移是有意義的. 因此代碼:
mov? ax, seg symbol
mov? es, ax
mov bx, symbol
將會加載ES:BX指向符號的有效指針.
事情可能會比這個復雜: 因為16位段和組可能會重疊, 你可能偶爾希望通過不同的段基地址來引用一些符號. nasm允許這樣作, 通過使用wrt關鍵字, 你可以這樣做:
mov? ax, werid_seg
mov? es, ax
mov? bx, symbol wrt werid_seg
去用不同的, 但是功能等價的指針指向符號symbol 加載到es:bx.(with reference to)
nasm支持段內的遠調用, 和遠跳轉, 通過call segment:offset, segment, 和offset均代表立即數值. 因此要遠調用一個過程, 你可能編碼如下:
call??? (seg? procedure): procedure
call??? weird_seg : (procedure wrt weird_seg)
加入括號是為了清楚, 展示以上指令語法分析的目的.
nasm支持語法call far procedure 作為上面第一種的同義詞. jmp在以上例子中功效等同于call:
為了聲明一個對數據的遠指針在數據段中, 你應該這樣:
dw?? symbol,? seg? symbol
nasm沒有類似的同義語, 雖然你可以使用宏來發明一個.
7抑制優化 STRICT
當在2或以上優化選項下, 匯編代碼, nasm會使用大小限定符, 但是會給他們最小的大小. 關鍵字strict可以用于抑制這種優化.
例如: 在16位模式下:
push dword 33
被編碼為66 6a 21, 而? push dword 33編碼為 66 68 21 00 00 00
8關鍵表達式:
盡管nasm有可選的多邊優化, 有若干表達式必須在第一遍中被解析, 這些稱為關鍵表達式.
第一遍用于決定所有匯編代碼的大小, 在第二遍, 當生成所有的代碼時, 知道所有的代碼引用的符號地址. 因此, nasm不能處理的事是代碼大小決定于后面聲明的符號的值, 在代碼被提問時. 例如:
times (label-$) db 0
label: db? 'where am i'
這種情況下times的參數合法的等價于任何值; nasm將會拒絕這種情況, 因為他不能在首次見到時知道times行的大小.
times (label-$+1) db 0
label: db "now where am i"
這種情況下, 任何值都錯.
nasm拒絕這些例子, 通過一個叫做關鍵表達式的概念, 被定以為一個表達式, 其值需要在第一遍中計算出來, 因此只能依賴于前面定義的符號. times的參數是關鍵表達式.
本地變量:
對于以.開始的符號, nasm給予特殊的對待. 一個標號以一個原點開始, 被認為是局部變量, 意味著和以前的非局域變量存在聯系, 例如:
label
.loop
jne? .loop
ret
label2
.loop
jne .loop
ret
在上面的代碼片段中, 每個jne指令跳轉到前面的行, 因為兩個.loop的定義是隔離的通過前面的非局部變量的聯系的效力.
這種局部標號的處理借鑒于amiga匯編器; 然而, nasm更進了一步, 允許訪問局部變量從代碼的另一個部分. 這通過定義局部變量根據前面的非局部變量: 第一個.loop的定義實際是定以為label1.loop, 第二個是label2.loop, 因此, 你如果真的需要
label3
jmp label1.loop
有時是有用的, 在宏里, 例如, 可以定義一個標號可以從任何地方引用, 但是不會干預正常的局部標號機制. 這種標號不能是非局部的, 因為定義他的宏不知道label的全名. nasm因此引入了第三類標號, 可能值在宏中使用: 如果以..@開始的一個標號, 不會對局部標號產生作用:
label
.local:
..@foo:
label2:
.local:
jmp ..@foo
nasm有能力去定義其他特殊符號, 以..開始例如
..start, 用來指定obj文件的入口.
?
?
作者:liyonghelpme 發表于2010/6/11 18:19:00 原文鏈接 閱讀:2221 評論:0 查看評論
nasm 匯編
gcc? 編譯c
ld??? 進行鏈接
kscope 查看源代碼
make 工程管理
khexedit? 分析二進制文件
一:
nasm源文件布局:
像其他匯編器一樣, nasm源文件包含四個域的組合。(除了宏, 或者預編譯器指示, 或者匯編指示 )
label標號: 指令 操作數 ;注釋
通常, 這些域是可選的。 當然, 操作數域是根據指令的要求來放置,或者去掉的。
nasm使用/作為行鏈接符, 如果一行以/結尾, 下一行認為是本行的繼續.
nasm對于空格沒有限制; 標號可以在前面包含空格, 或者指令前可以沒有空格. 標號后的冒號是可選的. (可以使用-w+orphan-label選項來提示某行只有標號).
標號中的字符包括字母, 數字, _$#@~.?? 可以字母開頭,? . (.有特殊的含義!), _和? 也可以作為頭部. 一個標識符可能也有$前綴, 表明是作為標識符讀取的, 并不是保留字; 因此, 如果你鏈接的其他模塊定義了符號eax, 你可以通過$eax去區分符號和寄存器. 標識符最大的長度為4095.
指令域可能包含任何機器指令: 奔騰指令, 奔6指令, FPU指令, MMX指令, 甚至未文檔化的指令,都可以被支持. 指令可能包含前綴LOCK, REP, REPE, REPZ, 或者REPNZ, REPNE. 顯式的地址大小和操作數大小前綴A16, A32, A64, O16 和O32, O64 也被提供了. 一個使用他們的例子在10章.
你可以使用段寄存器名字作為指令前綴: 編碼 es mov [bx], ax 等價于 mov [es:bx], ax.? 但是對于LODSB等類似指令, 沒有操作數, 但是也需要一個段寄存器, 除了es lodsb 沒有其他辦法.
一個指令一下情況需要前綴: 前綴是cs, a32, lock, repe可以獨立出現在一行, nasm會生成帶前綴的代碼.
另外, 對于實際的機器指令, nasm支持偽指令.
指令操作數有很多形式: 寄存器, 有效地址, 常數, 或者表達式.
對于x87浮點指令, nasm接受叫大范圍的語法, 使用雙操作數, 或者使用nasm本地單操作數.例如
fadd st1
fadd st0, st1
fadd st1, st0
fadd to st1
幾乎所有x87引用內存的浮點指令都使用前綴DWORD, QWORD, TWORD, 表明內存操作數的大小.
2偽指令:
?DB DW DD DQ DT DY; 他們的未初始化對應物是RESB RESW RESD RESQ REST RESO和 RESY, INCBIN命令, EQU命令, TIMES前綴.
2.1DB聲明初始化數據
db? 0x55?? db 0x55, 0x56, 0x57
db 'a', 0x55
db 'hello', 13, 10, '$'
dw 0x1234
dw 'a'?? ;數字
dw 'abc' ;對其二字節?
dd 0x12345678
dd 1.234567e20
dq 0x1234567abc
dq 1.23456e20
dt? 1.2345e20
DT, DO, DY 不接受數字常量作為操作數
2.2RESB? 聲明為初始化數據
RESB RESW RESQ RESD REST RESO RESY 用來聲明模塊的BSS區域: 聲明為初始化的存儲區域(block start by symbol). 每個產生一個操作, 字節數, 字數, 雙字數, 或者其他要保留的大小. RESB類型偽指令是一個重要的表達式.
例如:
buffer:? resb 64
wordvar: resw 1
realarray: resq 10
ymmval: resy? 1 在ymm寄存器中
2.3INCBIN包含外部二進制文件:
INCBIN從早期的DevPac匯編器中借來的: 包含一個二進制文件verbatim到輸出文件中去. 這可以便于包含圖形文件, 聲音文件直接到一個游戲執行文件中去. 可以有一下3種調用方式:
incbin "file.dat"?? 整個文件
incbin "file.dat", 1024? 忽略頭1024字節
incbin "file.dat", 1024, 512 忽略頭1024字節, 最多包含512字節
INCBIN即是指示, 也是宏.
2.4EQU:定義常數
EQU定義一個符號賦值常數: 當使用EQU, 源代碼必須包含標號.
message? db? 'hello'
mslen?? equ?? $-message
2.5TIMES: 重復指令或者數據
TIMES前綴引起指令匯編多次. 等價于DUP
zerobuf:?? times? 64? db 0
或者類似; 但是TIMES功能更多. times的參數不僅僅是數字常量, 也可以是表達式
buffer: db? 'hello'
times? 64? -$+buffer? db ' '
將會保存足夠的空間, 使buffer達到64. 最后, times可以應用到一般指令, 你可以編碼平凡非回轉循環在其中:
times? 100? movsb
注意到: times 100 resb? 1 和 resb 100沒有區別, 除了后者可以更快的匯編.
times的操作數是重要的表達式.
注意到times不能應用到宏中: 原因是times在宏階段后處理, 允許times使用參數包含表達式, 例如64-$+buffer.
為了重復多余一行的代碼, 或者復雜宏, 使用預編譯指令%rep
3有效地址:
一個有效地址是任何操作數, 在指令中引用內存. 有效地址, 在nasm中有很簡單的語法: 由表達式組成, 等價于期望的地址, 被方括號包圍:
wordvar? dw 123
mov?? ax , [wordvar]
mov?? ax, [word+1]
mov?? ax, [es:wordvar +bx]
任何不符合這個規則的東西都不是有效的內存引用.例如: es:wordvar[bx]
更復雜的有效地址, 例如包含多個寄存器:
mov? eax , [ebx*2 + ecx + offset]
mov ax, [bp + di + 8]
nasm有能力對這些有效地址作代數運算, 因此這些看起來不合法的表達式, 是正確的:
mov? eax, [ebx*5] ;匯編為 ebx*4 + ebx
mov? eax, [label1*2-label2] ;匯編為: label1 + (label1 - label2)
一些形式是有效地址, 含有超過一種匯編形式; 大多數情況下, nasm會生成最小的形式. 例如對于[eax*2 + 0]和[eax + eax], 有兩種不同的匯編形式, nasm會生成后者.
nasm有一個提示機制, 可以使[eax+ebx] 和[ebx+eax]生成不同的代碼; 這個偶爾有用, 因為[esi+ebp]和[ebp+esi]有不同的默認段寄存器.
然而, 你可以強制nasm生成有效地址以特殊形式, 通過使用關鍵字BYTE, WORD, DWORD, NOSPLIT. 如果你使用[eax+3]匯編成雙字偏移, 而不是單字節, 你可以使用[dword eax+3].
類似的, 你可以強制nasm使用單字節偏移對一個小的數值, 沒有在第一遍中發現.,[byte eax+offset].
作為特例, [byte eax]編碼[eax+0], 使用一個字節偏移0, [dword eax]編碼雙字偏移. 正常形式[eax]沒有偏移域.
以上描述的在你從16位代碼中訪問32位段中的數據時也是有用的. 可以查看10.2混合大小尋址章.
特別地, 如果訪問已知偏移的數據比當前16位值大, 如果你不指明這是個dword偏移, nasm將會使偏移的高字節丟失.
類似的, nasm會分割[eax*2]為[eax+eax]因為允許偏移部分被省略, 空間節省; 事實上, 他也會分割[eax*2 + offset]為[eax+eax +offset]. 你可以通過使用NOSPLIT來抵抗這種行為: [nosplit eax*2]強制按字面生成[eax*2 + 0].
64位模式下, nasm會默認生成絕對地址. rel關鍵字使之生成rip相關地址.
3.5常數:
nasm理解四種形式的常數:數字, 字符, 字符串, 浮點數.
4.1數字常數:
nasm允許你指定數字以各種進制: 你可以添加后綴H, X, Q, O, B用于16進制, 8進制, 2進制, 你也可以使用0x, 或者前綴$.
當前nasm使用0h 0o 0q 0b只是16, 8 ,2進制.
例如:
mov? ax? , 200
mov? ax, 0200
mov? ax, 0200d
mov ax, 0d200
mov ax, 0c8h
mov ax, $0c8
mov ax 310o
mov ax, 11001000b
4.2字符串:
字符串由"", '', ``包含. 單引號, 雙引號等價的, 反引號用于特殊字符.
db? `/u263a`
db `/xe2/x98/xba`
db 0e2h, 098h, 0bah
4.3字符常量
mov? eax, 'abcd'
4.4字符串常量
db? 'hello'
4.6浮點數
db? -0.2
dw -0.5
dd? 1.2
dd 1.222222222
dd 0x1p+2
dq 1.e10
5表達式:
nasm表達式類似于c. 表達式等價于64為整數, 將會在后來被調整到合適大小.
nasm支持兩種表達式詞法記號, 允許在當前匯編位置計算: $和$$詞法記號. $計算匯編位置, 在包含行的開始; 所以你可以編碼無限循環 JMP $. $$計算當前段開始; 所以你可以通過$-$$得知在當前段中的位置.
nasm提供算術操作:
|位或, ^異或 &位與 << >>位移 + - 加減, * / // % %% 乘法和除法
/無符號乘法, //有符號除法, %無符號, %%有符號求模操作.
nasm不提供對于有符號的求模操作符的強力操作的保證.
因為%字符被宏預編譯擴展使用, 你應該保證被空格后接有符號, 無符號求模操作符.
單操作符: + - ~ ! SEG
~求補, !求反, SEG求操作數段地址.
6SEG WRT
當寫16位大程序, 必須被分割為多個小段, 因此很有必要去定位段的地址的一部分, 通過一個符號. NASM支持seg操作符, 來完成這個功能.
seg操作符返回符號所在的段的基址, 定義段基地址相對于符號的偏移是有意義的. 因此代碼:
mov? ax, seg symbol
mov? es, ax
mov bx, symbol
將會加載ES:BX指向符號的有效指針.
事情可能會比這個復雜: 因為16位段和組可能會重疊, 你可能偶爾希望通過不同的段基地址來引用一些符號. nasm允許這樣作, 通過使用wrt關鍵字, 你可以這樣做:
mov? ax, werid_seg
mov? es, ax
mov? bx, symbol wrt werid_seg
去用不同的, 但是功能等價的指針指向符號symbol 加載到es:bx.(with reference to)
nasm支持段內的遠調用, 和遠跳轉, 通過call segment:offset, segment, 和offset均代表立即數值. 因此要遠調用一個過程, 你可能編碼如下:
call??? (seg? procedure): procedure
call??? weird_seg : (procedure wrt weird_seg)
加入括號是為了清楚, 展示以上指令語法分析的目的.
nasm支持語法call far procedure 作為上面第一種的同義詞. jmp在以上例子中功效等同于call:
為了聲明一個對數據的遠指針在數據段中, 你應該這樣:
dw?? symbol,? seg? symbol
nasm沒有類似的同義語, 雖然你可以使用宏來發明一個.
7抑制優化 STRICT
當在2或以上優化選項下, 匯編代碼, nasm會使用大小限定符, 但是會給他們最小的大小. 關鍵字strict可以用于抑制這種優化.
例如: 在16位模式下:
push dword 33
被編碼為66 6a 21, 而? push dword 33編碼為 66 68 21 00 00 00
8關鍵表達式:
盡管nasm有可選的多邊優化, 有若干表達式必須在第一遍中被解析, 這些稱為關鍵表達式.
第一遍用于決定所有匯編代碼的大小, 在第二遍, 當生成所有的代碼時, 知道所有的代碼引用的符號地址. 因此, nasm不能處理的事是代碼大小決定于后面聲明的符號的值, 在代碼被提問時. 例如:
times (label-$) db 0
label: db? 'where am i'
這種情況下times的參數合法的等價于任何值; nasm將會拒絕這種情況, 因為他不能在首次見到時知道times行的大小.
times (label-$+1) db 0
label: db "now where am i"
這種情況下, 任何值都錯.
nasm拒絕這些例子, 通過一個叫做關鍵表達式的概念, 被定以為一個表達式, 其值需要在第一遍中計算出來, 因此只能依賴于前面定義的符號. times的參數是關鍵表達式.
本地變量:
對于以.開始的符號, nasm給予特殊的對待. 一個標號以一個原點開始, 被認為是局部變量, 意味著和以前的非局域變量存在聯系, 例如:
label
.loop
jne? .loop
ret
label2
.loop
jne .loop
ret
在上面的代碼片段中, 每個jne指令跳轉到前面的行, 因為兩個.loop的定義是隔離的通過前面的非局部變量的聯系的效力.
這種局部標號的處理借鑒于amiga匯編器; 然而, nasm更進了一步, 允許訪問局部變量從代碼的另一個部分. 這通過定義局部變量根據前面的非局部變量: 第一個.loop的定義實際是定以為label1.loop, 第二個是label2.loop, 因此, 你如果真的需要
label3
jmp label1.loop
有時是有用的, 在宏里, 例如, 可以定義一個標號可以從任何地方引用, 但是不會干預正常的局部標號機制. 這種標號不能是非局部的, 因為定義他的宏不知道label的全名. nasm因此引入了第三類標號, 可能值在宏中使用: 如果以..@開始的一個標號, 不會對局部標號產生作用:
label
.local:
..@foo:
label2:
.local:
jmp ..@foo
nasm有能力去定義其他特殊符號, 以..開始例如
..start, 用來指定obj文件的入口.
?
?
作者:liyonghelpme 發表于2010/6/11 18:19:00 原文鏈接 閱讀:2221 評論:0 查看評論
轉載于:https://www.cnblogs.com/liyonghelpme/archive/2010/06/11/4273548.html
總結
- 上一篇: 文件加密软件
- 下一篇: PHP常用工具方法集...