? 书中前几章的几个小程序,基本的运算操作,使用了作者的库 Irvine32 和 Irvine64(一开始以为作者网站过期了,各网站上找到的文件大小都不一样,最后发现是要搭* Orz,顺利下载)
● 代码,整数数组求和
1 .386 2 .model flat,stdcall 3 .stack 4096 4 5 ExitProcess PROTO, dwExitCode: dword 6 7 .data 8 array DWORD 10000h, 20000h, 30000h, 40000h, 9 10 .code 11 main PROC 12 mov edi, OFFSET array ; 变址寄存器获得 array 首元素地址 13 mov ecx, LENGTH array ; 循环计数器获得 array 元素个数 14 mov eax, 0 15 16 L1: 17 add eax, [edi] ; 将 array 每个元素加到 eax 中 18 add edi, TYPE array ; 递增变址寄存器 19 loop L1 ; 循环直到 ecx 减为 0 20 21 INVOKE ExitProcess, 0 22 main ENDP 23 24 END main
● 代码,整数数组求和,64位版本
1 ExitProcess PROTO 2 3 .data 4 array QWORD 1000000000000h, 2000000000000h, 3000000000000h, 4000000000000h, 5 6 .code 7 main PROC 8 mov rdi, OFFSET array ; 用到的寄存器都改成 64 位的版本 9 mov rcx, LENGTH array 10 mov rax, 0 11 12 L1: 13 add rax, [rdi] 14 add rdi, TYPE array 15 loop L1 16 17 mov ecx, 0 ; 还是使用 ecx 作为返回值 18 call ExitProcess 19 main ENDP 20 21 END
● 代码,复制字符串
1 .386 2 .model flat,stdcall 3 .stack 4096 4 5 ExitProcess PROTO, dwExitCode: dword 6 7 .data 8 source BYTE "Something to be copied 2333.",0 9 target BYTE SIZEOF source DUP(0) 10 11 .code 12 main PROC 13 mov esi, OFFSET source 14 mov ecx, LENGTH source 15 16 L1: 17 mov al, source[esi] 18 mov target[esi], al 19 inc esi 20 loop L1 21 22 INVOKE ExitProcess, 0 23 main ENDP 24 25 END main
● 涨姿势,代码中间有一个块段注释没有封口(直到代码结尾都是注释),报错信息是 END directive required at end of file。
● 代码,翻转字符串
1 .386 2 .model flat,stdcall 3 .stack 4096 4 5 ExitProcess PROTO, dwExitCode: dword 6 7 .data 8 source BYTE "Something to be copied 2333.", 0 9 nameSize = ($ - source) - 1 ; 使用常量来存储字符串的长度 10 11 .code 12 main PROC 13 mov esi, 0 14 mov ecx, LENGTH source 15 16 L1: 17 movzx eax, source[esi] ; 获取字符,压栈,递增指针,循环 18 push eax 19 inc esi 20 loop L1 21 22 mov esi, 0 ; 相同的赋值 23 mov ecx, LENGTH source 24 L2: 25 pop eax ; 吐栈,放入字符,递增指针,循环 26 mov source[esi], eax 27 inc esi 28 loop L2 29 30 INVOKE ExitProcess, 0 31 main ENDP 32 33 END main
● 代码,使用子过程计算数组的和
1 .386 2 .model flat,stdcall 3 .stack 4096 4 ExitProcess proto,dwExitCode:dword 5 6 .data 7 array dword 10000h,20000h,30000h,40000h,50000h 8 sum dword ? 9 10 .code 11 sumArray proc uses esi ecx ; 定义子过程,uses 在栈中备份 esi 和 ecx,并在 ret 前还原 12 ;push esi ; 用栈备份用到的寄存器,与 uses 作用等效 13 ;push ecx 14 mov eax, 0 15 16 L1: ; 使用循环将和放入 eax 中 17 add eax, [esi] 18 add esi, type dword 19 loop L1 20 21 ;pop ecx ; 从栈中还原寄存器的状态 22 ;pop esi 23 ret ; 从子过程中返回 24 sumArray endp 25 26 main proc 27 mov esi, offset array 28 mov ecx, length array 29 30 call sumArray 31 mov sum, eax 32 33 invoke ExitProcess, 0 34 main endp 35 36 end main
● 代码,库 Irvine32 测试 1,简单的输入输出。记得在 “属性,配置属性,链接器,输入” 中加上 Irvine32.lib,并在工作目录下添加 Irvine32.inc,Irvine32.lib,SmallWin.inc,VirtualKeys.inc。
1 INCLUDE Irvine32.inc ; 包含库 2 .data 3 array DWORD 1000h,2000h,3000h 4 message BYTE "Enter a 32-bit signed integer: ", 0 5 dwordVal DWORD ? 6 7 .code 8 main PROC 9 mov eax, yellow + (blue * 16) 10 call SetTextColor 11 call Clrscr ; 清屏为背景色 12 call DumpRegs ; 显示当亲寄存器状态 13 14 mov esi, OFFSET array ; 三个寄存器分别存储数组的信息 15 mov ecx, LENGTHOF array 16 mov ebx, TYPE array 17 call DumpMem ; 调用库函数,输出数组所有元素 18 call Crlf ; 换行 19 20 mov edx, OFFSET message 21 call WriteString ; 输出字符串 22 call ReadInt ; 输入整数 23 mov dwordVal, eax ; 输入的整数存储到 eax 中 24 call Crlf 25 call WriteInt ; 用十进制、十六进制、二进制输出 eax 26 call Crlf 27 call WriteHex 28 call Crlf 29 call WriteBin 30 call Crlf 31 call WaitMsg ; 显示 "Press any key to cintinue" 并等待 32 33 mov eax, lightGray + (black * 16) ; 恢复终端颜色 34 call SetTextColor 35 call Clrscr 36 call WaitMsg 37 38 exit 39 main ENDP 40 END main
● 输出结果
; 清屏为蓝色 EAX=0000001E EBX=00436000 ECX=00961055 EDX=00961055 ESI=00961055 EDI=00961055 EBP=0075FE18 ESP=0075FE08 EIP=00963674 EFL=00000202 CF=0 SF=0 ZF=0 OF=0 AF=0 PF=0 Dump of offset 00966000 ------------------------------- 00001000 00002000 00003000 Enter a 32-bit signed integer: 65536 ; 输入 +65536 00010000 0000 0000 0000 0001 0000 0000 0000 0000 Press any key to continue... ; 清屏恢复黑色 Press any key to continue...
● 代码,库 Irvine32 测试 2,随机数
1 INCLUDE Irvine32.inc 2 3 TAB = 9 ; ASCII code for Tab 4 5 .code 6 main PROC 7 call Randomize ; 随机数种子 8 call Rand1 ; 无符号随机数 9 call Rand2 ; 有符号随机数 10 call WaitMsg 11 exit 12 main ENDP 13 14 Rand1 PROC 15 mov ecx, 10 16 L1: 17 call Random32 ; 生成随机整数用于输出 18 call WriteDec 19 mov al, TAB ; 给一个水平制表符用于输出 20 call WriteChar 21 loop L1 22 23 call Crlf 24 ret 25 Rand1 ENDP 26 27 Rand2 PROC 28 mov ecx, 10 29 30 L1: 31 mov eax, 100 32 call RandomRange ; 生成给定范围内的随机数 33 sub eax, 50 34 call WriteInt 35 mov al,TAB 36 call WriteChar 37 loop L1 38 39 call Crlf 40 ret 41 Rand2 ENDP 42 43 END main
● 代码,库 Irvine32 测试 3,计时器
1 INCLUDE Irvine32.inc 2 3 .data 4 OUTER_LOOP_COUNT = 3 5 startTime DWORD ? 6 msg1 BYTE "Start", 0dh, 0ah, 0 ; 等价于 "Start\r\n\0" 7 msg2 BYTE "End", 0dh, 0ah, "Time(ms): ", 0 8 9 .code 10 main PROC 11 mov edx, OFFSET msg1 12 call WriteString 13 14 call GetMSeconds ; 计时器1 15 mov startTime, eax 16 17 mov ecx, OUTER_LOOP_COUNT ; 外层循环 18 L1: 19 call innerLoop 20 loop L1 21 22 call GetMSeconds ; 计时器2 23 sub eax, startTime ; 直接在 eax 中计算耗时 24 25 mov edx, OFFSET msg2 ; 显示 26 call WriteString 27 call WriteDec 28 call Crlf 29 30 call WaitMsg 31 exit 32 main ENDP 33 34 innerLoop PROC uses ecx 35 mov ecx, 0FFFFFFFh ; 内层循环 36 L1: 37 mul eax ; 无符号乘法 38 mul eax 39 mul eax 40 loop L1 41 42 ret 43 innerLoop ENDP 44 45 END main
● 代码,库 Irvine32 测试 4,对话框
1 INCLUDE Irvine32.inc 2 3 .data 4 caption db "Title", 0 5 HelloMsg BYTE "This is a pop-up message box.", 0dh, 0ah, 0 6 7 .code 8 main PROC 9 mov ebx, OFFSET caption ; 标题,可以为 0 10 mov edx, OFFSET HelloMsg ; 对话框内容 11 call MsgBox 12 13 mov ebx, OFFSET caption 14 mov edx, OFFSET HelloMsg 15 call MsgBoxAsk ; 返回值在 eax 中,6(yes) 或 7(no) 16 17 call WaitMsg 18 exit 19 main ENDP 20 21 END main
● 代码,库 Irvine32 测试 5,用不同编码输出编号为 1~255 的字符
1 INCLUDE Irvine32.inc 2 3 SetConsoleOutputCP PROTO, pageNum:DWORD 4 5 .data 6 divider BYTE " - ", 0 7 codepage DWORD 1252 8 ; 1250 - Central Europe 9 ; 1251 - Cyrillic 10 ; 1252 - Latin I 11 ; 1253 - Greek 12 ; 1254 - Turkish 13 ; 1255 - Hebrew 14 ; 1256 - Arabic 15 ; 1247 - Baltic 16 ; 1258 - Vietnam 17 ; 874 - Thai 18 ; 437 - OEM United States 19 ; 858 - OEM Multilingual Latin and European 20 21 .code 22 main PROC 23 invoke SetConsoleOutputCP, codePage 24 25 mov ecx, 255 26 mov eax, 1 27 mov edx, OFFSET divider 28 L1: 29 call WriteDec ; eax 作为计数器 30 call WriteString ; edx 指向字符串 31 call WriteChar ; al 为得到的字符 32 call Crlf 33 inc aL 34 Loop L1 35 36 call WaitMsg 37 exit 38 main ENDP 39 40 END main
● 代码,库 Irvine64 测试 1,显示 20 个 64 位随机数
1 ExitProcess PROTO ; 手动声明需要用到的函数 2 WriteInt64 PROTO 3 Crlf PROTO 4 Random64 PROTO 5 RandomRange PROTO 6 Randomize PROTO 7 8 .code 9 main proc 10 sub rsp, 8 ; 栈指针对其到 16 Byte 11 sub rsp, 20h ; 影子空间 32 Byte 12 13 call Randomize 14 mov rcx, 20 15 L1: 16 mov rax, 234324243242 17 call RandomRange ; 返回的 64 位随机数在 eax 中 18 call WriteInt64 19 call Crlf 20 loop L1 21 22 add rsp, 28h ; 恢复 rsp 指针位置,main 中可以不用,子过程中需要 23 mov ecx, 0 24 call ExitProcess 25 main endp 26 27 end
● 涨姿势,链接时把 irvine64.obj 加入项目中(添加现有项),然后报错 LNK2017 没有 /LARGEADDRESSAWARE:NO,“ADDR32”到“bufferLHB”的重定位无效 。改正:“属性,配置属性,连接器,系统,启用大地址” 选否(/LARGEADDRESSAWARE:NO),即可正确运行。
● 代码,库 Irvine64 测试 2,简单的输入输出
1 ExitProcess proto 2 ReadInt64 proto 3 ReadString proto 4 WriteString proto 5 WriteInt64 proto 6 WriteHex32 proto 7 WriteHex64 proto 8 Crlf proto 9 10 .data 11 message BYTE "Test irvine64.lib", 0 12 maxval qword 9223372036854775807 13 minval qword -9223372036854775808 14 inbuf BYTE 50 dup(0),0 15 inbuf_size = $ - inbuf 16 17 .code 18 main proc 19 20 mov rdx,offset message 21 call WriteString 22 call Crlf 23 24 call ReadInt64 ; 从键盘读取一个 64 位整数 25 call Crlf 26 call WriteInt64 27 call Crlf 28 29 mov rdx,offset inbuf 30 call WriteString 31 call Crlf 32 33 mov rax, minVal 34 call WriteInt64 35 call Crlf 36 37 mov rax, maxVal 38 call WriteInt64 39 call Crlf 40 41 mov ecx, 0 42 call ExitProcess 43 main endp 44 45 end