背景知识
链接库 Irvine32.lib 用于 32 位保护模式下编写的程序,其中进行输入输出的过程调用了 MS-Windows API。
链接库 Irvine16.lib 用于 16 位实地址模式下编写的程序,其中进行输入输出的过程调用了 MS-DOS 中断。
链接库
本书中附带的链接库
控制台窗口
向控制台输出内容:本质上是显存分出一小部分用来给控制台输出内容,当我们向显存的固定的位置写入字符,控制台就会显示内容。如果输出的内容超出控制台的大小(默认是25*80),那么控制台就会向下移动一行显示后面的内容。这个程序我们在16位汇编中写过,理解起来比较简单。在 32 位汇编中,显存地址由控制台句柄代替,句柄指的就是指针的指针。控制台窗口颜色属性设置,默认是黑底白字。
重定向输入输出
过程描述 CloseFile(仅Irvine32) CloseFile 过程关闭一个以前打开的文件。文件是以文件句柄(handle)标识的,文件句柄通过 EAX 传递。如果文件被成功关闭,EAX中返回非零值。例如:
1 2 MOV EAX,FileHandle CALL CloseFile
CLrscr CLrscr 过程用于清除控制台窗口的内容,它通过在程序的开始和结束时使用。最好在调用 Clrscr 之前暂停一下程序(调用 WaitMsg),以便用户在清屏之前看清已有的信息。例如:
1 2 CALL WaitMsg CALL Clrscr
Crlf Crlf 过程把光标定位到控制台窗口下一行的开始,该功能是通过向标准输出写入 0DH 和 0AH 两个字符来实现的。例如:
CreateOutputFile(仅Irvine32) CreateOutputFile 过程创建一个磁盘文件并以输出模式打开。使用时通过 EDX 传递要创建的文件名的偏移地址。过程返回时,如果文件创建成功,则 EAX 包含一个有效的文件句柄(一个32位整数)。如果创建失败,EAX 中的值是 INVALID_HANDLE_VALUE = -1(一个预定义的常量)。例如:
1 2 3 4 5 6 7 8 9 10 .data filename BYTE "newfile.txt",0 handle DWORD ? .code mov edx,OFFSET filename call CreateOutputFile cmp eax,INVALID_HANDLE_VALUE je file_error ;显示文件错误信息 mov handle,eax ;保存文件句柄
Delay Delay 过程暂停程序指定的毫秒数。EAX 是入口参数,因此在调用该过程之前要把 EAX 初始化为预期暂停的事件,以毫秒为单位计算。例如:
1 2 mov eax,1000 ;1s call Delay
DumpMem DumpMem 过程以十六进制数格式在控制台窗口中新鲜事一块内存的内容。在调用之前,需要将 ESI 设置为内存的开始地址,ECX设置为元素数目,EBX设置为元素尺寸。下面的语句显示一个名为 array 的包含 11 个双字变量的数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 INCLUDE Irvine32.inc .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 exit main ENDP END main
DumpRegs DumpRegs 过程以十六进制数格式显示 EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP,EIP,EFL(EFLAGS)寄存器的内容,并同时显示进位、符号、零和溢出标志位的值。例如:
GetCommandTail GetCommandTail 过程把程序的命令行复制到一个以空字符结尾的字符串中。如果命令行为空,则设置进位标志位。这个过程允许用户通过命令行传递信息。例如:下面的程序读取并输出参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 STD_OUTPUT_HANDLE = -11 NULL = 0 INCLUDE Irvine32.inc .data cmdTail BYTE 129 DUP(0) .code main PROC MOV edx,OFFSET cmdTail CALL GetCommandtail INVOKE GetStdHandle,STD_OUTPUT_HANDLE INVOKE WriteConsole,eax,addr cmdTail,sizeof cmdTail,ebx,NULL exit main ENDP END main
这个原理和 8086 汇编中的 PSP 段一样。
GetMaxXY(仅Irvine32) GetMaxXY 过程返回控制台窗口缓冲区大小。如果控制台窗口缓冲区的大小大于可见窗口部分,控制台会出现滚动条。GetMaxXY 无输入参数。返回时,DL存放窗口缓冲区的列数,DH存放窗口缓冲区的行数。该过程要求行数和列数都不能大于 255,实际窗口缓冲区的行列大小会超过255,不过从这种情况少见。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 INCLUDE Irvine32.inc .data rows BYTE ? cols BYTE ? .code main PROC CALL GetMaxXY MOV rows,dh MOV cols,dl MOV esi,OFFSET rows MOV ECX,2 MOV EBX,TYPE rows CALL DumpMem exit main ENDP END main
GetMseconds GetMseconds 计算程序运行的毫秒数,返回值在 EAX 中,这个过程可用来测量两个事件之间的间隔。该过程不需要输入参数。例如,程序首先调用该过程并保存其返回值,然后执行循环。循环结束后再次调用 GetMseconds 过程并把这两次调用的返回值相减,这样就得到以毫秒计算的循环执行的大致时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 INCLUDE Irvine32.inc .data startTime DWORD ? .code main PROC CALL GetMseconds MOV startTime,eax MOV ecx,5 L1: ADD eax,1 LOOP L1 SUB eax,startTime CALL DumpRegs exit main ENDP END main
后续还有很多函数,有兴趣的自行阅读。
库测试程序 整数 I/O 把文本的颜色改为蓝底黄字,然后以十六进制数显示数组的内容,最后提示用户输入一个有符号整数,再分别以十进制、十六进制和二进制数格式重复显示该整数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 ;--------------------------- ;程序名:Testlib1.asm ;功能:把文本的颜色改为蓝底黄字,然后以十六进制数显示数组的内容,最后提示用户输入一个有符号整数,再分别以十进制、十六进制和二进制数格式重复显示该整数 ;作者:9unk ;编写时间:2022-11-20 ;---------------------------- INCLUDE Irvine32.inc .data arrayD DWORD 1000h,2000h,3000h prompt1 BYTE "Enter a 32-bit signed integer: ",0 dwordVal DWORD ? .code main PROC ;使用 SetTextColor 函数设置蓝底黄字 MOV eax,yellow + (blue*16) CALL SetTextColor CALL Clrscr ;清屏 ;输出数组内容 MOV esi,OFFSET arrayD MOV ecx,LENGTHOF arrayD MOV ebx,TYPE arrayD CALL DumpMem CALL crlf ;提示用户输入一个十进制整数 MOV edx,OFFSET prompt1 CALL WriteString CALL ReadInt MOV dwordVal,eax ;以十进制、十六进制和二进制数显示整数 CALL crlf CALL WriteInt CALL crlf CALL WriteHex call crlf CALL WriteBin CALL crlf CALL WaitMsg ;将控制台窗口设为默认颜色 MOV eax,lightGray + (black*16) CALL SetTextColor CALL Clrscr exit main ENDP END main
随机整数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 ;--------------------------- ;程序名:Testlib2.asm ;功能:测试 Irvine32 链接库中的随机数生成过程 ;作者:9unk ;编写时间:2022-11-21 ;---------------------------- INCLUDE Irvine32.inc TAB = 9 .code main PROC CALL Randomize ;初始化随机数发生器 CALL Rand1 CALL rand2 exit main ENDP Rand1 PROC ;生成 10 个伪随机整数 MOV ecx,10 L1: CALL Random32 CALL WriteDec MOV al,TAB CALL WriteChar LOOP L1 CALL Crlf RET Rand1 ENDP Rand2 PROC ;生成10个在范围-50~+49之间的伪随机整数 MOV ecx,10 L1: MOV eax,100 CALL RandomRange SUB eax,50 CALL WriteInt MOV al,TAB CALL WriteChar LOOP L1 CALL Crlf RET Rand2 ENDP END main
性能度量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 ;--------------------------- ;程序名:Testlib3.asm ;功能:计算执行嵌套循环用去的时间 ;作者:9unk ;编写时间:2022-11-21 ;---------------------------- INCLUDE Irvine32.inc OUTER_LOOP_COUNT = 3 .data startTime DWORD ? msg1 BYTE "Please wait...",0dh,0ah,0 msg2 BYTE "Elapsed milliseconds: ",0 .code main PROC MOV edx,OFFSET msg1 CALL WriteString ;保存起始时间 CALL GetMSeconds MOV startTime,eax MOV ecx,OUTER_LOOP_COUNT ;执行循环 L1: CALL innerLoop LOOP L1 ;显示用去的时间 CALL GetMSeconds SUB eax,startTime MOV edx,OFFSET msg2 CALL WriteString CALL WriteDec CALL Crlf exit main ENDP innerLoop PROC PUSH ecx MOV ecx,0ffffffffh L1: MOV eax,eax LOOP L1 POP ecx RET innerLoop ENDP END main
堆栈操作 运行时栈是由 CPU 进行管理的,它使用两个寄存器:SS 和 ESP。在保护模式下,SS寄存器存放的位置是段选择子,用户模式下不应对其进行修改。ESP 寄存器存放的是指向堆栈内特定位置的一个 32 位偏移值。ESP寄存器的值通常是由 CALL,RET,PUSH和POP等指令间接修改的。如下图所示,堆栈 PUSH(压入)的过程:
堆栈 POP(出栈)的过程:
X86系统,堆栈是32位的,因此每次 PUSH 压入 ESP 都会减4,每次 POP 弹出 ESP 都会加4。
本节中的其他内容和 80x86 一样这里就不再重复看了。
例子:反转字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ;--------------------------- ;程序名:RevStr.asm ;功能:将字符串压入堆栈,来实现字符串反转。 ;作者:9unk ;编写时间:2022-11-22 ;---------------------------- INCLUDE Irvine32.inc .data aName BYTE "Abraham Lincoln",0 nameSize = ($-aName)-1 .code main PROC ;字符串压入堆栈 XOR esi,esi MOV ecx,nameSize L1: MOVZX eax,aName[esi] PUSH eax INC esi LOOP L1 ;字符串弹出堆栈 XOR esi,esi MOV ecx,nameSize L2: POP eax MOV aName[esi],al INC esi LOOP L2 ; MOV edx,OFFSET aName CALL WriteString CALL Crlf exit main ENDP END main
过程的定义和使用 PROC 伪指令
CALL 和 RET 指令
例子:创建一个子程序,对整数数组求和。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 ;--------------------------- ;程序名:ArraySum.asm ;功能:创建一个子程序,对整数数组求和。 ;作者:9unk ;编写时间:2022-11-22 ;---------------------------- INCLUDE Irvine32.inc .data array DWORD 10000h,20000h,30000h,40000h,50000h theSum DWORD ? .code main PROC MOV esi,OFFSET array MOV ecx,LENGTHOF array CALL ArraySum MOV theSum,eax CALL DumpRegs exit main ENDP ;------------------------------ ArraySum PROC ;Calculates the sum of an array of 32-bit integers ;Recevies: ESI = the array offset ; ECX = number of elements in the array ;Returns: EAX = sum of the array elements ;------------------------------ PUSH esi PUSH ecx MOV eax,0 L1: ADD eax,[esi] ADD esi,TYPE DWORD LOOP L1 ; POP ecx POP esi RET ArraySum ENDP END main
流程图
大多数入门的程序设计教科书都已经不再介绍流程图了,应为对于已经封装好的函数和数据结构(面向对象程序设计)而言流程图并不适用。
保护和恢复寄存器
注意:恢复堆栈时,不要把返回值带进去
使用过程进行程序设计 整数求和程序(设计)
第一步:审题
写一个程序,提示用户输入 3 个 32 位整数,将其保存在数组中,计算数组内的元素的和并在屏幕上显示。
第二步:分解任务,并用伪代码写出
1 2 3 4 整数求和程序 提示用户输入3个整数 计算整数数组的和 显示结果
第三步:在准备写程序之前,为每个任务起一个过程名
1 2 3 4 Mian PromptForIntegers ArraySum DisplaySum
第四步:思考这个程序需要调用哪些函数库种的程序,并完善第二步
1 2 3 4 5 6 7 8 9 Mian Clrscr ;清屏 PromptForIntegers WriteString ;显示字符串 ReadInt ;输入整数 ArraySum ;对整数求和 DisplaySum WriteString ;显示字符串 WriteInt ;显示整数
第五步:画出程序结构图
第六步:设计简化版程序框架,其中包含各个子程序的功能描述、入口参数、出口参数
第七步:填写需要的变量和各子程序之间入口参数,实现程序。
编写程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 ;--------------------------- ;程序名:Sum2.asm ;功能:写一个程序,提示用户输入 3 个 32 位整数,将其保存在数组中,计算数组内的元素的和并在屏幕上显示。 ;作者:9unk ;编写时间:2022-11-22 ;---------------------------- INCLUDE Irvine32.inc INTEGER_COUNT = 3 .data str1 BYTE "Enter a signed integer: ",0 str2 BYTE "The sum of the integer is: ",0 array DWORD INTEGER_COUNT DUP(?) .code main PROC CALL Clrscr MOV esi,OFFSET array MOV ecx,INTEGER_COUNT CALL PromptForIntegers CALL ArraySum CALL DisplaySum exit main ENDP ;------------------------------------------------ PromptForIntegers PROC USES ecx edx esi ;功能:提示用户输入任意数量的整数,并将整数插入数组。 ;入口参数: ESI = 数组指针, ecx = 数组的大小 ;出口参数: 无 ;------------------------------------------------ MOV edx,OFFSET str1 L1: CALL WriteString CALL ReadInt CALL Crlf MOV [esi],eax ADD esi,TYPE DWORD LOOP L1 RET PromptForIntegers ENDP ;------------------------------------------------- ArraySum PROC USES esi ecx ;功能:计算32位整数数组的和。 ;入口参数:esi = 数组指针,ecx = 数组的元素个数 ;出口参数:eax = 数组元素的和 MOV eax,0 L1: ADD eax,[esi] ADD esi,TYPE DWORD LOOP L1 RET ArraySum ENDP ;------------------------------------------------ DisplaySum PROC USES edx ;功能:在屏幕上显示数字 ;入口参数:eax ;出口参数:无 ;------------------------------------------------ MOV edx,OFFSET str2 CALL WriteString CALL WriteInt CALL Crlf RET DisplaySum ENDP END main
课后练习 绘制彩色文本 写一个程序,调用本书链接库中的 SetTextColor 过程,以 4 种不同的颜色显示同一种字符串,要求使用一个循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ;--------------------------- ;程序名:lx5-1.asm ;功能:写一个程序,调用本书链接库中的 SetTextColor 过程,以 4 种不同的颜色显示同一种字符串,要求使用一个循环。 ;作者:9unk ;编写时间:2022-11-29 ;---------------------------- ;1、数据:定义一个颜色变量 color,初始值是 “黑底蓝字“ ;2、定义一个以 0 结尾的字符串变量 message: Hello World! ;3、清屏 ;4、构造循环体输出 4 次不同颜色的字符串,每次循环 color变量加1 ;5、恢复窗口颜色 INCLUDE Irvine32.inc .data message db 'Hello World!',0 color dd blue + (black*16) .code main PROC CALL Clrscr MOV ecx,4 print: MOV eax,color CALL SetTextColor MOV edx,OFFSET message CALL WriteString CALL Crlf INC color LOOP print MOV eax,gray + (black*16) CALL SetTextColor exit main ENDP END main
斐波那契数文件 写一个斐波那契数列的前 47 个值,把这 47 个值存储在一个双数组中并把双字数组写入一个磁盘文件。打开文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 ;--------------------------- ;程序名:lx5-2.asm ;功能:写一个斐波那契数列的前 47 个值,把这 47 个值存储在一个双数组中并把双字数组写入一个磁盘文件。 ;作者:9unk ;编写时间:2022-11-30 ;---------------------------- ;1、把 lx4-6.asm 改写为子函数,向指定大小数组写入斐波那契数列 ;2、创建文件 ;3、写入数据 ;4、关闭文件 INCLUDE Irvine32.inc .data filename BYTE "Fib.txt",0 handles DWORD ? FibSeq dd 47 DUP(0) create_err db 'Failed to create file!',0 write_err db 'Failed to write file!',0 .code main PROC ;存储数组 MOV ecx,47 MOV esi,OFFSET FibSeq CALL FibSeqs ;创建文件 MOV edx,OFFSET filename CALL CreateOutputFile CMP eax,INVALID_HANDLE_VALUE JE create_error ;MOV handle,eax ;写入数据 ;MOV eax,handle MOV edx,OFFSET FibSeq MOV ecx,LENGTHOF FibSeq*4 CALL writeToFile CMP eax,LENGTHOF FibSeq*4 jnz write_error ;关闭文件 MOV eax,handles CALL CloseFile JMP file_stop create_error: MOV edx,OFFSET create_err CALL WriteString JMP file_stop write_error: MOV edx,OFFSET write_err CALL WriteString file_stop: exit main ENDP ;------------------------------------------ FibSeqs PROC ;功能:将指定数量的斐波那契数列存储到数组中。 ;入口参数:esi=数组指针;ecx=斐波那契数列数量 ;出口参数:无 ;------------------------------------------ MOV DWORD PTR [esi-4],0 MOV DWORD PTR [esi],1 FibSeqs1: ADD esi,4 MOV eax,[esi-4] MOV edx,[esi-8] ADD eax,edx MOV DWORD PTR [esi],eax LOOP FibSeqs1 RET FibSeqs ENDP END main
简单加法1 写一个程序,首先清除屏幕并把光标定位在屏幕的中间位置,然后提示用户输入两个整数,把它们相加并显示和。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 ;--------------------------- ;程序名:lx5-3.asm ;功能:写一个程序,首先清除屏幕并把光标定位在屏幕的中间位置,然后提示用户输入两个整数,把它们相加并显示和。 ;作者:9unk ;编写时间:2022-11-30 ;---------------------------- ;1、清屏 ;2、获取窗口大小 ;3、重新定位光标 ;4、输出提示信息,要求用户输入两个整数。 ;5、显示两个数的和 INCLUDE Irvine32.inc .data msg db 'Please Input Integer: ',0 cloumn db 0 line db 0 .code main PROC CALL Clrscr CALL GETMaxXY ;行和列除以2 SHR dh,1 SHR dl,1 MOV line,dh MOV cloumn,dl CALL Gotoxy ;提示并输入第一个整数 MOV edx,OFFSET msg CALL WriteString CALL ReadInt MOV ebx,eax ;换行 CALL Crlf ;光标定位到下一行的屏幕中间位置 INC line MOV dh,line MOV dl,cloumn CALL Gotoxy ;提示输入第二个整数 MOV edx,OFFSET msg CALL WriteString CALL ReadInt ;光标定位到下一行的屏幕中间位置 INC line MOV dh,line MOV dl,cloumn CALL Gotoxy ;输出结果 ADD eax,ebx CALL WriteInt exit main ENDP END main
简单加法2 用上一程序作为起点,使用循环令其重复执行三次,每次重复之后清除屏幕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 ;--------------------------- ;程序名:lx5-4.asm ;功能:用上一程序(lx5-3)作为起点,使用循环令其重复执行三次,每次重复之后清除屏幕。 ;作者:9unk ;编写时间:2022-11-30 ;---------------------------- ;1、清屏 ;2、获取窗口大小 ;3、重新定位光标 ;4、输出提示信息,要求用户输入两个整数。 ;5、显示两个数的和 INCLUDE Irvine32.inc .data msg db 'Please Input Integer: ',0 cloumn db 0 line db 0 .code main PROC MOV ecx,3 loop1: CALL inputint ;CALL Clrscr CALL Crlf CALL WaitMsg LOOP loop1 exit main ENDP inputint PROC CALL Clrscr CALL GETMaxXY ;行和列除以2 SHR dh,1 SHR dl,1 MOV line,dh MOV cloumn,dl CALL Gotoxy ;提示并输入第一个整数 MOV edx,OFFSET msg CALL WriteString CALL ReadInt MOV ebx,eax ;换行 CALL Crlf ;光标定位到下一行的屏幕中间位置 INC line MOV dh,line MOV dl,cloumn CALL Gotoxy ;提示输入第二个整数 MOV edx,OFFSET msg CALL WriteString CALL ReadInt ;光标定位到下一行的屏幕中间位置 INC line MOV dh,line MOV dl,cloumn CALL Gotoxy ;输出结果 ADD eax,ebx CALL WriteInt RET inputint ENDP END main
随机整数 写一个程序,生成并显示 50 个 -20~+20 之间的随机整数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ;------------------------------------------------------- ;程序名:lx5-5.asm ;功能:写一个程序,生成并显示 50 个 -20~+20 之间的随机整数。 ;作者:9unk ;编写时间:2022-11-30 ;------------------------------------------------------- ;使用 Randomize 生成随机数种子 ;使用循环生成并打印出结果 ;使用 RandomRange 生成0~40的伪随机数,然后再减 20 实现生成 -20~20 之间的随机数。 INCLUDE Irvine32.inc .code main PROC CALL Randomize MOV ecx,50 L1: MOV eax,41 CALL RandomRange SUB eax,20 CALL WriteInt MOV al,TAB CALL WriteChar LOOP L1 exit main ENDP END main
随机字符串 写一个程序,生成并显示 20 个随机字符串,每个字符串包含 10 个大写字母(A~Z)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ;------------------------------------------------------- ;程序名:lx5-6.asm ;功能:写一个程序,生成并显示 20 个随机字符串,每个字符串包含 10 个大写字母(A~Z)。 ;作者:9unk ;编写时间:2022-11-30 ;------------------------------------------------------- ;1、设计子程序循环随机生成一个字符 10 次 ;2、循环运行上面的子程序 20 次。 ;3、为了实现字符串随机,我们还需要在循环中加上随机延时来达到目的。 ;随机延时时间在0~15ms就可以达到目的。 INCLUDE Irvine32.inc .code main PROC MOV ecx,20 L1: CALL RandomStr CALL Crlf ;定义一个随机延时 CALL Randomize MOV eax,15 CALL RandomRange CALL Delay LOOP L1 exit main ENDP ;------------------------------------------------- RandomStr PROC USES ecx ;功能:随机生成使用 10 个 A~Z 之间的字母生成的字符串 ;入口参数:无 ;出口参数:无 ;------------------------------------------------- CALL Randomize MOV ecx,10 RandomStr1: MOV eax,26 CALL RandomRange ADD eax,65 CALL WriteChar LOOP RandomStr1 RET Randomstr ENDP END main
随机屏幕位置 写一个程序,在100个随机的屏幕位置显示一个字符,在显示字符时使用 100ms 的延迟。提示:使用 GetMaxXY 过程确定当前控制台窗口的大小。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 ;------------------------------------------------------------------------------ ;程序名:lx5-7.asm ;功能:写一个程序,在100个随机的屏幕位置显示一个字符,在显示字符时使用 100ms 的延迟。提示:使用 GetMaxXY 过程确定当前控制台窗口的大小。 ;作者:9unk ;编写时间:2022-11-30 ;------------------------------------------------------------------------------- ;1、清屏 ;2、GetMaxXY 获取屏幕大小 ;3、分别用行和列生成对应的随机数 ;4、使用 GotoXY 定位到屏幕位置 ;5、输出随机字母 ;6、延迟 100ms ;7、循环执行 100 次 INCLUDE Irvine32.inc .data cloumn db 0 line db 0 .code main PROC CALL Clrscr MOV ecx,100 L1: CALL GetMaxXY MOV line,dh MOV cloumn,dl ;随机生成行 MOVZX eax,dh INC al CALL RandomRange MOV line,al ;随机生成列 MOVZX eax,dl INC al CALL RandomRange MOV cloumn,al ;定位光标 MOV dh,line MOV dl,cloumn CALL GotoXY ;随机输出一个字符 CALL Randomchr ;延迟100毫秒 MOV eax,100 CALL Delay LOOP L1 ; exit main ENDP ;------------------------------------------------- Randomchr PROC ;功能:随机生成一个字符 ;入口参数:无 ;出口参数:无 ;------------------------------------------------- CALL Randomize ; MOV eax,26 CALL RandomRange ADD eax,65 CALL WriteChar RET Randomchr ENDP END main
色彩矩阵 写一个程序,以所有可能的前景和背景色的组合(16X16=256)显示某个字符。颜色值的取值范围是0~15,因此可以使用一个嵌套的循环来产生所有可能的组合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 ;-------------------------------------------------------------------------- ;程序名:lx5-8.asm ;功能:写一个程序,以所有可能的前景和背景色的组合(16X16=256)显示某个字符。 ;颜色值的取值范围是0~15,因此可以使用一个嵌套的循环来产生所有可能的组合。 ;作者:9unk ;编写时间:2022-12-1 ;-------------------------------------------------------------------------- ;1、清屏 ;2、每次循环:生成一个随机数 0~15 的随机数作为前景色 ;3、每次循环:生成一个随机数 0~15 的随机数作为背景色 ;4、每次循环:输出一个随机字母 A~Z ;5、循环结束:恢复原有屏幕颜色 ;6、结束程序 INCLUDE Irvine32.inc .data Fore dW ? Back dW ? .code main PROC CALL Clrscr MOV ecx,5 L1: ;随机生成前景色 CALL Randomize MOV eax,16 CALL RandomRange MOV Fore,ax ;随机延时15ms CALL Randomize MOV eax,15 CALL RandomRange CALL Delay ;随机生成背景色 CALL Randomize MOV eax,16 CALL RandomRange ;设置窗口颜色 ;MOV cl,4 SHL ax,4 ADD ax,Fore CALL SetTextColor ;输出随机字母 CALL Randomchr LOOP L1 ;恢复窗口颜色 MOV eax,gray+(black*16) CALL SetTextColor ;结束程序 exit main ENDP ;------------------------------------------------- Randomchr PROC ;功能:随机生成一个字符 ;入口参数:无 ;出口参数:无 ;------------------------------------------------- CALL Randomize ; MOV eax,26 CALL RandomRange ADD eax,65 CALL WriteChar RET Randomchr ENDP END main
求和程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 ;--------------------------- ;程序名:lx5-9.asm ;功能:按题目要求修改 sum2.asm ;作者:9unk ;编写时间:2022-12-1 ;---------------------------- INCLUDE Irvine32.inc ARRAY_SIZE = 20 .data str1 BYTE "Enter a signed integer: ",0 str2 BYTE "The sum of the integer is: ",0 str3 BYTE "How many integers whiLbe added? ",0 str4 BYTE "The Array cannot be larger than 20",0 array DWORD ARRAY_SIZE DUP(?) .code main PROC CALL Clrscr CALL Tips MOV esi,OFFSET array MOV ecx,eax CALL PromptForIntegers CALL ArraySum CALL DisplaySum exit main ENDP ;------------------------------------------------ PromptForIntegers PROC USES ecx edx esi ;功能:提示用户输入任意数量的整数,并将整数插入数组。 ;入口参数: ESI = 数组指针, ecx = 数组的大小 ;出口参数: 无 ;------------------------------------------------ MOV edx,OFFSET str1 L1: CALL WriteString CALL ReadInt CALL Crlf MOV [esi],eax ADD esi,TYPE DWORD LOOP L1 RET PromptForIntegers ENDP ;------------------------------------------------- ArraySum PROC USES esi ecx ;功能:计算32位整数数组的和。 ;入口参数:esi = 数组指针,ecx = 数组的元素个数 ;出口参数:eax = 数组元素的和 MOV eax,0 L1: ADD eax,[esi] ADD esi,TYPE DWORD LOOP L1 RET ArraySum ENDP ;------------------------------------------------ DisplaySum PROC USES edx ;功能:在屏幕上显示数字 ;入口参数:eax ;出口参数:无 ;------------------------------------------------ MOV edx,OFFSET str2 CALL WriteString CALL WriteInt CALL Crlf RET DisplaySum ENDP ;------------------------------------------------ Tips PROC USES edx ;功能:输出提示信息,如果数组数量小于20,返回值到eax ;如果大于20,提示报错信息,并终止程序。 ;入口参数:eax ;出口参数:eax ;------------------------------------------------ MOV edx,OFFSET str3 CALL WriteString CALL ReadInt ;CALL WriteInt CMP eax,20 JG pro_stop RET pro_stop: CALL Crlf MOV edx,OFFSET str4 CALL WriteString ;报错就直接终止程序 exit Tips ENDP END main