Sure you can do it without the bloated C calls! Whether it's more "difficult" or more "fun" is a matter of opinion... (no, there is no way to read an integer from the keyboard)
; Compiling this code for 32-bit use:
; nasm -f elf file.asm
; ld -melf_i386 -o file file.o
;
global _start
;~.~. Definitions for readability: ~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.
%define SYS_EXIT 1
%define SYS_READ 3
%define SYS_WRITE 4
%define STDIN 0
%define STDOUT 1
%define STDERR 2
%define LF 10
%define MAX_NUMBER 16
SECTION .data
format: db "The number is: " ; not really used
SECTION .bss
buffer resb MAX_NUMBER
number resd 1
SECTION .text
_start:
nop
GetInput:
mov EAX, SYS_READ
mov EBX, STDIN
mov ECX, buffer
mov edx, MAX_NUMBER
int 80H
cmp byte [ecx + eax - 1], LF
jz Calculate
; pesky user has tried to overflow us!
; flush the buffer!
sub esp, 4 ; temporary "buffer"
flush:
mov eax, SYS_READ
; ebx still okay
mov ecx, esp ; buffer is on the stack
mov edx, 1
int 80h
cmp byte [ecx], LF
jnz flush
add esp, 4 ; "free" our "buffer"
Calculate:
push buffer
call atoi
add esp, 4
mov [number], eax ; not really used...
add eax, 1 ; just to do something
mov esi, buffer
mov ecx, MAX_NUMBER
call binasc
mov byte [esi + ecx], LF
inc ecx
Display:
mov edx, ecx
mov ecx, esi
mov ebx, STDOUT
mov eax, SYS_WRITE
int 80h
exit:
mov eax, SYS_EXIT
xor ebx, ebx
int 80h
;--------------------
;--------------------
atoi:
push ebx
mov edx, [esp + 8] ; pointer to string
xor ebx, ebx ; assume not negative
cmp byte [edx], '-'
jnz notneg
inc ebx ; indicate negative
inc edx ; move past the '-'
notneg:
xor eax, eax ; clear "result"
.top:
movzx ecx, byte [edx]
inc edx
cmp ecx, byte '0'
jb .done
cmp ecx, byte '9'
ja .done
; we have a valid character - multiply
; result-so-far by 10, subtract '0'
; from the character to convert it to
; a number, and add it to result.
lea eax, [eax + eax * 4]
lea eax, [eax * 2 + ecx - '0']
jmp short .top
.done:
test ebx, ebx
jz notminus
neg eax
notminus:
pop ebx
ret
;------------------------
;--------------------
; from Chuck Crayne - RIP, Chuck.
;convert binary to ascii
;call with eax = signed binary number
; esi = address of output string
; ecx = length of output string
;returns esi = 1st printed digit
; ecx = no of digits printed (includes sign if any)
; other registers preserved
binasc: push edx
push ebx
push edi
push eax
mov edi,esi ;save start of string
ba1: mov byte [esi],' ' ;fill string with blanks
inc esi
loop ba1
mov ebx,10 ;initialize divisor
or eax,eax ;value negative?
jns ba2 ;no problem
neg eax ;make it positive
ba2: xor edx,edx ;clear high part of dividend
div ebx ;divide by 10
add dl,'0' ;convert to ascii digit
dec esi ;step backwards through buffer
mov [esi],dl ;store digit
inc ecx
cmp esi,edi ;out of space
jz ba4 ;yes - quit
or eax,eax ;all digits printed?
jnz ba2 ;no - keep trucking
pop eax ;get original value
or eax,eax ;negative?
jns ba3 ;no - quit
dec esi ;place for sign
mov byte [esi],'-'
inc ecx ;add to char count
ba3: pop edi
pop ebx
pop edx
ret
ba4: pop eax
jmp ba3
;-------------------
Bryant's version, stripped, 2712 bytes. My version, stripped, 600 bytes. Tell me again about "overhead"?
Best,
Frank