News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Taking care of the prerequisites to create my first program without VS

Started by RedSkeleton007, February 05, 2016, 06:45:02 PM

Previous topic - Next topic

hutch--

The added 13, 10 gives you a carriage return and a line feed. Much the same as pressing the enter key.

RE: exchanges of values, you will do this on a needs basis, have a good look at both the help files in MASM32 AND the examples and tutorials, this is what they were written for, to help folks learning assembler. If you can get the swing of the addressing mode and some practice using instructions, the rest will come with practice.

RedSkeleton007

And the quest for simple ways of printing register values in the console continues. I've tested the following code (my questions are in the comments as always):

include \masm32\include\masm32rt.inc
.data
val1 DWORD 1000h
val2 DWORD 2000h

.code
start:

    mov eax, val1
    xchg eax, val2
    mov val1, eax ; Wait, if we're removing the value from eax into var1, what's left in eax afterwards?

    ;print   str$(dwVal1),13,10 ; error: INVOKE argument type mismatch (is str$ the problem?)
   
    ;print   ustr$(eax),13,10 ; result was 8192. Why? That can't be in hex.
   
    ;print   str$(eax) ; result was 8192 again. And why did using str$ work this time?

    inkey "We've made it through the operations without errors!" ; yes, we do make it this far and past!
   
  nop ; no operation left to perform

  inkey "End of program."
  exit
end start

dedndave

    mov val1, eax ; Wait, if we're removing the value from eax into var1, what's left in eax afterwards?

    ;print   str$(dwVal1),13,10 ; error: INVOKE argument type mismatch (is str$ the problem?)

    ;print   ustr$(eax),13,10 ; result was 8192. Why? That can't be in hex.

    ;print   str$(eax) ; result was 8192 again. And why did using str$ work this time?


1) the source register is unchanged in MOV
2) dwVal1 is not defined - try val1
3) ustr$ converts to unsigned decimal string - 8192 decimal is 2000h
4) i think str$ is the same as ustr$

...and the masm32 package has a bug with regard to ustr$

http://masm32.com/board/index.php?topic=1811.0

i proposed a fix here, with no disagreements - lol

http://masm32.com/board/index.php?topic=1811.msg33372#msg33372

RedSkeleton007

Quote from: dedndave on March 02, 2016, 09:48:54 PM
2) dwVal1 is not defined - try val1
I still get the same error.

Quote from: dedndave on March 02, 2016, 09:48:54 PM
3) ustr$ converts to unsigned decimal string - 8192 decimal is 2000h
Okay, so how do I get it to print out in hexadecimal? I would prefer to see my output in the same format as my input.

jj2007

Quote from: RedSkeleton007 on March 03, 2016, 05:36:44 AMOkay, so how do I get it to print out in hexadecimal?

include \masm32\include\masm32rt.inc
.code
start:
  print hex$(2000h)
  exit
end start

Always at your service 8)


RedSkeleton007

When I try to print both the value in a register and in a variable at the same time:

include \masm32\include\masm32rt.inc
.data
val1 DWORD 1000h
val2 DWORD 2000h

.code
start:

    mov eax, val1 ; eax should now have 1000h
   
    xchg eax, val2 ; eax should now have 2000h, and val2 should now be 1000h instead of 2000h
   
    mov val1, eax ; val1 should now have 2000h instead of 1000h

    ; val1 and eax should both be 2000h:
    print hex$(val1),13,10 ; result: 00002000
    print hex$(eax),13,10 ; result: 00000002   
   

    inkey "We've made it through the operations without errors!"
   
  nop ; no operation left to perform

  inkey "End of program."
  exit
end start

it prints out two different values. Strangely, the value 00002000 comes out when I only print one of them (from eax or val1). What is going on?

jj2007

Quote from: RedSkeleton007 on March 03, 2016, 08:31:39 AM
it prints out two different values. Strangely, the value 00002000 comes out when I only print one of them (from eax or val1). What is going on?

See here, read the part beginning with "Assembly beginners stumble"...

RedSkeleton007

Quote from: jj2007 on March 03, 2016, 08:56:08 AM
See here, read the part beginning with "Assembly beginners stumble"...

Read. Is it worth my time as a noob to do research on why registers get trashed, or should I just accept that truth and move on?

hutch--

Red,

Its called the "Intel Application Binary Interface" (ABI) and it is how all 32 bit Windows API code is written. If you properly observe the ABI design, you will not have problems with mysterious register overwrites, this is why the system is designed this way. If you go to the help file "ASM Intro Help" and go to the link "Register Preservation Convention" you will see how it works. It looks complicated but is really simple in operation.

MichaelW


include \masm32\include\masm32rt.inc
.data
val1 DWORD 1000h
.code
start:
    mov eax, val1
    print hex$(val1),13,10
    print hex$(eax),13,10
    inkey   
    mov eax, val1
    push  eax
    print hex$(val1),13,10
    pop   eax
    print hex$(eax),13,10
    inkey       
  exit
end start

    hex$ MACRO DDvalue
      LOCAL rvstring
      .data
        rvstring db 12 dup (0)
        align 4
      .code
      invoke dw2hex,DDvalue,ADDR rvstring
      EXITM <ADDR rvstring>
    ENDM

; ########################################################################
;
;               This original module was written by f0dder.
;
;      Part of the code has been optimised by Alexander Yackubtchik
;
; ########################################################################

    .386
    .model flat, stdcall
    option casemap :none   ; case sensitive

    .code

; ########################################################################

; THIS CODE CONTAINS 6 INSTRUCTIONS THAT MODIFY, OR POTENTIALLY MODIFY,
; EAX WITHOUT PRESERVING ITS VALUE, IN PERFECT CONFORMANCE WITH THE ABI.

dw2hex proc source:DWORD, lpBuffer:DWORD

    push esi

    mov edx, lpBuffer
    mov esi, source

    xor eax, eax
    xor ecx, ecx

    mov [edx+8], al         ; put terminator at correct length
    mov cl, 7               ; length of hexstring - 1

  @@:
    mov eax, esi            ; we're going to work on AL
    and al, 00001111b       ; mask out high nibble

    cmp al,10
    sbb al,69h
    das

    mov [edx + ecx], al     ; store the asciihex(AL) in the string
    shr esi, 4              ; next nibble
    dec ecx                 ; decrease counter (one byte less than dec cl :-)
    jns @B                  ; eat them if there's any more

    pop esi

    ret

dw2hex endp

; #########################################################################

end


00001000
00000002
Press any key to continue ...
00001000
00001000
Press any key to continue ...


Well Microsoft, here's another nice mess you've gotten us into.

RedSkeleton007

This means that if you must store values in any of the 3 mentioned registers and then call other procedures, you must preserve any of EAX ECX EDX before you call another procedure and restore them after it has returned.

So how do I get MASM to preserve the values in those three registers? Also, I'm not really sure what "restoring them" means.


The solution is to use LOCAL variables to get the procedure running reliably then selectively replace them with any registers that may not be used in the procedure. With careful register reuse you can reduce the number of LOCAL variables by using registers and produce faster code if you get it right.


I'm assuming that variables are local to the procedure that they're declared and used in. So how do you get MASM to treat variables as global? For example, are val1 and val2 considered global variables in the following code:

include \masm32\include\masm32rt.inc
.data
val1 DWORD 1000h
val2 DWORD 2000h

.code
start:

    mov eax, val1 ; eax should now have 1000h
   
    xchg eax, val2 ; eax should now have 2000h, and val2 should now be 1000h instead of 2000h
   
    mov val1, eax ; val1 should now have 2000h instead of 1000h

   
    print hex$(val1),13,10 ; result: 00002000

    ;What must I do to preserve eax, so that the result stays "00002000"?

    print hex$(eax),13,10 ; result: 00000002   
   

    inkey "We've made it through the operations without errors!"
   
  nop ; no operation left to perform

  inkey "End of program."
  exit
end start

hutch--

push = preserve
pop =restore

Ensure you pop registers in REVERSE order to what you push them in.

Like this


push ebx
push esi
push edi

; run your code here

pop edi
pop esi
pop ebx

hutch--

Red,

Here is a simple test piece that shows how to use the old instruction XCHG. You would not normally write it this way but it is done so you can understand it.


; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL var1  :DWORD
    LOCAL var2  :DWORD

    push esi
    push edi

    mov var1, 12345678
    mov var2, 87654321

    print "Before XCHG",13,10
    print str$(var1)," var1",13,10
    print str$(var2)," var2",13,10,13,10

    mov esi, var1
    mov edi, var2

  ; ***************************

    xchg esi, edi       ; exchange the two registers

  ; ***************************

    mov var1, esi
    mov var2, edi

    print "After XCHG",13,10
    print str$(var1)," var1",13,10
    print str$(var2)," var2",13,10


    pop edi
    pop esi

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

RedSkeleton007

Quote from: hutch-- on March 05, 2016, 12:21:16 AM

main proc

    LOCAL var1  :DWORD
    LOCAL var2  :DWORD ;Why didn't you need to use [b]?[/b] to indicate that the variables are uninitialized?

    push esi ;Why are you pushing a register onto the stack before storing var1 or var2 in it?
    push edi

    mov var1, 12345678
    mov var2, 87654321

    print "Before XCHG",13,10
    print str$(var1)," var1",13,10
    print str$(var2)," var2",13,10,13,10

    mov esi, var1
    mov edi, var2