linux nasm assembly print all numbers from zero to 100

后端 未结 3 1079
深忆病人
深忆病人 2021-01-28 15:23

I am writing a program to print out all the numbers from zero to 100. The only reason I am doing this is to test out printing out multiple digit numbers.

The problem th

相关标签:
3条回答
  • 2021-01-28 15:36

    You need to convert the number to an ASCII digit(s) in order to print to terminal. Now I won't give you my dwtoa, that will take the fun out of learning, but you could do something like this:

    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
    

    Notice, I use things like sys_exit, sys_write, stdout, instead of hard coded numbers. Makes code a bit more self documenting.

    0 讨论(0)
  • 2021-01-28 15:43

    This is my function to print the digits on stdout. It's in AT&T sorry ;)

    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
    

    Cheers!

    0 讨论(0)
  • 2021-01-28 16:00

    EDIT: it's not an "error" per se, but just misdirection for the casual reader to access a counter and strlen as one byte variables and in other places compare the contents to 32-bit variables...

    add BYTE[ecx], NUL

    this perhaps adds NUL terminator to ecx, but I suppose it should append the terminator. That could happen at place [ecx+1].

    Anyway the handling of the variables and pointers is very unconventional in your code...

    First: the kernel functions that 'output' stuff, assume that ecx contains the address of a string. There isn't a string allocated anywhere. If the string would just fit into the eight bytes reserved to counter at counter resb 8, and the counter would contain characters: '1','3','\0' then the approach would work. And this reveals the second thing: printf deals with strings, which encode single digits 0-9 to values 48-57. Space e.g. in this ASCII system encodes to 32 (decimal) while \NUL is ascii zero.

    So, what is needed:

    • option 1
      Initialize your counter to a string

      counter db '0','0','0','0','0','0','0','1'  
      length  dq 1
      

      Ascii zero is not needed to terminate the string, because as I understood, it's given to the print function

      Then one can give the real pointer to the string as

      lea ecx, counter     // get the address of counter string
      add ecx, 7           // this is the last character
      

      Also one can increase the counter as a string one digit at a time:

      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  
      
    • option 2

      Increase the counter as a 32-bit integer Convert the integer to string one digit at a time with the following algorithm:

      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.
      

    To produce some good looking result, one has to still add line feeds. That can be handled separately or just appended to the original string -- and ensure they are never written over, so they can be used in all cases.

    0 讨论(0)
提交回复
热议问题