linux nasm程序集打印从零到100的所有数字

我正在编写一个程序来打印出从零到100的所有数字。我这样做的唯一原因是testing打印出多个数字。

我遇到的问题是我的程序只打印出数字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

更新:

编辑包括“打印”标签

这是我的功能打印标准输出数字。 在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 

干杯!

您需要将数字转换为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之类的东西,而不是硬编码的数字。 使代码更加自我记录。

编辑:它本身不是一个“错误”,但只是偶然的读者访问一个计数器和strlen作为一个字节变量和其他地方比较内容与32位变量误导…

add BYTE[ecx], NUL

这可能会增加 NUL终结者到ecx ,但我想它应该追加终结者。 这可能发生在[ecx+1]

无论如何,变量和指针的处理是非常非常规的在你的代码…

首先:内核函数“输出”的东西,假设ecx包含一个字符串的地址。 没有一个字符串分配在任何地方。 如果字符串恰好适合保留在计数器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零不需要终止字符串,因为据我所知,它被赋予打印功能

    然后可以给真正的指针字符串为

     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. 

为了产生一个好看的结果,必须还要添加换行符 。 这可以单独处理,也可以附加到原始字符串,并确保它们不会被写入,因此可以在所有情况下使用它们。