80386汇编-过程
9unk Lv5

背景知识

  • 链接库 Irvine32.lib 用于 32 位保护模式下编写的程序,其中进行输入输出的过程调用了 MS-Windows API。
  • 链接库 Irvine16.lib 用于 16 位实地址模式下编写的程序,其中进行输入输出的过程调用了 MS-DOS 中断。

链接库

1
2
3

本书中附带的链接库

4
5
6
7

控制台窗口

8

向控制台输出内容:本质上是显存分出一小部分用来给控制台输出内容,当我们向显存的固定的位置写入字符,控制台就会显示内容。如果输出的内容超出控制台的大小(默认是25*80),那么控制台就会向下移动一行显示后面的内容。这个程序我们在16位汇编中写过,理解起来比较简单。在 32 位汇编中,显存地址由控制台句柄代替,句柄指的就是指针的指针。控制台窗口颜色属性设置,默认是黑底白字。

重定向输入输出

9

过程描述

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 两个字符来实现的。例如:

1
CALL Crlf

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)寄存器的内容,并同时显示进位、符号、零和溢出标志位的值。例如:

1
call DumpRegs

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

10

这个原理和 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

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

后续还有很多函数,有兴趣的自行阅读。

库测试程序

整数 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(压入)的过程:
26

堆栈 POP(出栈)的过程:
27

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 伪指令

28

CALL 和 RET 指令

29
30
31
32
33
34

例子:创建一个子程序,对整数数组求和。

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

流程图

35
36
37

大多数入门的程序设计教科书都已经不再介绍流程图了,应为对于已经封装好的函数和数据结构(面向对象程序设计)而言流程图并不适用。

保护和恢复寄存器

38
39

注意:恢复堆栈时,不要把返回值带进去

使用过程进行程序设计

整数求和程序(设计)

  • 第一步:审题

    写一个程序,提示用户输入 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 ;显示整数
  • 第五步:画出程序结构图
    40

  • 第六步:设计简化版程序框架,其中包含各个子程序的功能描述、入口参数、出口参数
    41
    42
    43

  • 第七步:填写需要的变量和各子程序之间入口参数,实现程序。
    44
    45

  • 编写程序

    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 个值存储在一个双数组中并把双字数组写入一个磁盘文件。打开文件内容如下:
46

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

求和程序

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
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
  • 本文标题:80386汇编-过程
  • 本文作者:9unk
  • 创建时间:2022-11-13 23:53:00
  • 本文链接:https://9unkk.github.io/2022/11/13/80386-hui-bian-guo-cheng/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!