NASM - how to print a number using int 080h?
If you want to print a number in ASCII string, you have to convert the number to a string.
This will work for nonnegative number:
; dummy to tell the program the end of data
push -1
; set the number to convert
xor eax, eax
mov al, [lett]
; convert the number to string (sequence of character)
convert_loop:
xor edx, edx
mov ebx, 10
div ebx
add edx, '0'
push edx
test eax, eax
jnz convert_loop
; print the converted string
print_loop:
cmp dword [esp], 0
jl print_loop_end ; break when -1 is found
mov eax, 4
mov ebx, 1
mov ecx, esp
mov edx, 1
int 080h
pop eax ; move on next character
jmp print_loop
print_loop_end:
pop eax ; clean -1
UPDATE: Another version without using push / pop
instruction:
section .bss
; 32-bit unsigned integer won't be longer than 10 digits in decimal
strtonum_convert_buffer resb 12
section .text
; dummy to tell the program the end of data
mov ecx, strtonum_convert_buffer
mov byte [ecx], 0
; set the number to convert
xor eax, eax
mov al, [lett]
; convert the number to string (sequence of character)
convert_loop:
xor edx, edx
mov ebx, 10
div ebx
add edx, '0'
inc ecx
mov [ecx], dl
test eax, eax
jnz convert_loop
; print the converted string
print_loop:
cmp byte [ecx], 0
je print_loop_end ; break when 0 is found
mov eax, 4
mov ebx, 1
; there is already the pointer to the character on ecx
mov edx, 1
int 080h
dec ecx ; move on next character
jmp print_loop
print_loop_end:
linux nasm assembly find number of digits held in variable
For numbers in the range 0..100
, I'd just compare at the boundaries, with pseudo-assembler like:
mov ax, [counter]
mov cx, 3 ; default length
cmp ax, 100 ; >= 100, use 3
bge done
dec cx ; set length to 2
cmp val, 10 ; >= 10, use 2
bge done
dec cx ; set length to 1
done:
; cx now holds the digit count.
That will actually handle up to 999 but you could also add more condition checks before the 100 one if you wanted to expand the range.
linux nasm assembly dwtoa
Well, ya gotta write it... or borrow one somebody's already written. The latter is easier (the C library has functions like this, and it's easy to call from asm), but the former is more "fun". (if you like that kind of thing - hey, some people do crossword puzzles)
The div
instruction is very slow. There's a better way to do it based on multiplying by the reciprocal and "back multiplying". It's quite complicated. We'll wait for div
. :)
div ebx
If we had arranged to have our number, say 1234, in eax
and 10 in ebx
, we would now have 123 in eax
and 4 in edx
(ebx
remains unchanged). Actually, we'd want to have 0 in edx
before the div
...
xor edx, edx
div ebx
As you know, we can convert the number 4 to the character '4' by adding the character '0' (or 48 decimal or 30h). Now we've got something we can print! But we're not quite ready to print it yet - we're getting the digits backwards. There are several ways to deal with this. I think the simplest is to push
'em on the stack and pop
'em off in the correct order. Another way is to go ahead and put 'em in the buffer backwards and do a "string reverse" at the end. Another way is to start at the "end" of the buffer and work toward the front (decrement your index into the buffer after each character instead of incrementing it). This can mean that you're not quite at the beginning of the buffer when you run out of digits. We can use that to our advantage - right justified numbers look good if you're going to print 'em in a column. You could fill with leading zeros, too (the character '0', not the number 0) if you think that looks good (I don't).
In any case, we've got '4' stashed away safely. Loop back and div
again (making edx
zero first!). Now we've got 12 in eax
and 3 in edx
. Do something with the 3 and go back to div
again. 1 in eax
and 2 in edx
. Again, and eax
is zero (edx
is 1) - at that point we're done! We can skip the last div
if we compare eax
to 9 - if it's less, we can get our final (first to be printed) digit from al
instead of dl
. Simpler to do it the same way every time...
; mov eax, the number
; mov edi, the buffer (at least resb 10, please)
; call dwtoa
; mov edx, eax ; count
; mov ecx, buffer
; print it
dwtoa:
xor ecx, ecx ; for a counter
mov ebx, 10
pushloop:
xor edx, edx ; or mov edx, 0
div ebx
add edx, '0'
push edx
inc ecx ; count it
test eax, eax ; or cmp eax, 0
jnz pushloop
mov eax, ecx ; we'll return the count in eax
poploop:
pop edx
mov [edi], dl
inc edi
loop poploop
ret
That's off the top of my head (not cut-and-pasted), and may have errors. It's pretty sloppy - trashes registers that C would like preserved - doesn't return a zero-terminated string as C would like... but we're not using C so we don't care! :)
Feel free to improve it to your taste, or try a different method.
Unless you've got one, you'll want a "atoi" (or "atodw" to use the same naming convention), to convert the text the user enters to a number. Same idea, but we subtract '0' from the character, multiply the "result so far" by ten, and add in the new digit... until done.
;-------------------
; atoi - converts string to (unsigned!) integer
; expects: buffer in edx
; returns: number in eax
atoi:
xor eax, eax ; clear "result"
.top:
movzx ecx, byte [edx]
inc edx
cmp ecx, byte 0
jz .done
cmp ecx, byte 10
jz .done
cmp ecx, byte '0'
jb .invalid
cmp ecx, byte '9'
ja .invalid
; 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
.invalid:
stc
.done:
ret
;--------------
That one's cut-and-pasted so "should" work. It, too, could be improved. Uses an "interesting" way to multiply by ten and add in the new character converted to a number. At this point, the "work" of your program consists of:add eax, 1
Should give you something to work with, anyway. Have fun! :)
Related Topics
How to Understand "Cmpl $0X0, -0X30(%Rbp)"/"Je ..."
How to Clear All History in Linux/Ubuntu Terminal or Bash Permanently
Find Files in Created Between a Date Range
How to Make Vim Play Typewriter Sound When I Write a Letter
How to Check Syslog in Bash on Linux
Install Zsh Without Root Access
How to Compare Two Tarball's Content
What Does the Mkdir -P Mean in a Script File
Why Is Cpu-Cycles Much Less Than CPU Current Frequency
Diff to Output Only the File Names
How to Extract Files Without Folder Structure Using Tar
How to Hide Wget Output in Linux
What Is the Advantage of Using Supervisord Over Monit
Scp Command Syntax for Copying a Folder from Local MAChine to a Remote Server