在汇编中添加两个三个单词的数字



这就是我迄今为止所做的:

.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-6Result-4Result-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隐式的。对于DSSS相等的SMALL模型来说,这很好,但如果您切换代码模型,您会想知道为什么您的代码不写入Result,即使BP";显然";指向它。

  • 您在循环(BP, SI, DI, CX(中使用了四个不同的寄存器,它们基本上都只是跟踪循环索引。看看你能不能把这个降到一个。通过执行类似MOV AX, [X+BX]MOV DX, [Y+BX]的操作,可以将单个寄存器用作所有数组的偏移量。

  • 如果你最终要使用现代x86 CPU,LOOP指令是一个坏习惯,因为它的优化效果很差,而且不鼓励使用。在这样的机器上,自己进行递减和条件跳跃实际上更有效,而且它还让您可以自由使用任何寄存器,而不是绑定到CX

  • 同样,PUSHF/POPF技巧也是一个坏习惯,因为这些指令在现代CPU上非常昂贵,因为它们可能会操纵中断标志。尝试设计循环的其余部分,使其在迭代之间保持进位标志不变。INCDEC指令在这里很好,因为它们不修改它;像这样的循环正是它们被设计成那样的原因。

  • 将助记符大写,并始终如一地注册姓名。有些人喜欢大写,有些人喜欢小写,但没有人喜欢混合大小写。

至少有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]

最新更新