彙編-Irvine32.inc庫總結

1. 堆棧操作

1). 運行時棧

  • PUSH 操作

作用:32位PUSH操作將堆棧指針遞減4並將值複製到該位置堆棧指針指向的堆棧

PUSH操作.png

 

  • POP 操作

作用:POP操作從棧中移除一個數據, 數據移除之後, 棧指針增加指向更高的堆棧位置

POP操作.png

2). PUSH 和 POP 指令

  • PUSH 指令

PUSH指令將ESP地址減小並且源操作數到棧中

PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
  • POP 指令

POP指令複製ESP指針指向的數據到目的操作數中,並增加ESP的數值

POP reg/mem16
POP reg/mem32
  • PUSHFD 和 POPFD 指令

PUSHFD 指令將32位EFLAGS寄存器壓入棧中,POPFD將32位EFLAGS移出棧中

pushfd
popfd
  • PUSHAD, PUSHA, POPAD, and POPA 指令

PUSHAD / POPAD 將32位通用寄存器(EAX, EBX, ECX, EDX, ESP, EBP, ESI, EDI)壓入/移出棧中
PUSHA / POPA 將16位寄存器(AX, CX, DX, BX, SP, BP, SI, DI)壓入 / 移出棧中

MySub PROC
pushad ; save general-purpose registers
.
.
mov eax,...
mov edx,...
mov ecx,...
.
.
popad ; restore general-purpose registers
ret
MySub ENDP

3). 查看數組地址

方法:調試 -> 窗口 -> 內存 -> 內存1,在地址欄中輸入(&+變量名)即可查看數組

內存.png

 

4). 字符串翻轉

.486        ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式爲平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小爲4096字節
ExitProcess PROTO, dwExitCode: DWORD    


COMMENT &
    字符串翻轉
&
.data
    aName BYTE "Abraham Lincoln", 0
    nameSize = ($ - aName) - 1

.code
main PROC                   ; 定義主函數開始位置
    ; 將那麼長度存入寄存器
    mov ecx, nameSize
    mov esi, 0
L1: movzx eax, aName[esi]   ; 獲取字符
    push eax                ; 壓入棧中
    inc esi                 ; 循環變量自加
    LOOP L1

    ; 翻轉字符串
    mov ecx, nameSize
    mov esi, 0
L2: pop eax                 ; 獲取字符
    mov aName[esi], al      ; 存放字符
    inc esi                 ; 循環變量自加
    LOOP L2

    INVOKE ExitProcess, 0   ; 退出程序2
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口

2. 定義和使用程序

1). PROC 指令

  • 定義一個程序
main PROC
.
.
main ENDP

非main方法定義如下:

sample PROC
.
.
 ret
sample ENDP

其中RET強制CPU返回方法被Call的位置。

  • 程序中的標籤
jmp Destination
Destination::

2). CALL 和 RET 指令

  • CALL
    處理器直接調用程序開始執行在一個新的內存位置

  • RET
    程序指針返回被調用的位置

3). 嵌套過程調用

循環嵌套調用應該當被調用的過程在第一個之前調用另一個過程時
程序返回

循環嵌套調用.png

假設main函數調用一段名爲Sub1的程序,當Sub1正在執行的時候,它調用名爲Sub2的程序,當Sub2正在執行的時候,它調用名爲Sub3的程序。

4). 參數傳遞

注:通過寄存器傳遞參數

示例:

.486        ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式爲平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小爲4096字節
ExitProcess PROTO, dwExitCode: DWORD    

COMMENT &
    求和
&
.data
    theSum DWORD ?

.code
;------------------------------------------------------
; SumOf
; 計算並返回是三個數之和
; Receieves: EAX, EBX, ECX, 三個數. 
; Returns: EAX = sum
;------------------------------------------------------
SumOf PROC
    add eax, ebx            ; 計算EAX與EBX之和
    add eax, ecx            ; 計算EAX與ECX之和
    RET                     ; 返回程序調用的位置
SumOf ENDP

main PROC                   ; 定義主函數開始位置
    mov eax, 10000h         ; 參數1
    mov ebx, 20000h         ; 參數2
    mov ecx, 30000h         ; 參數3

    call SumOf              ; 調用SumOf方法,並傳遞參數

    mov theSum, eax         ; 將計算結果賦值給theSum變量

    INVOKE ExitProcess, 0   ; 退出程序2
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口

5). 數組求和之程序調用

.486        ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall    ; 選擇程序的內存模式爲平坦模式,stdcall調用習慣
.stack 4096             ; 設置運行的堆棧大小爲4096字節
ExitProcess PROTO, dwExitCode: DWORD    

COMMENT &
    計算數組之和
&
.data
    array DWORD 10000h, 20000h, 30000h, 40000h, 50000h
    theSum DWORD ?

.code
main PROC                   ; 定義主函數開始位置
    mov esi, OFFSET array   ; ESI 指向數組
    mov ecx, LENGTHOF array ; ECX 存放數組長度
    call ArraySum           ; 調用數組求和程序
    mov theSum, eax         ; 賦值

    INVOKE ExitProcess, 0   ; 退出程序2
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 

;------------------------------------------------------
; ArraySum
; 計算數組元素之和
; Receieves: ESI = 數組偏移地址
;            ECS = 數組長度
; Returns: EAX = 各數組元素之和
;------------------------------------------------------
ArraySum PROC
    push esi            ; 保存ESI
    push ecx            ; 保存ECX
    mov eax, 0          ; 設置數組之和爲0
L1:                     ; 循環頭
    add eax, [esi]      ; 將當前數組指針指向的數組元素值加入EAX寄存器
    add esi, TYPE DWORD ; 移動數組指針到下一個元素
    LOOP L1             ; 設置循環

    pop ecx             ; 恢復ecx值
    pop esi             ; 恢復esi值
    ret                 ; 返回程序調用位置
ArraySum ENDP

END main            ; 設置了函數的入口與出口

6). 保存和恢復寄存器

問題:每一段中都需要不PUSH和POP寄存值,這樣在書寫程序時會出現代碼冗餘的現象,並且如果忘記,則程序數據會出現異常。丟失數據。

  • USES 操作數
    伴隨着PROC指令出現,後面跟着程序要修改的所有寄存器的名字列表。
;------------------------------------------------------
; ArraySum
; 計算數組元素之和
; Receieves: ESI = 數組偏移地址
;            ECS = 數組長度
; Returns: EAX = 各數組元素之和
;------------------------------------------------------
ArraySum PROC USES esi ecx
    mov eax,0           ; 設置和爲0
L1:
    add eax,[esi]       ; 添加每一項到EAX
    add esi,TYPE DWORD  ; 移動指針
    loop L1             ; 循環加
    ret                 ; 返回到程序調用的位置
ArraySum ENDP

3. 鏈接外部庫

1). 背景資料

  • 使用
WriteString proto

call WriteString
  • 鏈接命令行參數
    link hello.obj irvine32.lib kernel32.lib

鏈接32位庫.png

4. Irvine32 庫

1). 配置Irvine32庫

2). Irvine32 庫內容

專業程序員通常更喜歡建立自己的庫,這樣做是一種很好的教育體驗。 在Windows下運行的32位模式下,輸入輸出庫必須直接調用操作系統。

Procedure Description
CloseFile Closes a disk file that was previously opened.
Clrscr Clears the console window and locates the cursor at the upper left corner.
CreateOutputFile Creates a new disk file for writing in output mode.
Crlf Writes an end-of-line sequence to the console window.
Delay Pauses the program execution for a specified n-millisecond interval.
DumpMem Writes a block of memory to the console window in hexadecimal.
DumpRegs Displays the EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, EFLAGS, and EIP registers in hexadecimal. Also displays the most common CPU status flags.
GetCommandTail Copies the program’s command-line arguments (called the command tail) into an array of bytes.
GetDateTime Gets the current date and time from the system.
GetMaxXY Gets the number of columns and rows in the console window’s buffer.
GetMseconds Returns the number of milliseconds elapsed since midnight.
GetTextColor Returns the active foreground and background text colors in the console window.
Gotoxy Locates the cursor at a specific row and column in the console window.
IsDigit Sets the Zero flag if the AL register contains the ASCII code for a decimal digit (0–9).
MsgBox Displays a popup message box.
MsgBoxAsk Display a yes/no question in a popup message box.
OpenInputFile Opens an existing disk file for input.
ParseDecimal32 Converts an unsigned decimal integer string to 32-bit binary.
ParseInteger32 Converts a signed decimal integer string to 32-bit binary.
Random32 Generates a 32-bit pseudorandom integer in the range 0 to FFFFFFFFh.
Randomize Seeds the random number generator with a unique value.
RandomRange Generates a pseudorandom integer within a specified range.
ReadChar Waits for a single character to be typed at the keyboard and returns the character.
ReadDec Reads an unsigned 32-bit decimal integer from the keyboard, terminated by the Enter key.
ReadFromFile Reads an input disk file into a buffer.
ReadHex Reads a 32-bit hexadecimal integer from the keyboard, terminated by the Enter key.
ReadInt Reads a 32-bit signed decimal integer from the keyboard, terminated by the Enter key.
ReadKey Reads a character from the keyboard’s input buffer without waiting for input.
ReadString Reads a string from the keyboard, terminated by the Enter key.
SetTextColor Sets the foreground and background colors of all subsequent text output to the console.
Str_compare Compares two strings.
Str_copy Copies a source string to a destination string.
Str_length Returns the length of a string in EAX.
Str_trim Removes unwanted characters from a string.
Str_ucase Converts a string to uppercase letters.
WaitMsg Displays a message and waits for a key to be pressed.
WriteBin Writes an unsigned 32-bit integer to the console window in ASCII binary format.
WriteBinB Writes a binary integer to the console window in byte, word, or doubleword format.
WriteChar Writes a single character to the console window.
WriteDec Writes an unsigned 32-bit integer to the console window in decimal format.
WriteHex Writes a 32-bit integer to the console window in hexadecimal format.
WriteHexB Writes a byte, word, or doubleword integer to the console window in hexadecimal format.
WriteInt Writes a signed 32-bit integer to the console window in decimal format.
WriteStackFrame Writes the current procedure’s stack frame to the console.
WriteStackFrameName Writes the current procedure’s name and stack frame to the console.
WriteString Writes a null-terminated string to the console window.
WriteToFile Writes a buffer to an output file.
WriteWindowsMsg Displays a string containing the most recent error generated by MS-Windows.

3). 概覽

  • Console Window
    控制檯窗口(或命令窗口)是在顯示命令提示符時由MS-Windows創建的純文本窗口。

4). 個別程序說明

  • CloseFile: 關閉之前創建/打開的文件呢, 通過接收一個32位整型句柄。如果文件成功關閉,則EAX將返回非0值。
mov eax,fileHandle
call CloseFile
  • Clrscr: 清除控制檯窗口,在程序的開始或結尾調用。其他時間如果要調用,需要調用WaitMsg暫停程序,然後再調用此程序。
call WaitMsg ;   "Press any key to continue..."
call Clrscr
  • CreateOutputFile: 在磁盤上創建一個新的文件,並以寫的方式打開。當我們調用這個程序的時候,爲EDX寄存器設置一個文件名。當程序返回時,如果創建成功,EAX包含一個有效的文件句柄;否則EAX等於INVALID_HANDLE_VALUE
.data
filename BYTE "newfile.txt",0
.code
mov edx,OFFSET filename
call CreateOutputFile
  • Crlf: 控制檯換行,它輸出一個包含ASCII碼'0Dh'和'0Ah'的字符串
call Crlf
  • Delay: 暫停程序。當調用的時候,設置期望值到EAX中,當爲毫秒(ms).
mov eax,1000 ; 1 second
call Delay
  • DumpMem: 以十六進制的形式將一系列內存寫入控制檯窗口。並將通過ESI賦值首地址,ECX賦值數組長度,EBX賦值數組元素所佔字節數
.data
    array DWORD 1,2,3,4,5,6,7,8,9,0Ah,0Bh
.code
main PROC
    mov esi,OFFSET array        ; 首地址
    mov ecx,LENGTHOF array      ; 數組長度
    mov ebx,TYPE array          ; 數組元素所佔字節
    call DumpMem
  • DumpRegs: 以16進制形式顯示EAX, EBX, ECX, EDX, ESI, EDI, EBP,ESP, EIP, and EFL (EFLAGS) 寄存器數值。它也可以顯示CF,SF,ZF,OF,AF,PF標誌位的數值。
call DumpRegs
  • GetCommandTail: 將程序的命令行復制到以null結尾的字符串。如果命令行是空的,則設置CF標誌位;否則,CF標誌位清空。這段程序用在命令行參數獲取上。當我們調用該程序時,EDX必須包含至少129個字節的偏移。
.data
    cmdTail BYTE 129 DUP(0)     ; empty buffer
.code
    mov edx,OFFSET cmdTail
    call GetCommandTail         ; fills the buffer

設置命名行參數方法:工程名右鍵 -> 屬性 -> 調試 -> 命名參數

命名行參數設置.png

  • GetMaxXY: 獲取控制檯緩衝字節。如果控制檯窗口緩衝字節大於可視化窗口大小,滾動條自動顯示。該程序沒有輸入參數,返回時,DX寄存器包含緩衝列長度,AX寄存器包含緩衝行長度,它們的值不會大於255。
.data
    rows BYTE ?
    cols BYTE ?
.code
    call GetMaxXY
    mov rows,al
    mov cols,dl
  • GetMseconds: 從主機電腦獲取當前的系統時間,並將時間返回給EAX寄存器。這段程序用於計算事件之間的執行時間。沒有輸入參數。
.data
    startTime DWORD ?
.code
    call GetMseconds    
    mov startTime,eax
L1:
    ; (loop body)
    loop L1
    call GetMseconds
    sub eax,startTime ; EAX = loop time, in milliseconds
  • GetTextColor: 獲取當前控制檯的前景與背景色。沒有輸入參數,返回當前背景色並賦值給AL的高4位,前景色賦值給AL的低4位。
.data
    color byte ?
.code
    call GetTextColor
    mov color,AL
  • Gotoxy: 將控制檯中的光標移動到指定位置(行與列)。默認的,控制檯的x可選值爲0—79,y可選值爲0—24.當我們調用Gotoxy時,將Y(row)的值賦給DH,X(column)的值賦給DL。
mov dh,10 ; row 10
mov dl,20 ; column 20
call Gotoxy ; locate cursor

注:用戶可能重設控制檯窗口的大小,所以應當應用調用GetMaxXY獲取rows和columns的取值。

  • IsDigit: 判斷AL中的ASCII碼是否爲一個有效的十進制數字。當調用這段程序時,將ASCII碼賦值給AL,如果AL中的內容是一個有效的十進制數據,那麼設置零標記位;否則,清空零標記位。
mov AL,somechar
call IsDigit
  • MsgBox: 顯示一個帶着文本的圖形彈出消息窗口(控制檯空口模式下)。爲EDX設置字符串,用於顯示在窗體內部。可選的,在EBX中設置窗體的標題。如果沒有標題,則設置EBX爲0
.data
    caption BYTE "Dialog Title", 0
    HelloMsg BYTE "This is a pop-up message box.", 0dh,0ah BYTE "Click OK to continue...", 0
.code
    mov ebx,OFFSET caption
    mov edx,OFFSET HelloMsg
    call MsgBox
  • MsgBoxAsk: 顯示一個帶着Yes/No的圖形彈出消息框(控制檯模式下)。消息框內容,爲EDX設置字符串。可選,EBX設置消息框標題,如果沒有標題則設置EBX爲0.該程序在EAX中返回一個整型,以告訴你用戶的選擇。IDYES爲6,IDNO爲7.
.data
    caption BYTE "Survey Completed",0
    question BYTE "Thank you for completing the survey." 
             BYTE 0dh,0ah
             BYTE "Would you like to receive the results?",0
.code
    mov ebx,OFFSET caption
    mov edx,OFFSET question
    call MsgBoxAsk
    ;(check return value in EAX)
  • OpenInputFile: 爲輸入打開一個已經存在的文件。其中EDX設置文件名,返回時,如果文件打開成功,EAX包含一個有效的文件句柄;否則,EAX等於INVALID_HANDLE_VALUE
.data
    filename BYTE "myfile.txt",0
.code
    mov edx,OFFSET filename
    call OpenInputFile
  • ParseDecimal32: 轉換無符號十進制整數字符串到32位二進制。其中EDX設置字符串的首地址,ECX設置字符串的長度,返回時將二進制的值設置給EAX。
.data
    buffer BYTE "8193"
    bufSize = ($ - buffer)
.code
    mov edx,OFFSET buffer
    mov ecx,bufSize
    call ParseDecimal32 ; returns EAX

-- 如果這個整型是空白的, 則EAX = 0 and CF = 1
-- 如果這個整型僅僅包含空格, 則EAX = 0 and CF = 1
-- 如果這個整型是大於2^32�1, 則EAX = 0 and CF = 1
-- 否則, EAX包含轉換後的整型並且CF = 0

  • ParseInteger32: 轉換一個有符號的十進制整型字符串爲32位二進制數據。所有有效的數字從字符串第一個非數字字符開始轉換。字符串之前的空格忽略。EDX設置字符串的首地址,ECX設置字符串的長度,返回的數值存放在EAX中。
.data
    buffer byte "-8193"
    bufSize = ($ - buffer)
.code
    mov edx,OFFSET buffer
    mov ecx,bufSize
    call ParseInteger32 ; returns EAX
  • Random32: 在EAX寄存器中生成一個32位隨機整型。重複調用時,Random32生成模擬隨機序列。使用seed方法創建一個數字,這段程序使用種子生成一個隨機數。
.data
    randVal DWORD ? 
.code
    call Random32
    mov randVal,eax 
  • Randomize: 初始化Random32的起始種子值和RandomRange程序。種子等於一天中的時間,精確到1/100秒。 每次運行一個調用Random32和RandomRange的程序的時間,生成的序列隨機數將是唯一的。
    call Randomize
    mov ecx,10
L1: call Random32
    ; use or display random value in EAX here...
    loop L1
  • RandomRange: 從0—(n-1)生成一個隨機數,其中n賦值給EAX寄存器。隨機數返回給EAX寄存器。
.data
    randVal DWORD ?
.code
    mov eax,5000
    call RandomRange
    mov randVal,eax
  • ReadChar: 從鍵盤讀取一個字符,並返回這個字符到AL寄存器中。
.data
    char BYTE ?
.code
    ReadChar
    mov char, al

如果用戶按下一個擴展鍵,例如功能鍵Ins,Del,程序將設置AL爲0,AH設置對應的鍵值。

  • ReadDec: 從鍵盤讀取一個32位無符號整型,並將值設置到EAX中,忽略開頭的空格。返回值是從第一個有效的數字開始直到一個非數字。
.data
    intVal DWORD ?
.code
    call ReadDec
    mov intVal, eax

-- 如果這個整型是空白的, 則EAX = 0 and CF = 1
-- 如果這個整型僅僅包含空格, 則EAX = 0 and CF = 1
-- 如果這個整型是大於2^32�1, 則EAX = 0 and CF = 1
-- 否則, EAX包含轉換後的整型並且CF = 0

  • ReadFromFile: 讀取文件中的內容到內存中。當你調用ReadFromFile時,EAX中存儲已打開文件句柄,EDX中存儲文件起始地址,ECX中存儲文件內容最大字節數。ReadFromFile返回值,檢查CF進位標誌,如果CF是空的,EAX包含從文件中讀取到的字節數,但如果CF被設置,EAX中包含一個系統的錯誤碼。你可以調用WriteWindowsMsg程序獲取異常文本。
.data
    BUFFER_SIZE = 5000
    buffer BYTE BUFFER_SIZE DUP(?)
    bytesRead DWORD ?
.code
    mov edx,OFFSET buffer       ; points to buffer
    mov ecx,BUFFER_SIZE         ; max bytes to read
    call ReadFromFile           ; read the file
    ; 如果CF標誌位是空的,則可以執行這行代碼
    ; mov bytesRead, eax        ; count of bytes actually read
    ; 如果CF標誌位被設置,則調用WriteWindowsMsg
    ; call WriteWindowsMsg
  • ReadHex: 從鍵盤讀取一個32位的十六進制數據,並將獲取到的數據設置到EAX中。
.data
    hexVal DWORD ?
.code
    call ReadHex
    mov hexVal,eax
  • ReadInt: 從鍵盤讀取一個32位的有符號整型,並將值設置到EAX中。開頭位置用戶可以使用+/-, 其餘的數字僅包含數字。如果用戶輸入的值不是一個正確的32位有符號整數,那麼該程序設置OF標誌位顯示一個異常信息。該程序返回所有有效的數字直到非數字字符爲止。
.data
    intVal SDWORD ? 
.code
    call ReadInt
    mov intVal,eax
  • ReadKey: 執行無等待鍵盤檢查。換句話說,檢測用戶是否按下了某個鍵。如果沒有鍵盤數據,ZF標誌位被設置;如果有鍵被按下,則ZF標誌位被清空並設置AL寄存器爲ASCII碼值。如果AL等於0,則用戶可能按下了一下特殊鍵,AH寄存器將包含虛擬的掃描碼,DX包含一個虛擬鍵值,EBX包含鍵盤標識位。
if no_keyboard_data then
    ZF = 1
else
    ZF = 0
    if AL = 0 then
        extended key was pressed, and AH = scan code, DX = virtual key code, and EBX = keyboard flag bits
    else
        AL = the key's ASCII code
    endif
endif
  • ReadString: 從鍵盤讀取一個字符串,知道用戶輸入回車鍵爲止。EDX設置字符串首地址,ECX設置用戶最大輸入字符數。返回時EAX中存放字符個數。
.data
    buffer BYTE 21 DUP(0)   ; input buffer
    byteCount DWORD ?       ; holds counter
.code
    mov edx,OFFSET buffer   ; point to the buffer
    mov ecx,SIZEOF buffer   ; specify max characters
    call ReadString         ; input the string
    mov byteCount,eax       ; number of characters
  • SetTextColor: 設置文本輸出區域前景色和背景色。當調用SetTextColor時,分配一個顏色給EAX寄存器。下面是與定義的顏色常量,可以使用在前景色與背景色的設置。
Color Color Color Color
black = 0 red = 4 gray = 8 lightRed = 12
blue = 1 magenta = 5 lightBlue = 9 lightMagenta = 13
green = 2 brown = 6 lightGreen = 10 yellow = 14
cyan = 3 lightGray = 7 lightCyan = 11 white = 15

設置顏色時,EAX的高16位爲背景色,低16位爲前景色

mov eax,white  (blue * 16)   ; white on blue
call SetTextColor
  • Str_length: 返回一個控制終止的字符串長度。其中EDX設置字符串偏移量。返回時,EAX設置爲字符串長度。
.data
    buffer BYTE "abcde",0
    bufLength DWORD ?
.code
    mov edx,OFFSET buffer   ; point to string
    call Str_length         ; EAX = 5
    mov bufLength,eax       ; save length
  • WaitMsg: 顯示一個字符串"Press any key to continue..."並等待用戶按下一個鍵。
call WaitMsg
  • WriteBin: 以ASCII二進制格式將整數寫入控制檯窗口。其中EAX存放待輸出的字符串。
    mov eax,12346AF9h
    call WriteBin
  • WriteBinB: 以ASCII二進制格式將32位整數寫入控制檯窗口,EAX寄存器中存放待輸出的數值,EBX寄存器中存放要顯示類型的字節大小。
    mov eax,00001234h
    mov ebx,TYPE WORD   ; 2 bytes
    call WriteBinB      ; displays 0001 0010 0011 0100
  • WriteChar: 在控制檯窗口中輸出一個字符,AL寄存器中存放該字符或ASCII碼。
    mov al,'A'
    call WriteChar  ; displays: "A"
  • WriteDec: 在控制檯窗口中輸出一個開頭沒有0的32位無符號整數,其中EAX寄存器存放該數字。
    mov eax,295
    call WriteDec   ; displays: "295"
  • WriteHex: 在控制檯窗口中輸出一個8位十六進制的32位無符號整數,如果需要開始位置補0,EAX寄存器存放待輸出的整數。
    mov eax,7FFFh
    call WriteHex   ; displays: "00007FFF"
  • WriteHexB: 在控制檯窗口中輸出一個指定十六進制格式的32位無符號整數,如果必須,開始位置補0。EAX寄存器存儲待輸出整數,EBX寄存器中存放待顯示的位數。
    mov eax,7FFFh
    mov ebx,TYPE WORD   ; 2 bytes
    call WriteHexB      ; displays: "7FFF"
  • WriteInt: 在控制檯窗口中輸出一個帶符號且不帶0的32位十進制整數,EAX寄存器中存放待輸出的整數。
    mov eax,216543
    call WriteInt   ; displays: "+216543"
  • WriteString: 在控制檯窗口輸出一個以空值終止的字符串,EDX寄存器中存放字符串首地址。
.data
    prompt BYTE "Enter your name: ",0
.code
    mov edx,OFFSET prompt
    call WriteString
  • WriteToFile: 將緩衝的內容輸出到文件中,其中EAX寄存器中存放一個有效的文件句柄,EDX寄存器中存放緩衝內容的偏移地址,ECX寄存器中存放待寫入的字節長度。當程序返回時,如果EAX寄存器大於0,則它的值爲已經寫入的字節長度;否則,爲異常信息。
BUFFER_SIZE = 5000
.data
    fileHandle DWORD ?
    buffer BYTE BUFFER_SIZE DUP(?)
.code
    mov eax,fileHandle
    mov edx,OFFSET buffer
    mov ecx,BUFFER_SIZE
    call WriteToFile
  • WriteWindowsMsg: 當執行系統函數時,你的應用在控制檯窗口中輸出一個最近生成的異常信息。
    call WriteWindowsMsg

5. Irvine32 庫測試程序

1). 教程:Library Test #1

  • Step 1: 在程序開始位置添加標準頭
; Library Test #1: Integer I/O
; 測試 Clrsrc, Crlf, DumpMem, ReadInt, SetTextColor
; WaitMsg, WriteBin, WriteHex, WriteString
Include Irvine32.inc
  • Step 2: 定義常量COUNT用於決定程序循環次數,常量BlueTextOnGrayDefaultColor用於改變控制檯背景與前景顏色。
.data
    COUNT = 4               ; 設置循環次數
    BlueTextOnGray = blue + (lightGray * 16)            ; 控制檯的前景色和背景色
    DefaultColor = lightGray + (black * 16)             ; 默認的控制檯前景色和背景色
  • Step 3: 定義一個有符號的32位整型,使用十進制表示常量。定義一個字符串用於提示用於輸入一個整數
.data
    arrayD SDWORD 12345678h, 1A4B2000h, 3434h, 7AB9h    ; 數組
    prompt BYTE "Enter a 32-bit signed integer: ", 0    ; 提示信息
  • Step 4: 代碼區域定義主程序,設置EAX值爲BlueTextOnGray, 調用SetTextColor改變背景和前景色。爲了使設置的顏色生效,必須調用清屏程序清屏。
.code
main PROC                   ; 定義主函數開始位置
    mov eax, BlueTextOnGray ; 設置控制檯窗口顏色
    call SetTextColor       ; 設置顏色
    call Clrscr             ; 爲了使設置的顏色生效,調用清屏方法

    INVOKE ExitProcess, 0   ; 退出程序
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口
  • Step 5: 將ESI寄存器設置爲arrayD數組的首地址
    mov esi, OFFSET arrayD  ; 設置數組首地址
  • Step 6: 將EBX設置爲數組每個元素所佔用的字節數。
    mov ebx, TYPE arrayD    ; 設置數組元素所佔字節數
  • Step 7: 將ECX設置爲數組長度,然後調用DumpMem顯示。
    mov esi, OFFSET arrayD  ; 設置數組首地址
    mov ebx, TYPE arrayD    ; 設置數組元素所佔字節數
    mov ecx, LENGTHOF arrayD; 數組元素個數
    call DumpMem            ; 顯示信息

效果如下:

 

DumpMem效果.png

  • Step 8: 調用Crlf輸出一個空行,然後初始化ECX的值爲COUNT用於循環。
    call Crlf               ; 輸出空行
    mov ecx, COUNT          ; 設置循環次數
  • Step 9: 顯示一個字符串信息提示用戶輸入數字,字符串的首地址賦值給EDX,調用WriteString程序輸出,然後調用ReadInt程序接受用戶的輸入,將這個值賦值給EAX。
L1: 
    mov edx, OFFSET prompt  ; 設置字符串首地址
    call WriteString        ; 輸出提示信息
    call ReadInt            ; 將輸入的數字讀入EAX
    call Crlf               ; 輸出空行
  • Step 10: 調用WriteInt顯示一個格式化的十進制有符號數字, 然後調用Crlf輸出空行
    call WriteInt           ; 顯示一個有符號的十進制數
    call Crlf               ; 輸出空行
  • Step 11: 調用WriteHexWriteBin顯示十六進制數和二進制數。
    call WriteHex           ; 顯示十六進制數
    call Crlf               ; 輸出空行
    call WriteBin           ; 顯示二進制數
    call Crlf               ; 輸出空行
    call Crlf               ; 輸出空行
  • Step 12: 設置循環
    LOOP L1                 ; 設置循環,此時ECX遞減
  • Step 13: 循環結束後,顯示一個結束信息並暫停程序。
    call WaitMsg            ; 顯示請按任意鍵繼續信息
  • Step 14: 程序的結尾,將顏色設置回默認的
    mov eax, DefaultColor   ; 控制器默認的前景色與背景色
    call SetTextColor       ; 設置顏色
    call Clrscr             ; 清屏

效果:

InputLoop程序.png

  • Step 15: 完整程序
; Library Test #1: Integer I/O
; 測試 Clrsrc, Crlf, DumpMem, ReadInt, SetTextColor
; WaitMsg, WriteBin, WriteHex, WriteString
Include Irvine32.inc

.data
    COUNT = 4               ; 設置循環次數
    BlueTextOnGray = blue + (lightGray * 16)            ; 控制檯的前景色和背景色
    DefaultColor = lightGray + (black * 16)             ; 默認的控制檯前景色和背景色
    arrayD SDWORD 12345678h, 1A4B2000h, 3434h, 7AB9h    ; 數組
    prompt BYTE "Enter a 32-bit signed integer: ", 0    ; 提示信息

.code
main PROC                   ; 定義主函數開始位置
    ; 設置藍色文本和亮灰色背景
    mov eax, BlueTextOnGray ; 設置控制檯窗口顏色
    call SetTextColor       ; 設置顏色
    call Clrscr             ; 爲了使設置的顏色生效,調用清屏方法

    ; 使用DumpMem顯示數組
    mov esi, OFFSET arrayD  ; 設置數組首地址
    mov ebx, TYPE arrayD    ; 設置數組元素所佔字節數
    mov ecx, LENGTHOF arrayD; 數組元素個數
    call DumpMem            ; 顯示信息
    ; 讓用戶輸入有符號整型
    call Crlf               ; 輸出空行
    mov ecx, COUNT          ; 設置循環次數

L1: 
    mov edx, OFFSET prompt  ; 設置字符串首地址
    call WriteString        ; 輸出提示信息
    call ReadInt            ; 將輸入的數字讀入EAX
    call Crlf               ; 輸出空行

    ; 以十進制,十六進制,二進制形式輸出一個整數
    call WriteInt           ; 顯示一個有符號的十進制數
    call Crlf               ; 輸出空行

    call WriteHex           ; 顯示十六進制數
    call Crlf               ; 輸出空行
    call WriteBin           ; 顯示二進制數
    call Crlf               ; 輸出空行
    call Crlf               ; 輸出空行

    LOOP L1                 ; 設置循環,此時ECX遞減

    call WaitMsg            ; 顯示請按任意鍵繼續信息

    ; 設置控制檯顏色爲默認的
    mov eax, DefaultColor   ; 控制器默認的前景色與背景色
    call SetTextColor       ; 設置顏色
    call Clrscr             ; 清屏

    exit
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 
END main            ; 設置了函數的入口與出口

2). Library Test #2: 隨機數

; Library Test #2
; Rendom Integers
Include Irvine32.inc

TAB = 9             ; Tab的ASCII碼
    
.code
main PROC                   ; 定義主函數開始位置
    call Randomize          ; 初始化隨機數生成器
    call Rand1              ; 調用Rand1程序
    call Rand2              ; 調用Rand2程序

    call WaitMsg            ; 輸出等待按鍵信息
    exit
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 

Rand1 PROC
    ; 生成10個僞隨機數
    mov ecx, 10             ; 循環10次
L1: 
    call Random32           ; 隨機數生成初始化
    call WriteDec           ; 輸出一個無符號十進制數
    mov al, TAB             ; 設置TAB鍵的ASCII碼
    call WriteChar          ; 輸出一個字符
    LOOP L1                 ; 設置循環

    call Crlf               ; 輸處空行
    RET                     ; 回到調用該程序的位置
Rand1 ENDP

Rand2 PROC
    ; 從-50到49生成是個僞隨機數
    mov ecx, 10             ; 設置循環次數
L1:
    mov eax, 100            ; 設置值的範圍爲0-99
    call RandomRange        ; 生成隨機數
    sub eax, 50             ; 減去50,使生成的值的範圍爲-50——49
    call WriteInt           ; 輸出有符號的十進制
    mov al, TAB             ; 設置TAB的ASCII碼
    call WriteChar          ; 輸出TAB
    LOOP L1                 ; 設置循環

    call Crlf               ; 輸出空行
    RET
Rand2 ENDP
END main            ; 設置了函數的入口與出口

Random 效果.png

3). Library Test #3 : 性能時間

; Library Test #3: Performance Timing
; 計算嵌套循環的執行時間
Include Irvine32.inc
    
.data
    OUTER_LOOP_COUNT = 3    ; 循環次數
    startTIme DWORD ?       ; 循環開始時間
    msg1 BYTE "Please wait...", 0Dh, 0Ah, 0 ;等待信息
    msg2 BYTE "Elapsed milliseconds: ", 0   ; 經過時間

.code
main PROC                   ; 定義主函數開始位置
    mov edx, OFFSET msg1    ; 設置msg1的偏移地址
    call WriteString        ; 輸出msg1
    
    ; 保存開始時間
    call GetMSeconds        ; 獲取當前時間
    mov startTime, eax      ; 保存開始時間

    ; 設置外層循環次數
    mov ecx, OUTER_LOOP_COUNT

L1: 
    call innerLoop          ; 調用內層循環
    LOOP L1

    ; 計算執行時間
    call GetMSeconds        ; 獲取當前時間
    sub eax, startTime      ; 計算出執行時間

    ; 顯示執行時間
    mov edx, OFFSET msg2    ; 設置msg2的偏移地址
    call WriteString        ; 輸出msg2
    call WriteDec           ; 輸出循環執行時間
    call Crlf               ; 輸出空行

    call WaitMsg            ; 輸出等待按鍵信息
    exit
main ENDP           ; 函數結束位置, ENDP 之前的內容,要與PROC 

innerLoop PROC USES ecx
    mov ecx, 0FFFFFFFh      ; 設置循環次數
L1: 
    mul eax                 ; 乘法
    mul eax             
    mul eax
    LOOP L1                 ; 重複內層循環

    RET
innerLoop ENDP

END main            ; 設置了函數的入口與出口

Performance Timing.png

6. 64位彙編程序

1). Irvine64 庫

Procedure Description
Crlf Writes an end-of-line sequence to the console.
Random64 Generates a 64-bit pseudorandom integer in the range 0 to 2^64�1. The random value is returned in the RAX register.
Randomize Seeds the random number generator with a unique value.
ReadInt64 Reads a 64-bit signed integer from the keyboard, terminated by the Enter key. It returns the integer value in the RAX register.
ReadString Reads a string from the keyboard, terminated by the Enter key. Pass it the offset of the input buffer in RDX, and set RCX to the maximum number of characters the user can enter, plus 1 (for the null terminator byte). It returns a count (in RAX) of the number of characters typed by the user.
Str_compare Compares two strings. Pass it a pointer to the source string in RSI, and a pointer to the target string in RDI. Sets the Zero and Carry flags in the same way as the CMP (Compare) instruction.
Str_copy Copies a source string to the location indicated by a target pointer. Pass the source offset in RSI, and the target offset in RDI.
Str_length Returns the length of a null-terminated string in the RAX register. Pass it the string’s offset in RCX.
WriteInt64 Displays the contents of the RAX register as a 64-bit signed decimal integer, with a leading plus or minus sign. It has no return value.
WriteHex64 Displays the contents of the RAX register as a 64-bit hexadecimal integer. It has no return value.
WriteHexB Displays the contents of the RAX register as a hexadecimal integer in either a 1-byte, 2-byte, 4-byte, or 8-byte format. Pass it the display size (1, 2, 4, or 8) in the RBX register. It has no return value.
WriteString Displays a null-terminated ASCII string. Pass it the string’s 64-bit offset in RDX. It has no return value.

2). 調用64位子程序

ExitProcess PROTO   ; Windows API 中
WriteInt64 PROTO    ; Irvine64 庫中

    call ExitProcess    ; 調用

3). 調用過程示例

; Calling a subroutine in 64-bit mode           (CallProc_64.asm)
; 添加現有項Irvine64.obj

ExitProcess PROTO   ; Windows API 中
WriteInt64 PROTO    ; Irvine64 庫
Crlf PROTO          ; Irvine64 庫

.code
main PROC
    sub rsp, 8          ; 對齊棧指針
    sub rsp, 20h        ; 保留32個字節

    mov rcx, 1          ; 設置參數
    mov rdx, 2
    mov r8, 3
    mov r9, 4

    call AddFour        ; 返回值賦給RAX
    call WriteInt64     ; 顯示數字
    call Crlf           ; 輸出空行

    mov ecx, 0  
    call ExitProcess
main ENDP

AddFour PROC
    mov rax, rcx
    add rax, rdx
    add rax, r8
    add rax, r9         ; 四個數之和放在RAX中
    RET
AddFour ENDP

END

提示:該程序需要鏈接Irvine64.obj文件,在解決方案資源管理器窗口右鍵工程項目名 -> 添加 -> 現有項... -> 選擇Irvine64.obj文件,如果出現Irvine64.obj : error LNK2017: 沒有 /LARGEADDRESSAWARE:NO,“ADDR32”到“bufferLHB”的重定位無效問題,項目名右鍵 -> 屬性 -> 配置屬性 -> 鏈接器 -> 系統 -> 啓用大地址 -> 選擇否(/LARGEADDRESSAWARE:NO), 原文地址



作者:_凌浩雨
鏈接:https://www.jianshu.com/p/73582e20b1b5
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章