为什么除法后的输出是一个“@”符号?

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。在 diveax 保持 0x10 之后,然后将 0x30 添加到它,使其成为 0x400x40@ 的 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 带来了 DXAX,连接成一个 32 位数字,然后除以 r/m16(= BX 在你的代码)。

通过将DX清零,16位无符号数AX的数量与32位无符号数DX:AX的数量相同。