start:
程式碼區段開始,這裏有一個標記,start:,和在 DOS 時候一樣
end:
在程式的最後一行有一個end假指令,表示整個原始擋到此結束,end後面所接的標記表示這個程式的進入點
2010年7月4日 星期日
[組語] 指標的使用方式 Ptr
指標的觀念我還蠻熟的~
在C語言中,對於使用指標相關的方式,有一定的了解~
但是,在組語中,對於指標的使用方式就還不是很了解~
剛好這個時候可以整理一下這一方面的資料~
在組語中,使用Ptr有一定的格式資料長度 PTR [記憶體位址]
資料長度可以是BYTE, WORD, DWORD
例子:MOV AL, BYTE PTR [0A02B000190008400h]
include Irvine32.inc
.data ; 以下開始為資料區段
x1 QWORD 0A02B000190008400h ; 在目前這一個位置存放一個QWORD的資料,內容為0A02B000190008400h
x2 QWORD 800187008000A904h ; 在目前這一個位置存放一個QWORD的資料,內容為800187008000A904h
sum BYTE 9 DUP(0) ; 所以申請9個Byte的記憶體空間
; sum是一個存放記憶體位址的變數
.code ; 程式碼區段
main PROC ; 宣告一個名為main的function
xor eAX,eAX ; 清除AX=0
mov eDI,0 ; 目的索引暫存器(EDX)亦清除
mov eCX,9 ; 累加暫存器(ECX)亦清除
CLC ; 清除進位旗標(CLear Carry flag)
L1:
jnc L2 ; 若CF=0則跳到 L2:
adc BYTE PTR [sum+eDI],0 ; 否則 sum[下一個Byte]=sum[下一個Byte]+1
CLC ; 清除進位旗標 CF=0
L2:
mov AL,BYTE PTR [x1+eDI] ; 把x1+eDI記憶體的位址開始,長度為BYTE的資料存放到AL的暫存器中
add AL,BYTE PTR [x2+eDI] ; 把x2+eDI記憶體的位址開始,長度為BYTE的資料存與AL做相加的動作
; 並且把結果放到AL中
add BYTE PTR [sum+eDI],AL ; 結果放到 sum
inc eDI ; 做下一個Byte
loop L1
; 傾印記憶體內容
mov eSI,offset sum ; 把sum位址傳給ESI
mov CX,9
call DumpMem ; 呼叫DumpMem函式
call DumpRegs ; 呼叫DumpRegs函式
exit
main ENDP ; 宣告的main函式的結束
END main參考資料:
指令分類與指令集
組合語言的問題?
addr 與 offset
[組語] LEA和MOV
就我的理解,MOV是把變數的值復製給另一個變數。
在C語言的表示方式如下:int x=1;
int *ptr;
int y;
y = x;
在asm中,把x的值直接傳給y,則是直接以下面的方式表示MOV y, x
而LEA則是把變數的位址復製給另一個變數
在C語言的表示方式如下:int x=1;
int *ptr;
int y;
ptr = &x;
在asm中,把x的位址傳給y,則是直接以下面的方式表示LEA y, x
參考資料:
組語基礎篇-Lea與Mov
組合語言
2010年5月3日 星期一
[組語] PROC & ENDP
; Caspar-comment - PROC用來定義程序,以ENDP表示結束
; Caspar-comment - 若sub function與main function在同一段Code則使用NEAR, 主程式的Stack只會存入ip
; Caspar-comment - 若sub function與main function不在同一段Code則使用FAR, 主程式的Stack會存入cs, ip的值
FooStart PROC NEAR C PUBLICCALL 指令
用來呼叫副程式的指令,語法是
CALL 副程式名
RET 指令
RET 指令是在副程式中返回主程式的指令,其語法是:
RET n
RETN n
RETF n
n 是位元組數,此位元組數表示自副程式返回時還要再使 SP 加上幾個位元組。常用於高階語言呼叫副程式,見第 31 章。RETN、RETF 見 PROC/ENDP 假指令的說明。
PROC/ENDP 假指令
PROC 並非 80x86 指令而是假指令,它是用來定義副程式,它指出副程式由此開始,必須和 EDNP 搭配使用,否則組譯器會出錯。語法是:
標號名 proc [near/far]
;副程式碼
ret
標號名 endp
標號名就是這個副程式的名稱,例如當 CPU 執行到
CALL my_subroutine
指令時,就會跳到名為 my_subroutne 的副程式執行。
若 PROC 後接 near 表示副程式與主程式在同一區段內,稱為近程呼叫;若接 far,表示副程式與主程式在不同區段內,稱為遠程呼叫。若省略 near 和 far,組譯器能自動判斷副程式與主程式是否在同一區段內。近程呼叫或遠程呼叫會影響返回位址的大小。很明顯的,近程呼叫,只要把下一指令的偏移位址推入堆疊即可而偏移位址只有一個字組的大小;如果是遠程呼叫,就要把區段位址及偏移位址,共兩個字組推入堆疊。
這也影響到返回時要自堆疊取出一個或兩個字組,因此分別用 RETN、RETF 來表示。但是如果用 RET,也沒關係,組譯器也能自動判斷。
可多參考INTEL和AMD在CPU指令手册
下面有一個例子
;------------------------------------------------------------------------------
; VOID
; IoOutput32 (
; IN UINT16 Port,
; IN UINT32 Data
; )
;------------------------------------------------------------------------------
IoOutput32 PROC PUBLIC Port:UINT16, Data:UINT32
pushad
mov eax, Data
mov dx, Port
out dx, eax
popad
ret
IoOutput32 ENDP參考資料:
asm - 副程式
[組語] SEGMENT
之前已經提過 SEGMENT 假指令了,事實上 SEGMENT 後面有許多選項可供選擇,當您寫副程式製作成程式庫,或是寫很大的程式把它切割成數個小程式再合併時,要注意這些選項。其語法是:
區段名 segment 排列型式 合併型式 類別名
排列型式 (align type) 是告訴連結程式該區段由那一種位址開始,或者說此區段排在前一區段後的那一種位址開始。可以選擇的位址種類有下面幾種:
1. byte:由某一位元組開始,也就是任意位址開始,視載入 DOS 驅動程式多寡以及前面區段大小決定。
2. word:由某一字組開始,也就是從偶數位址開始。
3. dword:由某個雙字組開始,一個雙字組是 4 個位元組。
4. para:由某一節開始,節的英文是 paragraph,一節的大小是 10H 個位元組,也就是十進位的 16 個位元組。
5. page:由某一頁 (page) 開始,一頁是 100H 個位元組。
前面幾章的例子中,都省略排列形式,則連結器自動用 para 選項,也就是說沒有排列形式時,MASM 內定選項是 para。
合併型式 (combine type) 是告訴連結器該區段和程式庫內或其他目的檔內的那一個區段連結在一起成為一個區段。可以用的選項有:
1. none:不與其他區段合併。
2. public:具有相同名稱且相同類別名的區段合併成一個區段。
3. common:具有相同名稱的區段合併成一個區段。
4. at 位址:區段被置於特定位址。
5. stack:表示此區段為堆疊區段。
6. memory:使區段置於最高位址。
雖然 segment 的用法很複雜,但是最常用的還是『stack』、『public』。因為在主程式中要使用程式庫,或者要把某個副程式加入程式庫都必須宣告『public』及類別名,使連結程式 (LINK.EXE) 能順利把各區段正確連結。
參考資料:
SEGMENT 假指令
[組語] .module
tiny 用於成立 .com 檔,程式段、資料段、額外段及堆疊段等四個區共用在同一個區段(64Kb)中,檔案最大僅能64Kb。
small 程式段及資料段,各有64Kb的空間。為一般最常用的 .exe 檔的模式,建議使用。
medium 程式段可超過64Kb,而資料段只有64Kb的空間。
compact 資料段可超過64Kb,而程式段只有64Kb的空間。
large 程式段與資料段,皆可大於 64 Kb。
huge 同上,但更強的是,連同資料段中的任意某陣列,也可大於 64Kb 的範圍。
flat ???? 用於 OS/2 系統。用途不詳......MODEL SMALL, C 就指定要和C 語言聯結
參考資料:
組合語言假指令
[組語] INCLUDE
跟C語言中的#include是一樣的意思~
就是把後面的這一個檔案,整個把它貼到目前的這一個位置
INCLUDE function.inc以上的程式就是把function.inc整個貼到目前的這一個位置
2010年4月28日 星期三
組合語言語法
MARCO
就是把MACRO與ENDM這兩個夾起來的部分用另一個名稱來取代
Ex:
FOO MACRO
MOV AL, 0x32
ADD AL, 0x01
ENDM之後的程式碼就可以使用以下的方式
FOO
ADD AL, AL最後AL的結果就會0x66
===================PUBLIC=====EXTRN=============================
PUBLIC 假指令是宣告副程式、標記或變數為『公用』的,編譯器看到這個假指令,便會把相關資料寫進目的檔,讓 Linker 能夠連結,使得其他程式能夠使用被宣告為公用的副程式或變數。所以 PUBLIC 應該用在被呼叫的程式中。
PUBLIC 常常和EXTRN配合使用。EXTRN 的意思是『外部』的,當 cl.exe 看到被宣告外部的變數、副程式或標記時,雖然在程式中找不到,也不會出現錯誤,而會把相關資訊寫進目的檔,等到連結時會尋找被連結的程式庫或目的檔,如果找到就不會產生錯誤。因為使用外部的『東東』是變數、標記還是副程式的處理方式不同,所以必須在 EXTRN 後面告訴 cl.exe 是那一種。
EXTRN 的語法是:
EXTRN 副程式名:呼叫方式
呼叫方式可以用 near 或 far。
========================EQU=============================
把某一個變數設定為常數!
以下這一個例子是把PEI設定為3這一個常數
PEI EQU 3參考資料:
小木偶的網頁 - Ch10 程式庫