Assembler x86 中的递增寄存器不会超过 1 的值

Incrementing register in Assembler x86 doesn't go above value of 1

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

但结果是一样的

如果有人帮助我,我将不胜感激。

隐藏参数
问题在于 x86 指令集中的某些指令采用隐藏参数。

mul糟透了
在您的情况下,它是 MUL 指令。

mul ebx 是用词不当。真的是:

mul edx:eax, eax, ebx
    ^^^^^^^  ^^^  ^^^
      |||     |    +-------- Source 1
      |||     +------------- Source 2
      +++------------------- Destination

mul ebx翻译为:EDX:EAX = EAX * EBX

所以 mul 需要 3 个而不是 1 个操作数。

您可以在以下位置看到:http://www.felixcloutier.com/x86/MUL.html

原因是两个 32 位操作数相乘可以产生 64 位数字。为了促进这一点,处理器将结果存储在两个寄存器中。低 32 位进入 EAX,高 32 位进入 EDX。 在你的情况下,你乘以小数所以 EDX 总是以零结束,这巧妙地解释了为什么 EDX 永远不会超过一。
-你继续将它重置为零-。

解决方案是使用另一个寄存器作为计数器,例如EDI。 但要小心,因为 EDI 在 string instructions.
中也用作隐藏参数 如果您正在使用这些,那么您需要在 mul 指令之前 push edxpop edx 之后,或者使用 imul.

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

imul eax,ebx

该指令将转换为以下伪代码:eax = eax * ebx.
imul 执行 s̲i̲gn̲e̲d̲ m̲u̲l̲t̲i̲pl̲y(!),这可能适合您的用例,但需要注意一些事项。它还会丢弃溢出位,但您无需在代码中担心这一点。

终于
如果你乘以一个常数,你可以这样做:

imul ebx,eax,10  

将 3 条指令压缩为 1 条,避免破坏 edx

关于调用约定
如果您调用的这些例程中的任何一个修改了任何寄存器,您也会 运行 陷入麻烦。我假设您的例程始终使用 pusha/popa,但是如果任何寄存器被子例程破坏,您需要在代码中对此进行补偿。

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