【问题标题】:multiplication and division exercise in assembly x8086汇编x8086中的乘法和除法练习
【发布时间】:2014-03-12 18:15:06
【问题描述】:

几天前我刚开始学习组装,似乎我碰上了一堵坚固的墙。我有这个问题,我必须在汇编中制作一个接受整数输入(摄氏度)并将其转换为华氏度的程序。

这是我的代码:

org 100h

jmp compare 
var1 db 0 
ans1 db ?
num1 db ? 
num2 db ?
ex1 db ?
ex2 db ?

compare:
cmp var1,0
je start
jne move

move:
mov bl,var1
mov num1,bl
jmp digits

start:


mov ah,01h
int 21h
mov num1,al
cmp num1,0dh
jne digits
je convert

digits:



mov ah,01h
int 21h
cmp al,0dh
je revert
mov num2,al
jne proceed


proceed:
sub num1,48
mov cl,num1
mov al,10
imul cl
mov num1,al

sub num2,48


mov bl,num2
add num1,bl
mov bl,num1
mov var1,bl
jmp compare

revert:
cmp num2,0 ;also added this one too recently
jne c1
sub num1,48
c1:
mov bl,num1
mov var1,bl
jmp convert



convert:



mov cl, var1
mov al, 9
imul cl
mov cl, 5
idiv cl
add al, 32
mov ans1, al                
mov bl,ans1

mov dl,0    ;i recently added this for convertion
mov al,ans1
mov bl,10
div bl
mov ex1,al
mov ex2,ah

adc ex1,48
adc ex2,48





print:
mov ah,02h
mov dl,10
int 21h
mov ah,02h
mov dl,13
int 21h

mov ah,02h
mov dl,ans1
int 21h

mov ah,02h ;print the converted values
mov dl,ex1
int 21h
mov ah,02h
mov dl,ex2
int 21h
ret

我以前输入 15 会导致“;”在ASCII中是59。 我需要帮助来转换那个 ascii ;成十进制,当我输入更多 超过 2 个数字表示溢出除法。我该如何解决?提前致谢!

编辑:我最近添加了转换代码。它现在有点工作,但如果我在输入中输入超过“20”,输出就会出错。我使用了奥尔登的想法(非常感谢!)修改答案并单独转换和打印它。我现在还在做这个,我还在摸不着头脑哈哈。这么多错误哈哈。

再次编辑:这太奇怪了。我的程序只能转换以 5 结尾的数字。它只能正确转换 5 、 15 、 25 和 35 。这太奇怪了,其他所有的输出都搞砸了。谁能告诉我为什么会这样?

【问题讨论】:

    标签: assembly ascii converter division multiplication


    【解决方案1】:

    这需要比您想象的更多的工作。还有几种方法可以做到这一点。基本上你想要的是获取每个小数位的值,然后打印result + 48(48 是 ascii 0)。

    例如,假设您的输入是 15。您想打印 15。你可以通过15 mod 10 获得5。然后将 15 除以 10。结果是 11 mod 10 导致 1。您可以将这些值压入堆栈,直到您的 value mod 10 等于 0。我的组装生锈了,但这应该是一个功能模数:

    modTen:
        push   bp
        mov    bp, sp
        push   bx
        mov    ax, word [bp+4]
        mov    bx, ax
        cwd
        idiv   10
        imul   10
        sub    bx, ax
        mov    ax, bx
        pop    bx
        mov    sp, bp
        pop    bp
        ret
    

    我使用的是 GCC 风格的调用者/被调用者假设,但你可以做任何你想做的事情。接下来,您需要一个包含以下步骤的循环

    push your parameter
    call modTen
    pop your parameter (or increment your SP)
    push your result
    increment a register to keep track of number of digits
    divide your original value by 10
    check if the result is zero. 
        If not, go back to the start of the loop. 
        If so, start popping your values and printing them.
    

    更新: SP 代表堆栈指针。它指向存储在堆栈中的最后一个值。当您push 时,SP 会递减,并且引用寄存器中的值会推送SP 指向的位置。 pop 会将SP 指向的值从堆栈中弹出到一个寄存器中,然后增加SP。 (如果您考虑装入杂志,则将子弹推入,然后将它们弹出。这是先进后出的结构或堆栈)。

    BP 代表基指针并指向一个位置,该位置标记当前函数正在使用的堆栈的起点。例如,在modTen 中,当函数被调用时,它会保存旧函数的基指针,将当前堆栈指针移动到基指针中,然后将其用作附近所有其他值的引用 (就像函数的参数一样)。这样做的预期目的是,当您的函数执行时,它需要堆栈空间来存储变量。当您的堆栈指针四处移动时,您会丢失事物所在的位置(据推测,尽管您可以在没有基本指针的情况下完全正常)。

    在汇编中编写时,将代码分成函数并设置一些假设很方便,因此当其他人使用您的代码时,或者您在将来重新使用它时,您不需要重新阅读所有内容你的代码让它工作。汇编通常很难理解,因为作者的意图并不明显。 8086 汇编的约定是函数的参数以相反的顺序压入堆栈。然后call用于跳转到函数。 Call 将下一条指令的位置(您的返回地址)推入堆栈。然后被调用的函数(或被调用者)通过压入来保存前一个函数的基指针。然后将SP 复制到BP 中,BP 的值用于引用变量。被调用者还将在使用之前保存除AX 之外的所有已使用寄存器,然后在使用后恢复它们。 AX 用于返回值,因此 调用者 必须在调用之前保存其中的任何内容(如果您想保留它)。当函数正在执行时,您的堆栈将如下所示。

                                  ....
    function's second argument -> XXXX
    function's first argument  -> XXXX
    return address             -> XXXX
    BP points here             -> XXXX
      Also, saved last BP
    some variable              -> XXXX
                                  ....
    SP points here             -> XXXX
      and another variable
                                  ....
    

    很明显,您对 x86 架构不是很熟悉,这在编写 x86 汇编时非常重要。例如,您可能知道也可能不知道 x86 使用段以及指针寄存器来计算地址。随着您在 x86 汇编方面的经验越来越丰富,这可能会让您感到困惑。我强烈建议您查找详细介绍 8086 架构的书籍或在线资源。如果你这样做了,你将做好充分准备长出你的胡须,并像 1980 年那样编写代码。

    此外,如果您使用的是某种 linux 或 unix 环境,那么您已经拥有世界上最好的汇编学习资源。 使用objdump -S a.out 查看已编译可执行文件的程序集。如果您使用 -g 进行编译,那么它将向您显示哪些代码与哪些汇编指令一起使用。很整齐。 (这是假设您正在使用 gcc)。 ` 另外,我从来没有用过,但是这个用户有一个source 用于gcc 编译8086 兼容16 位指令的补丁。

    祝你好运

    【讨论】:

    • 是的,那里的逻辑很棒!但我似乎无法理解如何做到这一点。我知道你可以通过将其修改 10 并获取其余数以获取数字然后打印它来获得 15。但我无法理解如何做到这一点的方法。抱歉,我真的是一个组装新手,我仍然不明白那些 sp bp 和 push 和 pop 是什么意思。现在我只是将答案除以 10,然后得到余数等,并设法分离并打印数字..就像我输入15,结果是“;”我使用了 mod 和东西,得到了“59”,这是正确的,但如果我的数字高于 20,它就会出错
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多