CSC231 Printing & Inputting Decimal Numbers in Assembly

From dftwiki3
Revision as of 07:32, 5 October 2015 by Thiebaut (talk | contribs)
Jump to: navigation, search

--D. Thiebaut (talk) 16:16, 20 September 2014 (EDT)





This page presents two program that will display a byte, word, and double word in decimal. This code will work on 32-bit and 64-bit Linux machines.
There are 2 programs:

  • testLib.asm, the test program
  • 231Lib.asm, the library containing I/O functions


To assemble, link, and run the programs, execute the following commands:


nasm -f elf 231Lib.asm
nasm -f elf testLib.asm
ld -melf_i386 testLib.o 231Lib.o -o testLib
./testLib
x = 127
y = 10000
z = 100000 
> 1234567
z = 1234567
 


231Lib.asm


;;; 231Lib.asm
;;; A simple I/O library for CSC231.
;;; will be expanded as needed.
;;;
;;; D. Thiebaut
;;; Adapted from Swarnali Ahmed's 2002 program: mytools.inc
;;; http://cs.smith.edu/dftwiki
;;;
;;; Contains several functions for performing simple I/O of
;;; data.
;;; _printDec: function that prints an integer on the screen
;;; _printString: function that prints a string on the screen
;;; _println: moves the cursor to the next line on the screen
;;; _getInput: gets a possibly signed integer from the keyboard
;;;
;;; Version 2.  Sept 22, 2014. 
;;;      - updated _getInput to get only 1 char at at time.
;;;      - now works with pipes       
;;; Version 1.  Sept 21, 2014.
;;; 
%assign SYS_EXIT        1
%assign SYS_WRITE       4
%assign STDOUT          1
        
global  _printDec
global  _printString
global  _println
global  _getInput
        
        section         .text
        
     
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
;;; ; getInput: gets a numerical input from the keyboard.
;;; ;           returns the resulting number in eax (32 bits).
;;; ;           recognize - as the first character of
;;; ;           negative numbers.  Does not skip whitespace
;;; ;           at the beginning.  Stops on first not decimal
;;; ;           character encountered.
;;; ;
;;; ; NO REGISTERS MODIFIED, except eax
;;; ;
;;; ; Example of call:
;;; ;
;;; ;          call  getInput
;;; ;          mov   dword[x], eax ; put integer in x
;;; ;
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
_getInput:
                section .bss
buffer          resb    120
intg            resd    1
isneg           resb    1
        
                section .text
                pushad                  ; save all registers

                mov     esi, buffer     ; eci --> buffer
                mov     edi, 0          ; edi = counter of chars
.loop1:        
                mov     eax, 03         ; input
                mov     ebx, 0          ; stdin
                mov     ecx, esi        ; where to put the next char
                mov     edx, 1          ; one char at a time
                int     0x80            ; get the input into buffer

                cmp     byte[esi], 0    ; EOF?
                je      .parse
                cmp     byte[esi], 10   ; line feed?
                je      .parse
                inc     esi             ; point to next cell 
                inc     edi             ; increment char counter
                jmp     .loop1

.parse:
                mov     esi, buffer     ; esi --> buffer
                mov     ecx, edi        ; loop for all chars received
                mov     dword[intg], 0
                mov     byte[isneg], 0

.negativ:      
                cmp     byte[esi], '-'
                jne     .loop
                inc     byte[isneg]
        
.loop:          mov     ebx, 0
                mov     bl, byte[esi]

                ;; stop on line feed
                cmp     bl, 10          ; line feed?
                je      .done

                ;; stop on non-digit characters
                cmp     bl, '0'
                jb      .done
                cmp     bl, '9'
                ja      .done
        
                ;; bl is a digit...  multiply .int by 10 first
                mov     edx, 10
                mov     eax, dword[intg]
                mul     edx             ; edx:eax <-- 10 * .int
                
                ;; add int version of char
                sub     bl, '0'
                add     eax, ebx
                mov     dword[intg], eax
                inc     esi
                loop    .loop
.done:
                ;; if negative, make eax neg
                cmp     byte[isneg], 0
                je      .return
                neg     eax
                mov     dword [intg], eax
        
                ;; restore registers and return result in eax
.return:

                popad
                mov     eax, [intg]
                ret     
        
        
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
;;; ; _printDec: takes the double word in eax and prints it
;;; ; to STDOUT in decimal.
;;; ;
;;; ; Examples:
;;; ; print a byte variable
;;; ;          mov     eax, 0
;;; ;          mov     al, byte[someVar]
;;; ;          call    _printDec
;;; ;
;;; ; print a word variable
;;; ;          mov     eax
;;; ;          mov     ax, word[otherVar]
;;; ;          call    _printDec
;;; ;
;;; ; print a double-word variable
;;; ;          mov     eax, dword[thirdVar]
;;; ;          call    _printDec
;;; ;
;;; ; print register edx in decimal
;;; ;
;;; ;          mov     eax, edx
;;; ;          call    _printDec
;;; ;
;;; ;REGISTERS MODIFIED: NONE
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------

_printDec:
;;; saves all the registers so that they are not changed by the function

                section         .bss
.decstr         resb            10
.ct1            resd            1  ; to keep track of the size of the string

                section .text
                pushad                          ; save all registers

                mov             dword[.ct1],0   ; assume initially 0
                mov             edi,.decstr     ; edi points to decstring
                add             edi,9           ; moved to the last element of string
                xor             edx,edx         ; clear edx for 64-bit division
.whileNotZero:
                mov             ebx,10          ; get ready to divide by 10
                div             ebx             ; divide by 10
                add             edx,'0'         ; converts to ascii char
                mov             byte[edi],dl    ; put it in sring
                dec             edi             ; mov to next char in string
                inc             dword[.ct1]     ; increment char counter
                xor             edx,edx         ; clear edx
                cmp             eax,0           ; is remainder of division 0?
                jne             .whileNotZero   ; no, keep on looping

                inc             edi             ; conversion, finish, bring edi
                mov             ecx, edi        ; back to beg of string. make ecx
                mov             edx, [.ct1]     ; point to it, and edx gets # chars
                mov             eax, SYS_WRITE  ; and print!
                mov             ebx, STDOUT
                int             0x80

                popad                           ; restore all registers

                ret
        
;;; ; ------------------------------------------------------------
;;; ; _printString:        prints a string whose address is in
;;; ;                      ecx, and whose total number of chars
;;; ;                      is in edx.
;;; ; Examples:
;;; ; Assume a string labeled msg, containing "Hello World!",
;;; ; and a constant MSGLEN equal to 12.  To print this string:
;;; ;
;;; ;           mov        ecx, msg
;;; ;           mov        edx, MSGLEN
;;; ;           call       _printSTring
;;; ;
;;; ; REGISTERS MODIFIED:  NONE
;;; ; ------------------------------------------------------------

;;; ;save eax and ebx so that it is not modified by the function

_printString:
                push            eax
                push            ebx
        
                mov             eax,SYS_WRITE
                mov             ebx,STDOUT
                int             0x80

                pop             ebx
                pop             eax
                ret

;;; ; ------------------------------------------------------------
;;; ; _println             put the cursor on the next line.
;;; ;
;;; ; Example:
;;; ;           call      _println
;;; ;
;;; ; REGISTERS MODIFIED:  NONE
;;; ; ------------------------------------------------------------
_println:  
                section .data
.nl             db              10
        
                section .text
                push            ecx
                push            edx
        
                mov             ecx, .nl
                mov             edx, 1
                call            _printString

                pop             edx
                pop             ecx
                ret


testLib.asm


;;; -----------------------------------------------------
;;; testLib.asm
;;; D. Thiebaut
;;; Simple demo program for simple I/O operations
;;;
;;; To assemble, link and run:
;;; nasm -f elf 231Lib.asm
;;; nasm -f elf testLib.asm
;;; ld -melf_i386 testLib.o 231Lib.o -o testLib
;;; ./testLib
;;;
;;; Example of output, when user enters 1001 at the keyboard:
;;; x = 127
;;; y = 10000
;;; z = 100000
;;; > 1001
;;; z = 1001
;;; -----------------------------------------------------

;;; extern functions that will be linked to this program
;;; contained in 231Lib.asm

extern  _printDec
extern  _printString
extern  _println
extern  _getInput
        
;;; -----------------------------------------------------
;;; data section
;;; -----------------------------------------------------
        section .data
x       db      127
y       dw      10000
z       dd      100000
msgX    db      "x = "
msgY    db      "y = "
msgZ    db      "z = "
prompt  db      "> "
        
;;; -----------------------------------------------------
;;; code section
;;; -----------------------------------------------------
        section .text
        global _start
_start:

;;; display x
        mov             ecx, msgX
        mov             edx, 4
        call            _printString
        mov             eax, 0
        mov             al, byte[x]
        call            _printDec
        call            _println

;;; display y
        mov             ecx, msgY
        mov             edx, 4
        call            _printString
        mov             eax, 0
        mov             ax, word[y]
        call            _printDec
        call            _println

;;; display z
        mov             ecx, msgZ
        mov             edx, 4
        call            _printString
        mov             eax, dword[z]
        call            _printDec
        call            _println

;;; get number from user
        mov             ecx, prompt
        mov             edx, 2
        call            _printString
        call            _getInput
        mov             dword[z], eax
;;; display it back
        mov             ecx, msgZ
        mov             edx, 4
        call            _printString
        mov             eax, dword[z]
        call            _printDec
        call            _println

;;; ; exit
        mov     ebx, 0
        mov     eax, 1
        int     0x80