汇编(MOV,SUB,PUSH,POP,...)

汇编开发(三):程序

2019-02-16  本文已影响1人  _凌浩雨

1. 堆栈操作

1). 运行时栈

作用:32位PUSH操作将堆栈指针递减4并将值复制到该位置堆栈指针指向的堆栈

PUSH操作.png

作用:POP操作从栈中移除一个数据, 数据移除之后, 栈指针增加指向更高的堆栈位置

POP操作.png
2). PUSH 和 POP 指令

PUSH指令将ESP地址减小并且源操作数到栈中

PUSH reg/mem16
PUSH reg/mem32
PUSH imm32

POP指令复制ESP指针指向的数据到目的操作数中,并增加ESP的数值

POP reg/mem16
POP reg/mem32

PUSHFD 指令将32位EFLAGS寄存器压入栈中,POPFD将32位EFLAGS移出栈中

pushfd
popfd

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 指令
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寄存值,这样在书写程序时会出现代码冗余的现象,并且如果忘记,则程序数据会出现异常。丢失数据。

;------------------------------------------------------
; 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
链接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). 概览
4). 个别程序说明
mov eax,fileHandle
call CloseFile
call WaitMsg ;   "Press any key to continue..."
call Clrscr
.data
filename BYTE "newfile.txt",0
.code
mov edx,OFFSET filename
call CreateOutputFile
call Crlf
mov eax,1000 ; 1 second
call Delay
.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
call DumpRegs
.data
    cmdTail BYTE 129 DUP(0)     ; empty buffer
.code
    mov edx,OFFSET cmdTail
    call GetCommandTail         ; fills the buffer

设置命名行参数方法:工程名右键 -> 属性 -> 调试 -> 命名参数

命名行参数设置.png
.data
    rows BYTE ?
    cols BYTE ?
.code
    call GetMaxXY
    mov rows,al
    mov cols,dl
.data
    startTime DWORD ?
.code
    call GetMseconds    
    mov startTime,eax
L1:
    ; (loop body)
    loop L1
    call GetMseconds
    sub eax,startTime ; EAX = loop time, in milliseconds
.data
    color byte ?
.code
    call GetTextColor
    mov color,AL
mov dh,10 ; row 10
mov dl,20 ; column 20
call Gotoxy ; locate cursor

注:用户可能重设控制台窗口的大小,所以应当应用调用GetMaxXY获取rows和columns的取值。

mov AL,somechar
call IsDigit
.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
.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)
.data
    filename BYTE "myfile.txt",0
.code
    mov edx,OFFSET filename
    call OpenInputFile
.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

.data
    buffer byte "-8193"
    bufSize = ($ - buffer)
.code
    mov edx,OFFSET buffer
    mov ecx,bufSize
    call ParseInteger32 ; returns EAX
.data
    randVal DWORD ? 
.code
    call Random32
    mov randVal,eax 
    call Randomize
    mov ecx,10
L1: call Random32
    ; use or display random value in EAX here...
    loop L1
.data
    randVal DWORD ?
.code
    mov eax,5000
    call RandomRange
    mov randVal,eax
.data
    char BYTE ?
.code
    ReadChar
    mov char, al

如果用户按下一个扩展键,例如功能键Ins,Del,程序将设置AL为0,AH设置对应的键值。

.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

.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
.data
    hexVal DWORD ?
.code
    call ReadHex
    mov hexVal,eax
.data
    intVal SDWORD ? 
.code
    call ReadInt
    mov intVal,eax
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
.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
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
.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
call WaitMsg
    mov eax,12346AF9h
    call WriteBin
    mov eax,00001234h
    mov ebx,TYPE WORD   ; 2 bytes
    call WriteBinB      ; displays 0001 0010 0011 0100
    mov al,'A'
    call WriteChar  ; displays: "A"
    mov eax,295
    call WriteDec   ; displays: "295"
    mov eax,7FFFh
    call WriteHex   ; displays: "00007FFF"
    mov eax,7FFFh
    mov ebx,TYPE WORD   ; 2 bytes
    call WriteHexB      ; displays: "7FFF"
    mov eax,216543
    call WriteInt   ; displays: "+216543"
.data
    prompt BYTE "Enter your name: ",0
.code
    mov edx,OFFSET prompt
    call WriteString
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
    call WriteWindowsMsg

5. Irvine32 库测试程序

1). 教程:Library Test #1
; 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)             ; 默认的控制台前景色和背景色
.data
    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             ; 为了使设置的颜色生效,调用清屏方法

    INVOKE ExitProcess, 0   ; 退出程序
main ENDP           ; 函数结束位置, ENDP 之前的内容,要与PROC 
END main            ; 设置了函数的入口与出口
    mov esi, OFFSET arrayD  ; 设置数组首地址
    mov ebx, TYPE arrayD    ; 设置数组元素所占字节数
    mov esi, OFFSET arrayD  ; 设置数组首地址
    mov ebx, TYPE arrayD    ; 设置数组元素所占字节数
    mov ecx, LENGTHOF arrayD; 数组元素个数
    call DumpMem            ; 显示信息

效果如下:


DumpMem效果.png
    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             ; 清屏

效果:

InputLoop程序.png
; 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), 原文地址

/LARGEADDRESSAWARE:NO.png
上一篇下一篇

猜你喜欢

热点阅读