This takes a little more work than you might think. There are also several ways to do this. Essentially what you want is to get the value of each decimal position and then print the result + 48
(48 is ascii 0).
For example, say that your input is 15. You want to print a 1
and a 5
. You can get the 5
by doing 15 mod 10
. Then divide the 15 by 10. This results is a 1
. 1 mod 10
results in 1
. You can push these values onto the stack until your value mod 10
is equal to zero. I am rusty on my assembly, but this should be a functional modulo:
modTen:
push bp
mov bp, sp
push bx
mov ax, word [bp+4]
mov bx, ax
cwd
idiv 10
imul 10
sub bx, ax
mov ax, bx
pop bx
mov sp, bp
pop bp
ret
I am using GCC style caller/callee assumptions, but you can do whatever you want. Next you want a loop with the following steps
push your parameter
call modTen
pop your parameter (or increment your SP)
push your result
increment a register to keep track of number of digits
divide your original value by 10
check if the result is zero.
If not, go back to the start of the loop.
If so, start popping your values and printing them.
UPDATE:
SP
stands for stack pointer. It points to the last value that was stored on the stack. When you push
, the SP
is decremented and the value in the referenced register is pushed onto the location that the SP
is pointing to. pop
will pop the value that SP
points to off the stack into a register and then increment SP
. (If you think about loading a magazine, you push bullets in, and pop them out. It is a first in, last out structure, or a stack).
BP
stands for base pointer and points to a location that marks the beginning point of the stack that your current function is using. For example, in modTen
, when the function is called, it saves the base pointer from the old function, moves the current stack pointer into the base pointer, and then uses that as it's reference for all other values that are near by (like the arguments for the function). The intended purpose of this is that as your function executes, it needs stack space to store variables. When your stack pointer moves around you lose the location of where things are at (supposedly, though you can make due perfectly fine with out a base pointer).
When writing in assembly, it is convenient to separate your code into functions and set some assumptions so when someone else uses your code, or you go back to reuse it in some future time, you won't need to go reread all of your code to get it to work. Assembly is often very difficult to understand because it is not obvious what the writer intended it to do. Convention with 8086 assembly is that the arguments for a function are pushed onto the stack in reverse order. Then call
is used to jump to the function. Call pushes the location of the next instruction (your return address) onto the stack. Then the called function (or callee) saves the base pointer of the previous function by pushing it. Then it copies SP
into BP
and the value of BP
is used to reference variables. The callee will also save all used registers except for AX
before using them, and then restore them afterword. AX
is used for the returned value, so the caller must save whatever was in there before calling (if you want to keep it). While the function is executing your stack will look like this.
....
function's second argument -> XXXX
function's first argument -> XXXX
return address -> XXXX
BP points here -> XXXX
Also, saved last BP
some variable -> XXXX
....
SP points here -> XXXX
and another variable
....
It is apparent to me that you are not very familiar with x86 architecture, which is really important when writing x86 assembly. For example, you may or may not be aware that x86 uses segments as well as your pointer registers to calculate address. As you become more experienced in x86 assembly, this will likely trip you up. I highly recommend finding a book or online sources that give a detailed overview of the 8086 architecture. If you do so, you will be well prepared to grow out your neckbeard and hack together code like its 1980.
Also, if you are using some kind of linux or unix environment, you already have the best assembly learning sources in the world available to you.
Use objdump -S a.out
to view the assembly of a compiled executable. If you compile with -g then it will show you what piece of code goes with what assembly instructions. Very neat. (this is assuming you are using gcc by the way). ` Also, I have never used it, but this user has a source for a patch for gcc to compile 8086 compatible 16bit instructions.
GOOD LUCK