为什么除法后的输出是一个“@”符号?
Why is the output after division a "@" symbol?
我正在尝试以以下形式输入 3 个间隔数字:4 2 2
将前两位数字相除,然后乘以剩余数字。当我尝试将两个数字(dig1 和 dig2)相除时,我得到一个“@”符号。我怎样才能让它打印出答案(2)?
这是输出的图片(注意 4 2 2 成功输出
section .data
msg db 'Enter three numbers to !',0xa ;our dear string
len equ $ - msg
section .bss
dig1 resb 2
dig2 resb 2
dig3 resb 2
filler resb 1
res resb 1
section .text
global _start
_start:
;dig1 input
mov eax, 3
mov ebx, 0
mov ecx, dig1
mov edx, 2
int 0x80
;dig1 output
mov eax, 4
mov ebx, 1
mov ecx, dig1
mov edx, 2
int 0x80
;dig2 input
mov eax, 3
mov ebx, 0
mov ecx, dig2
mov edx, 2
int 0x80
;dig2 output
mov eax, 4
mov ebx, 1
mov ecx, dig2
mov edx, 2
int 0x80
;dig3 input
mov eax, 3
mov ebx, 0
mov ecx, dig3
mov edx, 2
int 0x80
;dig3 output
mov eax, 4
mov ebx, 1
mov ecx, dig3
mov edx, 2
int 0x80
;divide first digits
mov ax, [dig1]
sub ax, '0'
mov bx, [dig2]
sub bx, '0'
div bx
add ax, '0'
mov [res], ax
sub ax, '0'
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
int 0x80
;System exit
mov eax, 1
mov ebx, 0
int 0x80
就在您执行 div
之前,寄存器是这样的:
$eax : 0x2004
$ebx : 0x2002
$ecx : 0x0804a020 → 0x00000a32 ("2\n"?)
$edx : 0x2
前导 20 来自您与数字一起读入的 space。在 div
、eax
保持 0x10
之后,然后将 0x30
添加到它,使其成为 0x40
。 0x40
是 @
的 ASCII 码。
要解决此问题,您可以单独读取以丢弃 space 并且一次只读取一个字符,或者像您一样读取 space,然后清除在进行数学计算之前,从单词的顶部删除 space。
如果您还没有使用它,那么像 GDB 这样的调试器是至关重要的。获取 GDB,然后可能使用像 GEF 这样的附加组件来稍微清理一下输出。
要在 div
之前得到正确答案,您需要:
- 过滤掉
AX
, 中多余的space个字符
- 过滤掉
BX
中多余的space个字符,
- 归零
DX
及其评论提到了为什么以及如何完成前两个。我将尝试解释为什么需要最后一个。
根据 X86 instruction reference of DIV
,您使用的是 DIV r/m16
版本。 (这里,r/m16
大致意思是either 16-bit register or 16-bit memory contents
,而你使用的是16位寄存器BX
。)它说的是Unsigned divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder
。换句话说,div
带来了 DX
和 AX
,连接成一个 32 位数字,然后除以 r/m16
(= BX
在你的代码)。
通过将DX
清零,16位无符号数AX
的数量与32位无符号数DX:AX
的数量相同。
我正在尝试以以下形式输入 3 个间隔数字:4 2 2
将前两位数字相除,然后乘以剩余数字。当我尝试将两个数字(dig1 和 dig2)相除时,我得到一个“@”符号。我怎样才能让它打印出答案(2)?
这是输出的图片(注意 4 2 2 成功输出
section .data
msg db 'Enter three numbers to !',0xa ;our dear string
len equ $ - msg
section .bss
dig1 resb 2
dig2 resb 2
dig3 resb 2
filler resb 1
res resb 1
section .text
global _start
_start:
;dig1 input
mov eax, 3
mov ebx, 0
mov ecx, dig1
mov edx, 2
int 0x80
;dig1 output
mov eax, 4
mov ebx, 1
mov ecx, dig1
mov edx, 2
int 0x80
;dig2 input
mov eax, 3
mov ebx, 0
mov ecx, dig2
mov edx, 2
int 0x80
;dig2 output
mov eax, 4
mov ebx, 1
mov ecx, dig2
mov edx, 2
int 0x80
;dig3 input
mov eax, 3
mov ebx, 0
mov ecx, dig3
mov edx, 2
int 0x80
;dig3 output
mov eax, 4
mov ebx, 1
mov ecx, dig3
mov edx, 2
int 0x80
;divide first digits
mov ax, [dig1]
sub ax, '0'
mov bx, [dig2]
sub bx, '0'
div bx
add ax, '0'
mov [res], ax
sub ax, '0'
mov eax, 4
mov ebx, 1
mov ecx, res
mov edx, 1
int 0x80
;System exit
mov eax, 1
mov ebx, 0
int 0x80
就在您执行 div
之前,寄存器是这样的:
$eax : 0x2004
$ebx : 0x2002
$ecx : 0x0804a020 → 0x00000a32 ("2\n"?)
$edx : 0x2
前导 20 来自您与数字一起读入的 space。在 div
、eax
保持 0x10
之后,然后将 0x30
添加到它,使其成为 0x40
。 0x40
是 @
的 ASCII 码。
要解决此问题,您可以单独读取以丢弃 space 并且一次只读取一个字符,或者像您一样读取 space,然后清除在进行数学计算之前,从单词的顶部删除 space。
如果您还没有使用它,那么像 GDB 这样的调试器是至关重要的。获取 GDB,然后可能使用像 GEF 这样的附加组件来稍微清理一下输出。
要在 div
之前得到正确答案,您需要:
- 过滤掉
AX
, 中多余的space个字符
- 过滤掉
BX
中多余的space个字符, - 归零
DX
根据 X86 instruction reference of DIV
,您使用的是 DIV r/m16
版本。 (这里,r/m16
大致意思是either 16-bit register or 16-bit memory contents
,而你使用的是16位寄存器BX
。)它说的是Unsigned divide DX:AX by r/m16, with result stored in AX ← Quotient, DX ← Remainder
。换句话说,div
带来了 DX
和 AX
,连接成一个 32 位数字,然后除以 r/m16
(= BX
在你的代码)。
通过将DX
清零,16位无符号数AX
的数量与32位无符号数DX:AX
的数量相同。