Converting Numbers for Display


So far, we have been unable to display any number stored to the user, except by the extremely limitted means of passing it through exit codes. In this section, we will discuss converting positive numbers into strings for display.

The function will be called integer2string, and it will take two parameters - an integer to convert and a string buffer filled with null characters (zeroes). The buffer will be assumed to be big enough to store the entire number as a string.(at least 11 characters long, to include a trailing null character).

Remember that the way that we see numbers is in base 10. Therefore, to access the individual decimal digits of a number, we need to be dividing by 10 and displaying the remainder for each digit. Therefore, the process will look like this:

  • Divide the number by ten

  • The remainder is the current digit. Convert it to a character and store it.

  • We are finished if the quotient is zero.

  • Otherwise, take the quotient and the next location in the buffer and repeat the process.

The only problem is that since this process deals with the one's place first, it will leave the number backwards. Therefore, we will have to finish by reversing the characters. We will do this by storing the characters on the stack as we compute them. This way, as we pop them back off to fill in the buffer, it will be in the reverse order that we pushed them on.

The code for the function should be put in a file called integer-to-string.s and should be entered as follows:

 #PURPOSE:  Convert an integer number to a decimal string #          for display # #INPUT:    A buffer large enough to hold the largest #          possible number #          An integer to convert # #OUTPUT:   The buffer will be overwritten with the #          decimal string # #Variables: # # %ecx will hold the count of characters processed # %eax will hold the current value # %edi will hold the base (10) #  .equ ST_VALUE, 8  .equ ST_BUFFER, 12  .globl integer2string  .type integer2string, @function integer2string:  #Normal function beginning  pushl %ebp  movl  %esp, %ebp  #Current character count  movl  $0, %ecx  #Move the value into position  movl  ST_VALUE(%ebp), %eax  #When we divide by 10, the 10  #must be in a register or memory location  movl  $10, %edi conversion_loop:  #Division is actually performed on the  #combined %edx:%eax register, so first  #clear out %edx  movl  $0, %edx  #Divide %edx:%eax (which are implied) by 10.  #Store the quotient in %eax and the remainder  #in %edx (both of which are implied).  divl  %edi  #Quotient is in the right place.  %edx has  #the remainder, which now needs to be converted  #into a number.  So, %edx has a number that is  #0 through 9.  You could also interpret this as  #an index on the ASCII table starting from the  #character '0'.  The ascii code for '0' plus zero  #is still the ascii code for '0'.  The ascii code  #for '0' plus 1 is the ascii code for the  #character '1'.  Therefore, the following  #instruction will give us the character for the  #number stored in %edx  addl  $'0', %edx  #Now we will take this value and push it on the  #stack.  This way, when we are done, we can just  #pop off the characters one-by-one and they will  #be in the right order.  Note that we are pushing  #the whole register, but we only need the byte  #in %dl (the last byte of the %edx register) for  #the character.  pushl %edx  #Increment the digit count  incl  %ecx  #Check to see if %eax is zero yet, go to next  #step if so.  cmpl  $0, %eax  je    end_conversion_loop  #%eax already has its new value.  jmp conversion_loop end_conversion_loop:  #The string is now on the stack, if we pop it  #off a character at a time we can copy it into  #the buffer and be done.  #Get the pointer to the buffer in %edx  movl ST_BUFFER(%ebp), %edx copy_reversing_loop:  #We pushed a whole register, but we only need  #the last byte.  So we are going to pop off to  #the entire %eax register, but then only move the  #small part (%al) into the character string.  popl  %eax  movb  %al, (%edx)  #Decreasing %ecx so we know when we are finished  decl  %ecx  #Increasing %edx so that it will be pointing to  #the next byte  incl  %edx  #Check to see if we are finished  cmpl  $0, %ecx  #If so, jump to the end of the function  je    end_copy_reversing_loop  #Otherwise, repeat the loop  jmp   copy_reversing_loop end_copy_reversing_loop:  #Done copying.  Now write a null byte and return  movb  $0, (%edx)  movl  %ebp, %esp  popl  %ebp  ret 

To show this used in a full program, use the following code, along with the count_chars and write_newline functions written about in previous chapters. The code should be in a file called conversion-program.s.

  .include "linux.s"  .section .data  #This is where it will be stored tmp_buffer:  .ascii "\0\0\0\0\0\0\0\0\0\0\0"  .section .text  .globl _start _start:  movl  %esp, %ebp  #Storage for the result  pushl $tmp_buffer  #Number to convert  pushl $824  call  integer2string  addl  $8, %esp  #Get the character count for our system call  pushl $tmp_buffer  call  count_chars  addl  $4, %esp  #The count goes in %edx for SYS_WRITE  movl  %eax, %edx  #Make the system call  movl  $SYS_ WRITE, %eax  movl  $STDOUT, %ebx  movl  $tmp_buffer, %ecx  int   $LINUX_SYSCALL  #Write a carriage return  pushl $STDOUT  call  write_newline  #Exit  movl  $SYS_EXIT, %eax  movl  $0, %ebx  int   $LINUX_SYSCALL 

To build the program, issue the following commands:

 as integer-to-string.s -o integer-to-number.o as count-chars.s -o count-chars.o as write-newline.s -o write-newline.o as conversion-program.s -o conversion-program.o ld integer-to-number.o count-chars.o write-newline.o conversion- program.o -o conversion-program 

To run just type ./conversion-program and the output should say 824.




Programming from the Ground Up
Programming from the Ground Up
ISBN: 0975283847
EAN: 2147483647
Year: 2006
Pages: 137

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net