我几天前刚刚开始学习装配,似乎我已经打了一个坚固的墙。我有这个问题,我必须在程序集中创建一个程序,接受整数输入(celcius)并将其转换为华氏度。
这是我的代码:
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,这将导致&#34 ;;"在ascii中是59。 转换ascii我需要帮助;到十进制,当我输入更多 超过2个数字,它表示溢出除法。我该如何解决?提前谢谢!
编辑:我最近添加了转换代码。现在有点工作,但如果我输入超过" 20"在输入中它输出错误。我使用了Alden的想法(非常感谢!)修改答案并分别转换和打印。我现在还在努力做这件事,我还在挠头哈哈。这么多错误大声笑。
再次编辑:这太奇怪了。我的程序只能转换以5结尾的数字。它只能正确转换5,15,25和35.这太奇怪了所有其他人都搞砸了输出。谁能告诉我为什么会这样?
答案 0 :(得分:1)
这比你想象的要多一点。还有几种方法可以做到这一点。基本上你想要的是得到每个小数位的值,然后打印result + 48
(48是ascii 0)。
例如,假设您的输入为15.您想要打印1
和5
。您可以通过5
获取15 mod 10
。然后将15除以10.这个结果是1
。 1 mod 10
会产生1
。您可以将这些值压入堆栈,直到value mod 10
等于零。我的组装生锈了,但这应该是一个功能模块:
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
中,当调用该函数时,它会保存旧函数的基指针,将当前堆栈指针移动到基本指针中,然后将其用作附近所有其他值的引用。 by(就像函数的参数一样)。这样做的目的是,当您的函数执行时,它需要堆栈空间来存储变量。当你的堆栈指针移动时,你会失去事物处所在的位置(据说,尽管你可以通过基本指针完全正常)。
在汇编时,可以方便地将代码分成函数并设置一些假设,以便在其他人使用您的代码时,或者您将来重新使用它时,您将无需重新读取所有代码。你的代码让它工作。大会通常很难理解,因为作者打算做什么并不明显。使用8086程序集的约定是函数的参数以相反的顺序被压入堆栈。然后使用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位指令。
好运