我今天开始学习汇编,我编写了一个程序来打印数字的阶乘。它对于个位数的阶乘非常有效,但是当我对其进行一些更改以处理更大的数字时,我开始在阶乘的开头出现一个意想不到的字符。阶乘开头的字符对于每个数字都会发生变化。
这是我的代码:
section .data
msg db 'Enter a number: ',0 ;content of user prompt
lenmsg equ $ - msg ;length of user prompt
disp db 'Factorial: ',0 ;content of output
lendisp equ $ - disp ;length of output
newline db 0xa ;newline char
section .bss
num resb 3 ;2 bytes for number , 1 byte for newline
fac resb 12 ;12 bytes for Factorial
section .text
global _start
_start:
;Display User Prompt
mov edx,lenmsg ;number of bytes to write
mov ecx,msg ;content to write
mov ebx,1 ;file descriptor : stdout
mov eax,4 ;system call : sys_write
int 0x80 ;call kernel
;Accept User Input
mov edx,2 ;number of bytes to read
mov ecx,num ;input stored at num
mov ebx,0 ;file descriptor : stdin
mov eax,3 ;system call : sys_read
int 0x80 ;call kernel
mov byte [num+eax-1],0 ;replace newline with null
;Calculate Factorial
movzx eax, byte [num] ;move num to eax, replace leading places with zeroes
sub eax,'0' ;convert ascii to integer
mov ecx,eax ;transfer to ecx , acts as counter
mov eax,1 ;eax takes value of 1, acts as factorial
cmp ecx,0 ;checks if input is 0
jz output ;if input is 0 it goes directly to output
loop:
mul ecx ;multiply
dec ecx ;decrease counter
jnz loop ;if ecx > 0, loop through
output:
;Convert integer to ASCII
mov ebx,fac+11 ;fac is 12 bytes long, fac+11 goes to end of fac
mov byte [ebx],0 ;add null character
xor ecx,ecx ;clear ecx , acts as counter
convert:
xor edx,edx ;clear edx
mov ecx,10 ;divisor
div ecx ;eax /= ecx, edx contains remainder
add dl,'0' ;last 8 bits of edx contains the digit, convert it into a string by adding ascii number of '0'
dec ebx ;move buffer pointer, we save each digit in a different position
mov [ebx],dl ;store character
inc ecx ;ecx works as a general purpose register AND as a counter at the SAME TIME
test eax,eax ;works like bitwise AND
mov [fac],bl ;store result to fac
jnz convert ;if eax != 0, continue looping
;Display Output Message
mov edx,lendisp ;length of output message
mov ecx,disp ;content of output message
mov ebx,1 ;file descriptor : stdout
mov eax,4 ;system call : sys_write
int 0x80 ;call kernel
;Display Factorial
mov edx,ecx ;length of factorial
mov ecx,fac ;content of factorial
mov ebx,1 ;file descriptor : stdout
mov eax,4 ;system call : sys_write
int 0x80 ;call kernel
;Display Newline
mov edx,1 ;length of newline
mov ecx,newline ;content of newline
mov ebx,1 ;file descriptor : stdout
mov eax,4 ;system call : sys_write
int 0x80 ;call kernel
;Exit Code
mov eax,1 ;system call : sys_exit
int 0x80 ;call kernel
这是我得到的输出:
输入数字:2
阶乘:-2
输入数字:3
阶乘:-6
输入数字:4
阶乘: ,24
输入数字:5
阶乘:+120
输入数字:6
阶乘:+720
输入数字:7
阶乘:*5040
输入数字:8
阶乘:)40320
输入数字:9
阶乘:(362880
我在 Ubuntu 24.04.1 LTS 上使用 NASM 版本 2.16.01。
请帮助我。
当您准备好显示阶乘时,当前首先会显示一条消息。这破坏了您认为在转换循环期间在 ECX 中建立的计数。
转换循环还有
一些无意义的内容!
;Display Output Message
mov edx, lendisp
mov ecx, disp
mov ebx, 1
mov eax, 4
int 0x80
;Convert integer to ASCII
mov ecx, fac+12 ; Better build address in ECX, ready for output
xor ebx, ebx ; Count in any temp register
mov edi, 10 ; CONST throughout the loop
convert:
xor edx, edx
div edi
add dl,'0'
dec ecx
mov [ecx], dl
inc ebx
test eax, eax
jnz convert
;Display Factorial
mov edx, ebx
mov ebx, 1
mov eax, 4
int 0x80
看到,通过将消息放在转换之前,您可以更自由地使用寄存器。
mov eax, 1
cmp ecx, eax
jbe output
loop:
imul eax, ecx ; Non-widening is better (you don't use EDX)
dec ecx
cmp ecx, 1
jne loop
output: