问题描述
好吧,我有一个有限的(只输入一位数的被加数)求和程序,它在将余数保存在堆栈中并在之后打印它们的帮助下打印求和结果。
1 global _start
2 section .data
3 NEW_LINE db 10
4 NEW_LINE_LENGTH equ $-NEW_LINE
5 EXIT_SUCCESS_CODE equ 0
6 STDIN equ 0
7 STDOUT equ 1
8 STDERR equ 2
9 SYSCALL_EXIT equ 1
10 SYSCALL_READ equ 3
11 SYSCALL_WRITE equ 4
12
13 section .bss
14 sum resb 4
15 remainder resb 4
16 buffer resb 120
17
18 section .text
19 print_digit:
20 mov eax,SYSCALL_WRITE ; 4
21 mov ebx,STDOUT ; 1
22 int 80h
23 ret
24 _start:
25 mov esi,buffer ; buffer adress --> ESI
26 again:
27 ; input number:
28 mov eax,SYSCALL_READ ; 3
29 mov ebx,STDIN ; 0
30 mov ecx,esi ; buffer adress --> ecx
31 mov edx,1 ; length
32 int 80h
33 cmp byte [esi],0 ; EOF ?
34 je end_input
35 inc esi ; next byte of buffer memory
36 jmp again
37 end_input:
38 mov esi,buffer ; buffer adress --> ESI
39 xor edi,edi
40 ; EDI will hold sum:
41 loop:
42 cmp byte [esi],0 ; EOF ?
43 je div_preparation
44 cmp byte [esi],10 ; line Feed ?
45 je .next_digit
46 sub byte [esi],48 ; get value of digit
47 add edi,[esi] ; add to summ
48 add byte [esi],48
49 .next_digit:
50 inc esi ; next symbol(?) in buffer memory
51 jmp loop
52 ; EDI holds summ Now
53 div_preparation:
54 mov [sum],edi
55 xor edx,edx
56 xor eax,eax
57 xor ebp,ebp
58 mov al,[sum] ; ??????????????????
59 mov esi,10
60 push_remainder:
61 div esi
62 push edx ; push remainder
63 xor edx,edx
64 inc ebp ; remainders counter
65 test eax,eax ; if the quotient equal to 0 (cmp eax,0)
66 jne push_remainder
67 pop_remainder:
68 xor eax,eax
69 test ebp,ebp ; if remainders counter equals to 0
70 je quit
71 pop eax
72 mov [remainder],eax
73 add byte [remainder],48; get digit
74 mov ecx,remainder
75 mov edx,4
76 call print_digit
77 dec ebp
78 jmp pop_remainder
79 quit:
为什么我在第 58 行使用 EAX
或 AX
寄存器时得到错误的除法结果,但使用 AL
结果是正确的?
解决方法
在这部分代码中:
46 sub byte [esi],48 ; get value of digit
47 add edi,[esi] ; add to summ
看起来意图是在总和中添加一位数,但实际情况并非如此。 add edi,[esi]
与 add edi,dword [esi]
隐含相同,因此实际上以一种有趣的方式将 4 个字符添加到总和中,尽管只打算使用底部的一个,并且其中只有一个是从 ASCII 调整的char 为其等效的数字(顺便说一下,我不太明白您为什么将它们改回 ASCII 字符,但原则上应该没问题,只是多余的)。
只使用结果的低字节有效,因为低字节永远不会被那样“污染”,多余的字符被添加到 eax
的高字节中。
如何解决:确保一次只添加一个字符。例如
movzx eax,byte [esi]
sub eax,48
add edi,eax
如果您愿意,可以将 sub
和 add
合并到 lea
中:
movzx eax,byte [esi]
lea edi,[edi + eax - 48]