I have a procedure to print a multidigit nbr,
I don't want to have to pass in the Acc since it makes no sense really but I don't get how to pass a register to StdOut.
Also where is StdOut defined? I can't find a good reference and/or tutorial for masm32.
printnbr proc Acc : sdword
mov ebx, 10 ; Divide by this
xor ecx, ecx ; digit-counter
pushloop:
xor edx, edx ;
div ebx ; quotient in eax, remainder in edx
push edx ; store it for later
inc ecx
cmp eax, 0
jnz pushloop
poploop:
pop eax ; get digit back
add al, '0' ; convert to character
mov Acc, eax
push ecx ; StdOut modifies ecx so save it to pop it back 2 rows down.
invoke StdOut, addr Acc
pop ecx
loop poploop
ret
printnbr endp
invoke StdOut, eax
or invoke StdOut, [eax]
Depends on what you need.
I have tried both eax and [eax] and both assembles and links fine but crashes at runtime.
; #########################################################################
.386
.model flat, stdcall
option casemap :none
; #########################################################################
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\libs\math\math.lib
; #########################################################################
fac PROTO N : DWORD
fib PROTO N : DWORD
.data
S db "Result is: ", 0
N sdword 5
Acc sdword 0
;IntArray dword 8 dup (?)
.code
start:
;; invoke fac, 5
;; invoke fib, 12
mov eax, 10
utoa:
mov ebx, 10 ; we'll divide by this
xor ecx, ecx ; use as digit-counter
pushloop:
xor edx, edx ;
div ebx ; quotient in eax, remainder in edx
push edx ; store it for later
inc ecx
cmp eax, 0
jnz pushloop
poploop:
pop eax ; get digit back
add al, '0' ; convert to character
;; mov Acc, eax
push ecx
invoke StdOut, [eax] ;; addr Acc
pop ecx
loop poploop
ret
;; mov Acc, 1
;; add Acc, 48
;; invoke StdOut, addr Acc
;; invoke StdOut, addr Acc
invoke ExitProcess, 0
end start
StdOut is a routine in masm32lib. It looks like-
StdOut proc lpszText:DWORD
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD
LOCAL sl :DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax
invoke StrLen,lpszText
mov sl, eax
invoke WriteFile,hOutPut,lpszText,sl,ADDR bWritten,NULL
mov eax, bWritten
ret
StdOut endp
It is designed to print one or more characters to the standard output console.
This routine and most all the routines that write to output expect the address of a string, so you can't just pass the character in eax.
You could define a local variable rather than adding a proc parameter, store the character in that, and call StdOut with the address of the local variable.
eg.
printnbr proc
local Acc
mov ebx, 10 ; Divide by this
. etc
does the same thing.
You could make a modified StdOut that would accept a character in eax and use that instead, eg.
StdOutx proc inchar
LOCAL hOutPut :DWORD
LOCAL bWritten :DWORD
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOutPut, eax
invoke WriteFile,hOutPut,addr inchar,1,ADDR bWritten,NULL
mov eax, bWritten
ret
StdOutx endp
printnbr proc
mov ebx, 10 ; Divide by this
xor ecx, ecx ; digit-counter
pushloop:
xor edx, edx ;
div ebx ; quotient in eax, remainder in edx
push edx ; store it for later
inc ecx
cmp eax, 0
jnz pushloop
poploop:
pop eax ; get digit back
add al, '0' ; convert to character
push ecx ; StdOut modifies ecx so save it to pop it back 2 rows down.
invoke StdOutx, eax
pop ecx
loop poploop
ret
printnbr endp
I notice you didn't save ebx as is standard practice.
You could use esi rather than ecx and you would not have to worry about StdOut changing it-
e.g. printnbr proc uses ebx esi
I don't know of any windows api that takes one character as input and prints it to the console, but there is probably one hidden somewhere.
QuoteAlso where is StdOut defined? I can't find a good reference and/or tutorial for masm32.
StdOut is a member of masm32.lib and here is where you can find the source code of this function :
\masm32\m32lib\stdout.asm
MASM32 Library Reference :
\masm32\help
rotten,
StdOut expects a pointer to a zero-terminated string. Your code works OK for this because the three most-significant bytes of the remainder will always be zero, and dwords are stored in memory with the least-significant byte at the lowest address (so in other words, the converted character will be followed in memory by a zero byte). You could avoid using Acc with something like this:
poploop:
pop eax ; get digit back
add al, '0' ; convert to character
;mov Acc, eax
push ecx ; StdOut modifies ecx so save it to pop it back 2 rows down.
;invoke StdOut, addr Acc
push eax ; put eax on stack
invoke StdOut, esp ; esp always points to last value pushed
pop eax ; remove pushed value from stack
pop ecx
loop poploop
But IMO your current method is better because it's easier to understand.