这就是我迄今为止所做的:
.MODEL SMALL
.STACK 64
.DATA
X DW 5463h,0F8A8h,0D37Eh
Y DW 87DEh,3408h,92C2h
Result DW 3 DUP(0) ;Trying to add X, Y with the result being here.
.Code
MAIN PROC FAR
MOV AX,@Data
MOV DS,AX
;Adding X,Y:
;Getting Pointers Ready
LEA SI,X
LEA DI,Y
LEA BP,Result
MOV CX,3 ; Counter
CLC ;Clearing the carry
PushF ;We don't want the flag to be affected from the next two operations
;Looping three times to Add Word by Word
WordAdd:
MOV AX,[SI+4] ;We will iterate from the least significant word (4) to the most significant word (0)
MOV BX,[DI+4]
PopF ;Retaining the flag register
ADC AX,BX
PushF
MOV [BP+4],AX
Sub BP,2
Sub SI,2
Sub DI,2
Loop WordAdd
MOV Ax,[BP]
MOV BX,[BP+2]
MOV CX,[BP+4]
MAIN ENDP
END MAIN
出于某种原因,AX、BX、CX最终都是0000,但我不明白为什么,尽管我确保添加操作正确执行,并通过调试每次都放入AX中。
您的代码正确地计算了和,并将其存储在Result
的三个单词中,以您不寻常的混合endian顺序。但是,请注意BP
中的地址:开始时指向Result
,并在循环的每次迭代中将其递减2。由于你将循环中的单词存储到[BP+4]
,你得到了正确的单词,但在循环后BP
指向Result-6
。因此,您对AX, BX, CX
的加载分别来自Result-6
、Result-4
和Result-2
,它们不是存储总和的位置。
一些更一般的建议:
-
您当前的设计需要各种神奇的偏移,如
[BP+4]
、[BP+6]
等,分散在整个代码中。这些都取决于您的数组大小,因此您可以有效地在大约10个位置对该大小进行硬编码。想想当你想修改你的程序以添加四个单词的数字时的痛苦,或者天哪,一个长度要在运行时确定。所以你可能会考虑避免这种情况的设计。例如,如果从BP
开始,指向最后一个元素而不是第一个元素。 -
正如Brendan所说,您的混合endian词序是非常规的,可能会混淆其他程序员。颠倒顺序也可以简化代码,因为您可以向前而不是向后遍历数组。
-
当您可以简单地执行
ADC AX, [DI+4]
时,像MOV BX,[DI+4]
/ADC AX,BX
这样的序列是多余的。CPU设计人员费了很大的劲才使每条指令都能用一个内存操作数使用;不妨利用一下。 -
CCD_ 17可以被CCD_。对于其他只加载常量地址的
LEA
也是如此。 -
请记住,使用
BP
的内存引用是相对于堆栈段SS
隐式的。对于DS
和SS
相等的SMALL
模型来说,这很好,但如果您切换代码模型,您会想知道为什么您的代码不写入Result
,即使BP
";显然";指向它。 -
您在循环(
BP, SI, DI, CX
(中使用了四个不同的寄存器,它们基本上都只是跟踪循环索引。看看你能不能把这个降到一个。通过执行类似MOV AX, [X+BX]
MOV DX, [Y+BX]
的操作,可以将单个寄存器用作所有数组的偏移量。 -
如果你最终要使用现代x86 CPU,
LOOP
指令是一个坏习惯,因为它的优化效果很差,而且不鼓励使用。在这样的机器上,自己进行递减和条件跳跃实际上更有效,而且它还让您可以自由使用任何寄存器,而不是绑定到CX
。 -
同样,
PUSHF/POPF
技巧也是一个坏习惯,因为这些指令在现代CPU上非常昂贵,因为它们可能会操纵中断标志。尝试设计循环的其余部分,使其在迭代之间保持进位标志不变。INC
和DEC
指令在这里很好,因为它们不修改它;像这样的循环正是它们被设计成那样的原因。 -
将助记符大写,并始终如一地注册姓名。有些人喜欢大写,有些人喜欢小写,但没有人喜欢混合大小写。
至少有2个错误:
a( 最后一个pushf
永远不会弹出(正如Nate Eldredge在评论中提到的(。这可能会导致程序在返回到调用程序时崩溃。
b( 你把订单弄错了。80x86是little-endian;最重要的单词第一";。这将导致进位错误(如果是十进制数字而不是16位字,则类似于"090+010=001"(。
注意,因为你知道总会有3个单词,而且3很小,所以最好不要循环。这可能看起来像:
MOV AX,[X]
MOV BX,[X+2]
MOV CX,[X+4]
ADD AX,[Y]
ADC BX,[Y+2]
ADC CX,[Y+4]
还要注意,所有现代的80x86 CPU(自1985年的80386以来(都允许您在16位代码中使用32位指令。这可以让你做一些更像:
MOV EAX,[X]
MOV BX,[X+4]
ADD EAX,[Y]
ADC BX,[Y+4]