我正在编写一个程序来打印从0到100的所有数字。我这样做的唯一原因是测试打印出多位数字。
我遇到的问题是我的程序只打印出数字1和2.我不明白为什么。我的编译器编译正常,没有错误,也没有链接器错误。
这是我的代码:
SECTION .data
len EQU 32
NUL EQU 0
countlen EQU 8
SECTION .bss
counter resb countlen
strlen resb countlen
SECTION .text
GLOBAL _start
_start:
mov BYTE[counter], 1 ; set counter to 1
mov BYTE[strlen], 1 ; set string length counter to 1
mov ecx, counter ; move the counter to ecx
add BYTE[ecx], NUL ; add null terminator to ecx
mov esi, 9 ; move 9 to esi
Length:
cmp [counter], esi ; compare counter to esi
jle Set ; if equal, goto set
inc BYTE[strlen] ; increment the string size
mov eax, 10 ; move 10 to eax
mov ebx, esi ; move esi to ebx
mul ebx ; multiply ebx by esi
add eax, 9 ; add nine to the result
mov esi, eax ; move the result to esi
jmp Length ; jump to Length
Set:
mov esi, 9 ; reset checker
Check:
cmp BYTE[strlen], 1 ; is it one digit?
je Single ; if yes, jump to single
cmp BYTE[strlen], 3 ; is it 100?
je Exit ; if yes, jump to Exit
Print: ; this section deals with multi-digit numbers
cmp BYTE[ecx], NUL ; check if end of string
je Exit ; if equal goto exit
mov eax, 4
mov ebx, 1
mov edx, 1
int 80h ; print number
inc ecx ; point to next digit in number
jmp Print ; jump to Print
Single: ; this section deals with single digit numbers add BYTE[counter], '0' ; convert to ASCII
mov eax, 4
mov ebx, 1
mov ecx, counter
mov edx, countlen
int 80h ; print the digit
jmp Length ; go back
Exit: ; Exit section
mov eax, 1 ; sys_exit
mov ebx, 0 ; return 0
int 80h ; syscall
为什么这样做?此外,我需要更改什么才能使其按预期工作?
提前致谢,
RileyH
更新:
已修改为包含“打印”标签
答案 0 :(得分:2)
这是我在stdout上打印数字的功能。它在AT& T抱歉;)
movl <your decimal here>, %eax
xor %ecx, %ecx # the counter
movl $10, %ebx
loop:
xor %edx, %edx
div %ebx # isolate the last digit, remainder in edx
add $48, %dx # '0' is 48 in ascii, result is the ascii equivalent
shl $8, %dx # move the ascii byte to %dh
pushw %dx # puch ascii code on the stack
inc %esp # point to the ascii byte! (discard %dl)
inc %ecx # count the digits
cmp $0, %eax
jnz loop
movl $4, %eax # write()
movl $1, %ebx # stdout
movl %ecx, %edx # now edx holds the number of digits
movl %esp, %ecx # load the address of string array
int $0x80 # the string array is on top of the stack
干杯!
答案 1 :(得分:0)
add BYTE[ecx], NUL
这可能将 NUL
终止符添加到ecx
,但我认为它应该追加终结符。
这可能发生在[ecx+1]
处。
无论如何,变量和指针的处理在你的代码中非常不寻常......
首先:内核函数'输出'东西,假设ecx包含字符串的地址。在任何地方都没有分配字符串。如果字符串恰好适合保留在counter resb 8
计数器的八个字节,并且计数器将包含字符:'1'
,'3'
,'\0'
,那么该方法将起作用。这揭示了第二件事:printf处理字符串,将单个数字0-9编码为值48-57。空间例如在此ASCII系统中编码为32(十进制),而\ NUL为ascii零。
那么,需要什么:
选项1
将counter
初始化为字符串
counter db '0','0','0','0','0','0','0','1'
length dq 1
Ascii零不需要终止字符串,因为据我所知,它是 给予打印功能
然后可以将 real 指针指向字符串
lea ecx, counter // get the address of counter string
add ecx, 7 // this is the last character
也可以将计数器一次增加为一个数字的字符串:
loop:
mov al,[ecx] // assuming ecx still points to last character
inc al
mov [ecx],al
cmp al, '9'
jle string ok
mov al, '0'
mov [ecx],al
dec ecx
jmp loop
ok: // here the counter has been increased correctly
选项2
将计数器增加为32位整数 使用以下算法一次将整数转换为字符串一个数字:
digits = 0;
string_ptr = &my_string[32]; // move barely outside the string
do {
last_digit = a % 10 + '0'; // calculate the last digit and convert to ASCII
a = a / 10;
*--string_ptr = last_digit; // write the last digit
digits++; // count the number of digits
} while (a);
// because we predecrement string_ptr, that value also contains the exact
// start of the first character in the printable string. And digits contains the length.
要产生一些好看的结果,必须仍然添加换行。这可以单独处理,也可以追加到原始字符串 - 并确保它们永远不会被覆盖,因此可以在所有情况下使用它们。
答案 2 :(得分:0)
您需要将数字转换为ASCII数字才能打印到终端。现在我不会给你我的dwtoa,这将带来学习的乐趣,但你可以做这样的事情:
sys_exit equ 1
sys_write equ 4
stdout equ 1
SECTION .bss
lpBuffer resb 4
SECTION .text
GLOBAL _start
_start:
xor esi, esi
.NextNum:
call PrintNum
inc esi
cmp esi, 100
jna .NextNum
.Exit:
mov eax, sys_exit
xor ebx, ebx
int 80h
;~ #####################################################################
PrintNum:
push lpBuffer
push esi
call dwtoa
mov edi, lpBuffer
call GetStrlen
inc edx
mov ecx, lpBuffer
mov eax, sys_write
mov ebx, stdout
int 80H
ret
;~ #####################################################################
GetStrlen:
push ebx
xor ecx, ecx
not ecx
xor eax, eax
cld
repne scasb
mov byte [edi - 1], 10
not ecx
pop ebx
lea edx, [ecx - 1]
ret
注意,我使用sys_exit,sys_write,stdout之类的东西,而不是硬编码的数字。使代码更自我记录。