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 edx
和 pop 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 指定被调用例程保留哪些寄存器以及可以更改哪些寄存器。
我是 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 edx
和 pop 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 指定被调用例程保留哪些寄存器以及可以更改哪些寄存器。