Reputation: 1082
I hate asking such basic questions. It makes it look like I am being lazy! But I have spent hours looking over documentation, and for whatever reason, I can't get my head spun around straight on this small point.
I want to print the character "4" to the screen. I can do it as a string, but not from an ascii value.
Here is the working code:
include c:\masm32\include\masm32rt.inc
.data
num4 db "4", 10,0
.code
start:
invoke StdOut, addr num4
inkey
invoke ExitProcess, 0
end start
I just wanted to take a baby step from there and print ascii character 52 (which is "4"). Here's my best attempt so far:
include c:\masm32\include\masm32rt.inc
.data
.code
start:
myvar db 52
invoke StdOut, myvar
inkey
invoke ExitProcess, 0
end start
It assembles and links without trouble, but then crashes when I run it. I know that it doesn't have the 0 character at the end, but invoke StdOut, myvar,0
has too many arguments for StdOut.
My eventual goal is to be able to print a multiple digit number, as described by Alexey Frunze here:
x86 assembly (masm32) - how to split multi-digit data into individual characters
But since I am having so much trouble with syntax, I am taking baby steps. I found this, but it doesn't explain how to do the add 48 part syntactically:
x86 assembly - how to show the integer 2, not the second ASCII character
Please help me get past these opening hurdles, and thank you!
Upvotes: 1
Views: 7590
Reputation: 14409
First, myvar db 52
is on the wrong place. When the program starts, the computer comes to db 52
and treats that as an instruction. Second, the 0 value (don't say character) is not an argument for StdOut
and has to be at the end of the data. StdOut
needs as argument a pointer to a zero-terminated string. You cannot give it a direct value, the function would take that as pointer nevertheless. BTW: Consider that StdOut
is a function of MASM32 and not a function of the Windows kernel. Your program should look like:
include c:\masm32\include\masm32rt.inc
.data
myvar db 52, 0
.code
start:
invoke StdOut, ADDR myvar
inkey
invoke ExitProcess, 0
end start
You have first to build a string before outputting it with 'StdOut'. If you don't have a string but a number, you have to convert it to a string (keywords for Google: "assembly convert integer to ascii"). The trick is to repeatedly divide the number by 10 and store the remainder. Another trick is to use a MASM32-macro.
INCLUDELIB C:\masm32\lib\masm32.lib
INCLUDE C:\masm32\include\masm32rt.inc
.DATA
decimalstr db 16 DUP (0)
myvar db 52
.CODE
start PROC
movzx eax, myvar ; Load an 8-bit-byte into a 32-bit-register
lea edi, decimalstr ; Load the address of decimalstr
call EAX_to_DEC
invoke StdOut, addr decimalstr
movzx eax, myvar
printf ("\nAnd the lazy MASM32 way: %u\n",eax)
invoke ExitProcess, 0
start ENDP
EAX_to_DEC PROC ; ARG: EDI pointer to string buffer
mov ebx, 10 ; Divisor = 10
xor ecx, ecx ; ECX=0 (digit counter)
@@: ; First Loop: store the remainders
xor edx, edx
div ebx ; EDX:EAX / EBX = EAX remainder EDX
push dx ; push the digit in DL (LIFO)
add cl,1 ; = inc cl (digit counter)
or eax, eax ; AX == 0?
jnz @B ; no: once more (jump to the first @@ above)
@@: ; Second loop: load the remainders in reversed order
pop ax ; get back pushed digits
or al, 00110000b ; to ASCII
stosb ; Store AL to [EDI] (EDI is a pointer to a buffer)
loop @B ; until there are no digits left
mov byte ptr [edi], 0 ; ASCIIZ terminator (0)
ret ; RET: EDI pointer to ASCIIZ-string
EAX_to_DEC ENDP
END start
Also take a look here.
Upvotes: 7