汇编--通过堆栈传递参数方法

本文通过堆栈传递参数方法,完成将ARY为首地址的COUNT个字数据累加,不考虑溢出,并将结果保存在SUM中

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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
STSTACKS   SEGMENT  STACK
DW 200H DUP(?)
TOP LABEL WORD
STACKS ENDS --定义栈大小

DATAS SEGMENT
ARY DW 123,-54,267,251,55,9 --定义一串数字
COUNT EQU ($-ARY)/2 --表示ARY串的changdu
SUM DW ? --定义SUM变量存放累加和
DATAS ENDS

CODES SEGMENT
ASSUME CS:CODE,SS:STACKS,DS:DATAS

MAIN PROC NEAR
MOV BX,OFFSET ARY --ARY的首地址传入BX
PUSH BX --BX进栈
MOV BX,COUNT --COUNT的值送入BX
PUSH BX --BX进栈
MOV BX,OFFSET SUM --SUM的首地址传入BX
PUSH BX --BX进栈
CALL PROADD --调用子程序PROADD
INT 20H
MAIN ENDP

PROADD PROC NEAR
PUSH BP --保存现场
MOV BP,SP --将SP的值送入BP中,用于后面通过BP读取数据,不改变SP的值
PUSH AX
PUSH CX
PUSH SI
PUSH DI --保存现场
MOV SI,[BP+8] --BP+8地址为ARY的首地址
MOV CX,[BP+6] --BP+6地址里存的是COUNT的值
MOV DI,[BP+4] --BP+4地址存着SUM的首地址
XOR AX,AX --AX清零,用于累加
NEXT: ADD AX,[SI] --进行累加
ADD SI,2 --地址后移
LOOP NEXT
MOV [DI],AX --将累加和存入SUM中
POP DI
POP SI
POP CX
POP AX
POP BP 回复现场
RET
PROADD ENDP

CODES ENDS
END MAINACKS SEGMENT STACK
DW 100 DUP(?)
TOP LABEL WORD
STACKS ENDS

DATAS SEGMENT
NUM1 DW 9,9,8,7,4,5,6,7,8,9
NUM2 DW 6,4,5,6,7,8,9 ;定义两个数字,首位存放num的长度,这两个数字将用于做乘法运算
S DW 300H DUP(0) ;s用于存放结果
DATAS ENDS

CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
MAIN PROC FAR
MOV AX,STACKS
MOV SS,AX
LEA SP,TOP
MOV AX,DATAS
MOV DS,AX

LEA SI,NUM1
LEA DI,NUM2
LEA BX,S
ADD SI,2
ADD DI,2 ;加2的原因是因为第一位是数字的个数,从第二个数字开始才是真正的数,因为是DW的所以需要+2

MOV CX,NUM1
JIN1: PUSH [SI]
ADD SI,2
LOOP JIN1

LEA SI,NUM1
ADD SI,2
MOV CX,NUM1
CHU1: POP [SI]
ADD SI,2
LOOP CHU1 ;进栈出栈的目的是为了倒置该字符串用于乘法运算

MOV CX,NUM2
JIN2: PUSH [DI]
ADD DI,2
LOOP JIN2

LEA DI,NUM2
ADD DI,2
MOV CX,NUM2
CHU2: POP [DI]
ADD DI,2
LOOP CHU2 ;同上


LEA SI,NUM1
LEA DI,NUM2
LEA BX,S
ADD SI,2
ADD DI,2

MOV CX,NUM1 ;二重循环,把每个数都相乘,并存在s的对应位置,如果该位置里有值,则加上该值
L1: PUSH CX
MOV CX,NUM2
PUSH BX
PUSH DI
L2: MOV DX,[SI]
MOV AX,[DI]
MUL DX
ADD DI,2
ADD AX,[BX]
MOV [BX],AX
ADD BX,2

LOOP L2
POP DI
POP BX
ADD BX,2
POP CX
ADD SI,2
LOOP L1

XOR DX,DX
LEA BX,S
MOV CX,NUM1
ADD CX,NUM2 ;将s中每一个数除以10,余数放回原位,商作为进位
L4: MOV AX,[BX]
ADD AX,DX
MOV DL,10
DIV DL
MOV DL,AH
MOV [BX],DX
MOV DL,AL

ADD BX,2
LOOP L4


MOV CX,NUM1
ADD CX,NUM2


L5: SUB BX,2 ;逆序,输出结果
MOV DX,[BX]
ADD DX,30H
MOV AH,2
INT 21H

LOOP L5

L10: MOV AH,4CH
INT 21H
MAIN ENDP
CODES ENDS
END MAIN

这里面最难的地方是怎么判断栈里面的内容,我简单解释一下:

比如有一个栈,初始化的时候,SP指向的是栈顶同时也是最底部,当开始PUSH数据的时候,SP就会向上移动,我们可以知道程序中,最开始PUSH的元素是ARY的首地址其次是COUNT的值所以在调用子程序之前sp指向的是SUM的首地址。

然后调用子程序,首先要存源程序的下一条指令的地址值,然后再存其他的你想要存的内容。这时,我们把SP指向的地址位置送入BP,相当于BP用来标记这个位置,方便SP后面指向其他的位置。

这时我们就可以很轻易的得出,BP+8即为ARY的首地址、BP+6为COUNT的值、BP+4为SUM的首地址了

-->