CSC231 Printing & Inputting Decimal Numbers in Assembly
--D. Thiebaut (talk) 16:16, 20 September 2014 (EDT)
Contents
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 231Lib ./testLib x = 127 y = 10000 z = 100000 > 1234567 z = 1234567
231Lib.asm
;;; A simple I/O library for CSC231.
;;; will be expanded as needed
;;; D. Thiebaut
;;; Taken 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: returns the integer (possibly signed) entered at the keyboard
%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.
;;; ; recognize - as the first character of
;;; ; negative numbers. Does not skip whitespace
;;; ; at the begining. Stops on first not decimal
;;; ; digit encountered.
;;; ;
;;; ; NO REGISTERS MODIFIED, except eax
;;; ; Example:
;;; ;
;;; ; call getInput
;;; ; mov dword[x], eax ; put integer in x
;;; ;
;;; ;------------------------------------------------------
;;; ;------------------------------------------------------
_getInput:
section .bss
buffer resb 12
intg resd 1
isneg resb 1
section .text
pushad ; save all registers
mov eax, 03 ; input
mov ebx, 0 ; stdin
mov ecx, buffer ; where to put the input
mov edx, 12 ; max # of chars
int 0x80 ; get the input into buffer
mov esi, buffer
mov ecx, eax ; loop for all bytes
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, 0
;;; ; 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 231Lib
;;; ./testLib
;;; -----------------------------------------------------
;;; 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