1

我这里有一小部分计算器代码。我想就如何使用负数执行算术运算寻求帮助。

这是我的代码:

ASSCII_LOOP : MOV EDX , 0
                  DIV ECX 
                  OR DL , 30H       ;MAKE REMINDER ASSCII
                  MOV [ESI] , DL    ;PUT ASSCII IN ASSCII_NUM
                  DEC ESI
                  INC EBP           ;ADD ONE TO THE CHAR'S COUNTER
                  CMP EAX , 0       ;IF AX > 0 GOTO 
                  JA ASSCII_LOOP    ;ASSCII_LOOP

    CMP EDI , 0                     ;CHECK IF THAT WAS A NEGETIVE NUMBER
    JZ REST                         ;IF THATS NOT NEGETIVE GOTO REST
    MOV DL , '-'
    MOV [ESI] , DL                  ;ADD A MINES SIGN TO THE STRING
    DEC ESI
    INC EBP

REST :
    LEA EDI , ASSCII_NUM

    ;MOVE THE ASSCII CODE TO IT'S RIGHT PLCAE IN ASSCII_NUM
    ORDER_ASSCII : INC ESI
                   MOV AL , BYTE PTR [ESI] 
                   MOV BYTE PTR [EDI] , AL
                   INC EDI
                   DEC EBP
                   CMP EBP , 0
                   JA ORDER_ASSCII

    MOV CL , '$'           
    MOV BYTE PTR [EDI] , CL         ;AT LAST PUT A DOLLOR SIGN AT THE END OF ASSCII_NUM

该程序检查输入是否为负,如果为负则转到 REST。我想问以下问题:

* REST 在这个程序中的作用是什么?

*我想请教一下如何开始在这个程序中编写代码来对负数进行操作。我已经知道 2' 补码的事情,我想要的是 2's 补码的代码,我只是不知道从哪里开始,如何开始。我对汇编编程真的很陌生。希望你能帮助我。

这是我尝试过的代码,但它不起作用,我将其单独放置以便更好地理解:

neg_num: 
  mov ax, data
  mov ds, ax
  mov es, ax
  mov ah, 0000h
  mov al, num
  NOT al
  mov bl, al
  adc al, 00000001B
  mov bl, al
4

2 回答 2

1

我将向您展示如何实现 2 的补码以执行简单减法的示例。我将使用我自己的通用助记符来演示如何实现这一点。然后,您可以将其应用到您的汇编程序中。

我们将遵循 AB = A + (B( 1 的补码) + 1) 的模型

好的,假设我们想从 A (AB) 中减去累加器 B 的内容。

让我们假设我们的累加器 A 值的操作数就位([AccA]<-someValue)。

第一:从内存中获取你需要的值并将其存储在累加器 B 中。

    MOVM   B   'Move contents of memory into Acc B   ([AccB]<-someOtherValue)

第二:补B的值得到它的否定

    CMPL   B   'AccB = -B   

第三:将您的 1 的补码移到某个寄存器中以进行临时存储

    MOVBR R0  'Move contents of Acc B to Register 0

第四:我们想将“1”加载到现在可用的累加器 B

   MOVB   #1  'Move a '1' immediately to Acc B  [AccB]<- 1

第五:我们要把AccB的内容加到RO中,我们的-B就存放在这里

   ADDB   RO    ' This takes care of the (B(complement) +1 part of our model)
                ' The resulting value will be stored in AccB

第六:最后加上AccA和AccB

   ADAB     'Mnemonic for "Add AccA to AccB, result stored in AccA"

这满足了我们对 A + (B(complement) + 1) 的要求

这一切都假设您的架构不允许简单的 SUBA 或 SUBB 命令。一些处理器内置了它,但是由于您正在学习它的机制,因此上述基本代码结构有望为您描绘出更好的画面。

于 2013-02-13T19:42:32.677 回答
1

你在这方面遇到了太多麻烦,scarface23!x86 不使用 1 的补码,因此该示例可能有帮助,也可能没有帮助。我们使用 2 的补码,因为它“可以正常工作”(无论如何应该)。你最新的代码应该给你一个 2 的补码(adc这不是真的),但它会更容易neg al- 这就是它的作用。

REST一个示例的部分只是将您放置在缓冲区“末尾”的字符移动到缓冲区的“开头”。如果您在正确的位置 ( esi) 开始打印位置,您甚至不需要这样做。

就在你展示之前,你做了一些类似test eax, 8000h确定数字是否为负的事情。如果它是负数,则neg eax设置一个标志 ( edi) 以表明我们需要一个减号。由于您始终使用 32 位数字,因此我会...

test eax, eax
jns is_positive

仅测试第 15 位适用于 16 位数字,但您在这里使用的是 32 位寄存器/指令。混合大小的数字可能是给您带来麻烦的原因。既然你有一个非常好的(未经测试,但我看不出有什么问题)32 位数字到 ASCII 例程,请输入 32 位数字。或者,我认为如果您始终切换到 16 位寄存器,您的例程仍然可以工作。用 '$' 终止你的字符串让我知道这可能是 16 位代码。使用 32 位数字/寄存器/指令仍然可以使用,但请坚持使用一种数字大小。我想你会少一些麻烦。

在您未显示的部分 - 从键盘获取数字 - 如果用户以减号开头,请跳过减号并设置一个标志。将 ascii 按原样转换为数字,如果设置了标志,neg axneg eax在末尾转换为数字。

mov eax, 3
sub eax, 4

现在,eax将是负数 - 一个 2 的补码 - 只需使用它。如果您希望将其更改为正数,请“翻转”所有位(notxor全部位)并加 1。(这适用于正到负或负到正)这就是 2 的补码的工作原理,但是只需neg一条指令即可完成。

如果您需要在保留符号的同时更改数字的大小,movsx eax, al或者会这样做,但更容易坚持相同的大小,

您的代码中可能存在我没有看到的严重错误,但您所显示的内容对我来说看起来相当不错(除了mov al, RESULT +1部分)。我怀疑问题出在其他地方-也许混合了数字大小...

于 2013-02-14T07:22:13.290 回答