在汇编程序x86中递增寄存器不会超过1

时间:2017-04-03 01:35:01

标签: assembly x86 increment x86-16 cpu-registers

我对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

但结果相同。

如果有人帮助我,我将非常感激。

1 个答案:

答案 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之后mulimul使用imul

imul eax,ebx规则
该指令允许您指定显式操作数。

eax = eax * ebx

此说明将转换为以下伪代码:imul imul ebx,eax,10 执行一个带符号的乘法(!),这可能适合您的用例,但需要注意一些事项。它也会丢弃溢出位,但您不必在代码中担心这一点。

<强>最后
如果你将时间乘以常数,你就可以做到:

edx

将3条指令压缩为1,并避免碰撞pusha/popa

关于通话约定
如果你调用的那些例程中的任何一个修改了任何寄存器,那么你也会遇到麻烦。我假设您的例程始终使用{{1}},但如果任何寄存器被子例程破坏,您需要在代码中对其进行补偿。

如果调用库函数,它们将遵循calling convention,它指定被调用例程保留哪些寄存器以及可以更改哪些寄存器。