? 书中前几章的几个小程序,基本的运算操作,使用了作者的库 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 .code11 main PROC12 mov edi, OFFSET array ; 变址寄存器获得 array 首元素地址13 mov ecx, LENGTH array ; 循环计数器获得 array 元素个数14 mov eax, 015 16 L1:17 add eax, [edi] ; 将 array 每个元素加到 eax 中18 add edi, TYPE array ; 递增变址寄存器19 loop L1 ; 循环直到 ecx 减为 020 21 INVOKE ExitProcess, 022 main ENDP23 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 array10 mov rax, 011 12 L1:13 add rax, [rdi]14 add rdi, TYPE array15 loop L116 17 mov ecx, 0 ; 还是使用 ecx 作为返回值18 call ExitProcess19 main ENDP20 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 .code12 main PROC13 mov esi, OFFSET source14 mov ecx, LENGTH source15 16 L1:17 mov al, source[esi]18 mov target[esi], al19 inc esi20 loop L121 22 INVOKE ExitProcess, 023 main ENDP24 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 .code12 main PROC13 mov esi, 014 mov ecx, LENGTH source15 16 L1:17 movzx eax, source[esi] ; 获取字符,压栈,递增指针,循环18 push eax19 inc esi20 loop L121 22 mov esi, 0 ; 相同的赋值23 mov ecx, LENGTH source24 L2:25 pop eax ; 吐栈,放入字符,递增指针,循环26 mov source[esi], eax27 inc esi28 loop L229 30 INVOKE ExitProcess, 031 main ENDP32 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 .code11 sumArray proc uses esi ecx ; 定义子过程,uses 在栈中备份 esi 和 ecx,并在 ret 前还原12 ;push esi ; 用栈备份用到的寄存器,与 uses 作用等效13 ;push ecx14 mov eax, 015 16 L1: ; 使用循环将和放入 eax 中17 add eax, [esi]18 add esi, type dword19 loop L120 21 ;pop ecx ; 从栈中还原寄存器的状态22 ;pop esi23 ret ; 从子过程中返回24 sumArray endp25 26 main proc 27 mov esi, offset array28 mov ecx, length array29 30 call sumArray31 mov sum, eax32 33 invoke ExitProcess, 034 main endp35 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 SetTextColor11 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 message21 call WriteString ; 输出字符串22 call ReadInt ; 输入整数23 mov dwordVal, eax ; 输入的整数存储到 eax 中24 call Crlf 25 call WriteInt ; 用十进制、十六进制、二进制输出 eax26 call Crlf27 call WriteHex 28 call Crlf29 call WriteBin 30 call Crlf 31 call WaitMsg ; 显示 "Press any key to cintinue" 并等待32 33 mov eax, lightGray + (black * 16) ; 恢复终端颜色34 call SetTextColor35 call Clrscr36 call WaitMsg37 38 exit39 main ENDP40 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=0Dump of offset 00966000-------------------------------00001000 00002000 00003000Enter a 32-bit signed integer: 65536 ; 输入+65536000100000000 0000 0000 0001 0000 0000 0000 0000Press 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 WaitMsg11 exit12 main ENDP13 14 Rand1 PROC15 mov ecx, 1016 L1:17 call Random32 ; 生成随机整数用于输出18 call WriteDec19 mov al, TAB ; 给一个水平制表符用于输出20 call WriteChar21 loop L122 23 call Crlf24 ret25 Rand1 ENDP26 27 Rand2 PROC28 mov ecx, 1029 30 L1:31 mov eax, 10032 call RandomRange ; 生成给定范围内的随机数33 sub eax, 5034 call WriteInt35 mov al,TAB36 call WriteChar37 loop L138 39 call Crlf40 ret41 Rand2 ENDP42 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 ; 等价于 "Startrn" 7 msg2 BYTE "End", 0dh, 0ah, "Time(ms): ", 0 8 9 .code10 main PROC11 mov edx, OFFSET msg112 call WriteString13 14 call GetMSeconds ; 计时器115 mov startTime, eax16 17 mov ecx, OUTER_LOOP_COUNT ; 外层循环18 L1: 19 call innerLoop20 loop L121 22 call GetMSeconds ; 计时器223 sub eax, startTime ; 直接在 eax 中计算耗时24 25 mov edx, OFFSET msg2 ; 显示26 call WriteString27 call WriteDec28 call Crlf29 30 call WaitMsg31 exit32 main ENDP33 34 innerLoop PROC uses ecx 35 mov ecx, 0FFFFFFFh ; 内层循环36 L1:37 mul eax ; 无符号乘法38 mul eax39 mul eax40 loop L141 42 ret43 innerLoop ENDP44 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 ; 标题,可以为 010 mov edx, OFFSET HelloMsg ; 对话框内容11 call MsgBox12 13 mov ebx, OFFSET caption14 mov edx, OFFSET HelloMsg15 call MsgBoxAsk ; 返回值在 eax 中,6(yes) 或 7(no)16 17 call WaitMsg18 exit19 main ENDP20 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 - Cyrillic10 ; 1252 - Latin I11 ; 1253 - Greek12 ; 1254 - Turkish13 ; 1255 - Hebrew14 ; 1256 - Arabic15 ; 1247 - Baltic16 ; 1258 - Vietnam17 ; 874 - Thai18 ; 437 - OEM United States19 ; 858 - OEM Multilingual Latin and European20 21 .code22 main PROC23 invoke SetConsoleOutputCP, codePage24 25 mov ecx, 25526 mov eax, 127 mov edx, OFFSET divider28 L1: 29 call WriteDec ; eax 作为计数器30 call WriteString ; edx 指向字符串31 call WriteChar ; al 为得到的字符32 call Crlf33 inc aL34 Loop L135 36 call WaitMsg37 exit38 main ENDP39 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 proc10 sub rsp, 8 ; 栈指针对其到 16 Byte11 sub rsp, 20h ; 影子空间 32 Byte12 13 call Randomize14 mov rcx, 2015 L1:16 mov rax, 23432424324217 call RandomRange ; 返回的 64 位随机数在 eax 中18 call WriteInt6419 call Crlf20 loop L121 22 add rsp, 28h ; 恢复 rsp 指针位置,main 中可以不用,子过程中需要23 mov ecx, 024 call ExitProcess25 main endp26 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 .data11 message BYTE "Test irvine64.lib", 012 maxval qword 922337203685477580713 minval qword -922337203685477580814 inbuf BYTE 50 dup(0),015 inbuf_size = $ - inbuf16 17 .code18 main proc19 20 mov rdx,offset message21 call WriteString22 call Crlf23 24 call ReadInt64 ; 从键盘读取一个 64 位整数25 call Crlf26 call WriteInt6427 call Crlf28 29 mov rdx,offset inbuf30 call WriteString31 call Crlf32 33 mov rax, minVal34 call WriteInt6435 call Crlf36 37 mov rax, maxVal38 call WriteInt6439 call Crlf40 41 mov ecx, 042 call ExitProcess43 main endp44 45 end