Daniel
Daniel

Reputation: 318

Assembly coding with masm32

In assembly coding, working with masm32.

How can i put a value into a variable, that is not defiened at the .data segment, but by the LOCAL decleration?
thous:

.486                                    
.model flat, stdcall                    
option casemap :none                    

include \masm32\include\windows.inc     
include \masm32\macros\macros.asm       

include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib


.data  

.code  

start:  

call main  
exit  

main proc  

LOCAL dewit:DWORD

mov dewit, 0
print dewit  

ret  

main endp  

end start

I tried something like this:

Mov dewit, 0  

It didnt work. However, this code:

Mov dewit, input("enter a number")  

Did put a value into it.

Anybody?

** the LOCAL decleration can only be in a procedure

Upvotes: 0

Views: 1834

Answers (2)

Michael Petch
Michael Petch

Reputation: 47603

Since you are using MASM32 If you are trying to print out a 32-bit value try doing it this way with str$:

print str$(dewit)

This converts the 32-bit value at the memory location dewit into a string, and that string is printed on the console. This also work for an immediate value as well:

print str$(100)

And a register:

print str$(eax)

You can use $ustr as well if you wish to print the unsigned value.

These macros are described in the High Level Macro help that comes with MASM32 SDK

Upvotes: 0

Neitsa
Neitsa

Reputation: 8176

You could have found this with a debugger. Here is the beginning of the code viewed from a debugger:

CPU Disasm
Address   Command                                  Comments
00401000  CALL 0040100C                            ; call main
00401005  PUSH 0                                   ; /ExitCode = 0
00401007  CALL <JMP.&kernel32.ExitProcess>         ; \KERNEL32.ExitProcess
0040100C  PUSH EBP                                 ; main
0040100D  MOV EBP,ESP
0040100F  ADD ESP,-4
00401012  MOV DWORD PTR SS:[LOCAL.1],0             ; dewit = 0
00401019  PUSH DWORD PTR SS:[LOCAL.1]              ; /Arg1 => 0
0040101C  CALL 00401024                            ; print
00401021  LEAVE
00401022  RETN

So print is called (remember, print is a macro, so its expanded once compiled). Remeber you pushed 0 to print:

CPU Disasm
Address   Command                                  Comments
00401024  PUSH EBP                                 ; print (guessed Arg1)
00401025  MOV EBP,ESP
00401027  ADD ESP,-0C
0040102A  PUSH -0B                                 ; /StdHandle = STD_OUTPUT_HANDLE
0040102C  CALL <JMP.&kernel32.GetStdHandle>        ; \KERNEL32.GetStdHandle
00401031  MOV DWORD PTR SS:[LOCAL.1],EAX
00401034  PUSH DWORD PTR SS:[Arg1]                 ; /Arg1 => [Arg1]  *** push 0 ***
00401037  CALL 00401060                            ; \so.00401060

See at line 0x00401034, 0 is pushed as an argument for a call.

Let's see the code:

CPU Disasm
Address   Command                                  Comments
00401060  MOV EAX,DWORD PTR SS:[Arg1]              ; eax = 0
00401064  LEA EDX,[EAX+3]
00401067  PUSH EBP
00401068  PUSH EDI
00401069  MOV EBP,80808080
0040106E  /MOV EDI,DWORD PTR DS:[EAX]              ; trying to dereference [0]... 

The code is trying to read at address 0 (aka NULL pointer bug), which is a big no no.

Looking at print macro in macros.asm, it seems that this macro doesn't do any formatting, you should then use printf.

Your code fixed (you need msvcrt.inc and msvcrt.lib for printf macro, which is still defined in macros.asm):

.486                                    
.model flat, stdcall                    
option casemap :none                    

include \masm32\include\windows.inc  
include \masm32\include\msvcrt.inc  
include \masm32\macros\macros.asm       

include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib


.data  
format_string db "value: %d", 0

.code  

start:  

    call main  
    exit  

main proc  

    LOCAL dewit:DWORD

    mov dewit, 0
    print "printing value: "
    printf ("value: %d", dewit)

    ret  

main endp  

end start

Roughly the same code without any include:

; compile and link with:
; ml test.asm /link /subsystem:console /defaultlib:kernel32.lib /defaultlib:msvcrt.lib

.686
.model flat, stdcall
option casemap: none

ExitProcess PROTO STDCALL :DWORD

externdef _imp__printf:PTR c_msvcrt
crt_printf equ <_imp__printf>

.data
fmt db "value: %d", 0

.code
start:
    call MyFunc
    invoke ExitProcess, 0
    ret


MyFunc proc
    LOCAL foo:DWORD

    mov foo, 42

    push foo
    push offset fmt
    call crt_printf 

    ret
MyFunc endp

end start

I also completely agree with @Jester:

Also, consider not using helper features until you can do it by hand too, and understand what the assembler is doing

Macros are great but unless you can understand what they do and achieve the same by hand, you should refrain from using them. They hide way too much things from beginners' eyes.

Upvotes: 2

Related Questions