我对Assembler很陌生,我只需要完成我的学校任务,但我有一个小问题。程序应在输入时读取两位数字,并计算所有大于第一个数字的数字。问题是寄存器EDX(用于计算更大的数字)增量最多为1,但不高于它。你能提出一些不太复杂的事情吗?
%include "asm_io.inc"
segment .data
char_prompt db "Insert numbers: ",0
comma db ", ",0
out_msg1 db "Count of numbers greater than the first number(",0
out_msg2 db "): ",0
segment .text
global _asm_main
_asm_main:
enter 0,0
pusha
mov EAX, char_prompt
call print_string
first_number:
call read_char
cmp EAX, 32
je first_number
cmp EAX, 10
je after_input
cmp EAX, 13
je after_input
sub EAX, 48 ; turn ASCII code into a digit
mov EBX, 10
mul EBX ; multiply decimal point by 10
mov EBX, EAX
call read_char
sub EAX, 48 ; turn ASCII code into a digit
add EAX, EBX ; add decimals and units together
mov ECX, EAX
call print_int
mov EAX, comma
call print_string
jmp main_loop
main_loop:
call read_char
cmp EAX, 32
je main_loop
cmp EAX, 10
je after_input
cmp EAX, 13
je after_input
sub EAX, 48 ; turn ASCII code into a digit
mov EBX, 10
mul EBX ; multiply decimal point by 10
mov EBX, EAX
call read_char
sub EAX, 48 ; turn ASCII code into a digit
add EAX, EBX ; add decimals and units together
mov EBX, EAX
call print_int
mov EAX, comma
call print_string
mov EAX, EBX
cmp EAX, ECX ; compare current number to first number
ja increase
jmp main_loop
increase:
inc EDX ; increase count of greater numbers <-- PROBLEM HERE
jmp main_loop
after_input:
mov EAX, out_msg1
call print_string
mov EAX, ECX
call print_int
mov EAX, out_msg2
call print_string
mov EAX, EDX
call print_int
jmp finish
finish:
popa ; terminate program
mov EAX, 0
mov EBX, 0
mov ECX, 0
mov EDX, 0
leave
ret
输出的格式仍然非常原始,一旦我解决了这个主要问题,我就会纠正它。
我也试过
add EDX, 1
而不是
inc EDX
但结果相同。
如果有人帮助我,我将非常感激。
答案 0 :(得分:1)
隐藏参数
问题是x86指令集中的某些指令采用隐藏参数。
mul
糟透了
在您的情况下,它是MUL
指令。
mul ebx
用词不当。它确实是:
mul edx:eax, eax, ebx
^^^^^^^ ^^^ ^^^
||| | +-------- Source 1
||| +------------- Source 2
+++------------------- Destination
即mul ebx
转换为:EDX:EAX = EAX * EBX
。
因此,而不是1个操作数mul
需要3。
您可以在以下位置查看:http://www.felixcloutier.com/x86/MUL.html
这样做的原因是两个32位操作数的乘法可以产生64位数。为了便于此,处理器将结果存储在两个寄存器中。低32位进入EAX
,高32位进入EDX
。
在你的情况下,你是乘以小数字,所以EDX
总是最终为零,这巧妙地解释了为什么EDX永远不会超过一个。
- 你继续将它重置为零。
解决方案是使用另一个寄存器作为计数器,例如EDI
。
但要小心,因为EDI也被用作string instructions中的隐藏参数
如果您正在使用这些内容,那么您需要push edx
之前pop edx
之后mul
或imul
使用imul
。
imul eax,ebx
规则
该指令允许您指定显式操作数。
eax = eax * ebx
此说明将转换为以下伪代码:imul
imul ebx,eax,10
执行一个带符号的乘法(!),这可能适合您的用例,但需要注意一些事项。它也会丢弃溢出位,但您不必在代码中担心这一点。
<强>最后强>
如果你将时间乘以常数,你就可以做到:
edx
将3条指令压缩为1,并避免碰撞pusha/popa
。
关于通话约定
如果你调用的那些例程中的任何一个修改了任何寄存器,那么你也会遇到麻烦。我假设您的例程始终使用{{1}},但如果任何寄存器被子例程破坏,您需要在代码中对其进行补偿。
如果调用库函数,它们将遵循calling convention,它指定被调用例程保留哪些寄存器以及可以更改哪些寄存器。