News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

MASM newbie questions.

Started by RickyS, June 13, 2009, 01:07:37 AM

Previous topic - Next topic

RickyS

Hey everyone! I'm a high-level programmer that was introduced to assembly via emu8086 in a college course. Since that course, I have been trying to break away from the emulator and get into something more real. Since the course used MASM syntax, I thought MASM32 would be easiest way to make that transition.

Just to get started, I thought I would try to convert all of my old emu8086 console applications into MASM32 console applications. I've been having some problems, and I think they are related to the macros I have been using (but I'm not sure). Take this simple loop program for example:
mov cx, 5
   
newloop:
    print "Hi"
    dec cx
cmp cx, 0
jne newloop

It goes into an infinite loop, repeating "Hi" over and over again. I've tried to get this to work using several different methods. I tried using the loop instruction instead of cmp/jne. I tried using the sub instruction instead of the dec instruction. I tried to debug it by using the print macro to print the contents of cx, but it just caused the program to crash. I even tried pushing cx before the print macro and popping it afterward, thinking that the print macro might be messing with the register. I also tried searching through Google and the documentation for possible causes, but I couldn't find anything.

Another piece of code that I can't get to work is this:
cls
; Get input, store in EAX.
mov eax, sval(input("Enter the temperature to convert: "))

; Calculate whole number part.
sub eax, 32
mov ebx, 5
mul ebx
mov ebx, 9
div ebx

; Print the result.
print "The temperature in celsius is: "
print  sstr$(eax), 46

It just prints 31 as the answer everytime, no matter what the input. I got it to work by pushing eax to the stack before the first print statement and popping it before the last one, but that doesn't seem to work in other parts of the same program.

So, does anyone know what the problem is?

Oh, and sorry in advance if it is just me misusing the print macro or something stupid like that. I'm new to MASM32, so that's my excuse :P.

dedndave

the print macro destroys the contents of cx
so - it never gets to 0

try this

push ecx
print.........
pop ecx

(stick with 32-bit code - 16-bit code is kind of being phased out)

oh - and welcome to MASM32

RickyS

Thanks for the advice about sticking to 32-bit and the information about the print macro. My loops work now!

Is that kind of information about the macros (how they alter the stack and registers) in any of the documentation?

And does the print macro destroy any other registers (like eax or edx)? That would explain some of the other problems I have been having.

raymond

Whenever you use a macro or call a procedure in some external library, it is standard convention that the EAX, ECX and EDX registers are free to trash and may not be preserved. OTOH, you should expect that the EBX, ESI and EDI registers will have been preserved and restored if used (same for the EBP and ESP registers).

If you ever delve in using the FPU for floating point operations, there is no standard convention to preserve those registers. Some of the Windows APIs trash them.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

good info Raymond
what about the direction flag ?

RickyS

Quote from: raymond on June 13, 2009, 02:12:05 AM
Whenever you use a macro or call a procedure in some external library, it is standard convention that the EAX, ECX and EDX registers are free to trash and may not be preserved. OTOH, you should expect that the EBX, ESI and EDI registers will have been preserved and restored if used (same for the EBP and ESP registers).

If you ever delve in using the FPU for floating point operations, there is no standard convention to preserve those registers. Some of the Windows APIs trash them.
Thanks for the info. In emu8086, just about all of the procedures and macros preserve all of the general registers. I guess that makes things easier for newbies, but I can see why it's not standard practice.

raymond

Quotewhat about the direction flag ?
The flag register is not expected to be preserved. As for the direction flag itself, good programming would be to clear that flag as soon as possible after setting it when not needed anymore. Most, if not all, library functions expect that flag to be clear before calling any function (or macro).

If a called function would need to set that flag, it would be cleared before returning. If such a function is called with the flag in the "set" condition, that condition would therefore not be preserved. One should thus expect the direction flag to be preserved only if the flag is clear before calling a function or macro.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

dedndave

ouch - that one hurts
lol
if they need it cleared, they should clear it explicitly
as it happens, that is the way i have always treated it inside my own code
leave it cleared unless i need to go backwards - then i clear it when done
but, that is just so i don't have to worry about my own mistakes
is this convention documented someplace Ray ?

raymond

Quoteis this convention documented someplace Ray ?

I wouldn't be able to confirm that with absolute certainty. However, it may go back to the DOS era where I may have read something about such a requirement. Whether it still applies is a good question with the more modern OS'es. However, I certainly would never expect that direction flag to be set when returning from any library function. And I have never used the cld instruction unless I would have used the std instruction prior to that in any of my programs.
When you assume something, you risk being wrong half the time
http://www.ray.masmcode.com

MichaelW

I can find many Microsoft references to the CRT expecting the direction flag to be clear, for example:

http://msdn.microsoft.com/en-us/library/7td56tzs.aspx

But none for the Windows API functions. I cannot recall any problems with code that assumed the flag was clear.
eschew obfuscation

Mark Jones

Sounds like we're all avoiding STD's... :toothy
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

dedndave

well - i looked at some code for an API function
i didn't see pushfd
i see varying statements about the registers - lol
i see people say ebx, esi,. edi, and ebp must be preserved across procedures
that has to mean - procedures that use locals or that are intended to be used with compilers
what they don't say is, if it is your own proc and not made available to any other process, you can do what you like
everyplace i see mention of these registers, they are talking about compilers
i thought this was a masm forum - lol
as for the DF, i am surprised to see that the crt requires it to be clear
not a problem - but that seems strange
all i know is, i will continue to set it myself
as an example....

start:  push    ecx
        invoke  SomeApiFunction
        pop     ecx
        cld
        lodsb
        loop   start

up til now, i have assumed nothing about the DF and inserted cld in the loop
i will continue doing so

MichaelW

#12
The problems occur in callbacks, where Windows is expecting EBX, ESI, EDI, and EBP to be preserved. If in addition to EBP the callback preserves EBX, ESI, and EDI, then it doesn't matter what the procedures it calls do with these registers, but the convention is to preserve these registers in all procedures, so there is no dependence on code outside the procedure to preserve the registers, and so that any caller can depend on these registers being preserved.
eschew obfuscation