News:

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

Main Menu

MASM high level emulation.

Started by hutch--, April 08, 2017, 02:16:35 AM

Previous topic - Next topic

hutch--

This capacity has been around since MASM6 in 1990 but I have rarely ever seen it used. The capacity to assign and reassign a constant with the "=" sign allows code like the following. It requires a macro which allows you to check the arg count and it does not require a LOCAL variable for the return value as it uses the .DATA? section for a constant instead. The return value is always global in scope within a module but the name can be re-assigned at any time so you don't get the bad habits of allocation a large number of globals and getting naming conflicts.

I have never introduced the technique in the MASM32 SDK because it is a different animal with a different logic but it is highly suitable for making a simplified script style of language that assembles into pure assembler code without any bad habits.


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

    include \masm32\include64\masm64rt.inc

    MsgBox MACRO args:VARARG
      LOCAL acnt,rval
      acnt = argcount(args)
      IF acnt ne 4
        echo ---------------------------------
        echo MsgBox : incorrect argument count
        echo ---------------------------------
        .err <* incorrect argument count *>
      ENDIF
      .data?
        rval dq ?
      .code
      invoke __imp_MessageBoxA,args
      mov rval, rax
      EXITM < rval>
    ENDM

    .code

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

entry_point proc

    call Select_Option

    .if choice == IDYES
      void = MsgBox(0,"You chose YES","Result",MB_OK)
    .else
      void = MsgBox(0,"You chose NO","Result",MB_OK)
    .endif

    .exit

    ret

entry_point endp

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

Select_Option proc

    choice = MsgBox(0,"Choose YES or NO","Choice",MB_YESNO)
    ret

Select_Option endp

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

    end

comment # ------------------------------------------------------------------------------------------

.text:0000000140001000 C8800000                   enter 0x80, 0x0
.text:0000000140001004 4883EC60                   sub rsp, 0x60
.text:0000000140001008 E86D000000                 call sub_14000107a
.text:000000014000100d 48833DAB11000006           cmp qword ptr [0x1400021c0], 6
.text:0000000140001015 752B                       jne 0x140001042
.text:0000000140001017 48C7C100000000             mov rcx, 0x0
.text:000000014000101e 488B1549100000             mov rdx, qword ptr [0x14000206e]
.text:0000000140001025 4C8B055B100000             mov r8, qword ptr [0x140002087]
.text:000000014000102c 49C7C100000000             mov r9, 0x0
.text:0000000140001033 FF1523110000               call qword ptr [MessageBoxA]
.text:0000000140001039 48890570110000             mov qword ptr [0x1400021b0], rax
.text:0000000140001040 EB29                       jmp 0x14000106b
.text:0000000140001042
.text:0000000140001042 0x140001042:
.text:0000000140001042 48C7C100000000             mov rcx, 0x0
.text:0000000140001049 488B154D100000             mov rdx, qword ptr [0x14000209d]
.text:0000000140001050 4C8B0560100000             mov r8, qword ptr [0x1400020b7]
.text:0000000140001057 49C7C100000000             mov r9, 0x0
.text:000000014000105e FF15F8100000               call qword ptr [MessageBoxA]
.text:0000000140001064 4889054D110000             mov qword ptr [0x1400021b8], rax
.text:000000014000106b
.text:000000014000106b 0x14000106b:
.text:000000014000106b 48C7C100000000             mov rcx, 0x0
.text:0000000140001072 FF15D4100000               call qword ptr [ExitProcess]
.text:0000000140001078 C9                         leave
.text:0000000140001079 C3                         ret
; --------------------------------------------------------------------------
; sub_14000107a
; --------------------------------------------------------------------------
sub_14000107a   proc
.text:000000014000107a C8800000                   enter 0x80, 0x0
.text:000000014000107e 4883EC60                   sub rsp, 0x60
.text:0000000140001082 48C7C100000000             mov rcx, 0x0
.text:0000000140001089 488B1541100000             mov rdx, qword ptr [0x1400020d1]
.text:0000000140001090 4C8B0550100000             mov r8, qword ptr [0x1400020e7]
.text:0000000140001097 49C7C104000000             mov r9, 4
.text:000000014000109e FF15B8100000               call qword ptr [MessageBoxA]
.text:00000001400010a4 48890515110000             mov qword ptr [0x1400021c0], rax
.text:00000001400010ab C9                         leave
.text:00000001400010ac C3                         ret
sub_14000107a   endp

-------------------------------------------------------------------------------------------------- #

jj2007

Interesting technique - I never thought of that ::)

But it's tricky. Attached the 32-bit version; see in particular the line that finishes with ???

hutch--

Question : Why the hell is the executable 301k ?

TWell

#3
debug-info included.

porebase.exe /SPLIT can split it.

jj2007

Quote from: hutch-- on April 08, 2017, 12:48:00 PM
Question : Why the hell is the executable 301k ?

As Tim already noted, it has debug info. Here is the same without - 2048 bytes.
But if you run the "fat" version with Olly, you can see what it actually does, and why choosing YES fails :bgrin:

ragdog

Really nice Macro and idea  :t

hutch--

Funny enough on both the original and your modified version, the choice of YES works correctly. I don't claim to understand what your mods do or why they are done. I am inclined to trust a disassembler, that is why I posted the disassembly.

jj2007

Quote from: hutch-- on April 08, 2017, 11:16:38 PM
Funny enough on both the original and your modified version, the choice of YES works correctly. I don't claim to understand what your mods do or why they are done.

  varCnt=varCnt+1
  tmp$ CATSTR <MsgBoxRet>, %varCnt


Not a big deal, it just uses global names instead of local ones, so that you can identify them in the debugger as MsgBoxRet1, MsgBoxRet2 etc.

The problem with void returning 0 or 1 instead of always 1 aka IDOK is that the first void is not the same as the second one. It may have the same name, but it is a different variable (and that is what I call tricky ;)):
    .if choice == IDYES
inc eax ; marker for debugging
void = MsgBox(0,"You chose YES","Result",MB_OK)
    .else
dec eax ; marker for debugging
void = MsgBox(0,"You chose NO","Result",MB_OK)
    .endif
    print str$(void)


00401089        ³.  CC                      int3
0040108A        ³.  833D 98324000 06        cmp dword ptr [MsgBoxRet3], 6
00401091        ³. 75 1B                   jne short 004010AE
00401093        ³.  40                      inc eax
00401094        ³.  6A 00                   push 0                                   ; ÚType = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
00401096        ³.  68 8E304000             push offset 0040308E                     ; ³Caption = "Result"
0040109B        ³.  68 80304000             push offset 00403080                     ; ³Text = "You chose YES"
004010A0        ³.  6A 00                   push 0                                   ; ³hOwner = NULL
004010A2        ³.  E8 BB010000             call MessageBoxA                         ; ÀUSER32.MessageBoxA
004010A7        ³.  A3 90324000             mov [MsgBoxRet1], eax
004010AC        ³. EB 19                   jmp short 004010C7
004010AE        ³>  48                      dec eax
004010AF        ³.  6A 00                   push 0                                   ; ÚType = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
004010B1        ³.  68 8E304000             push offset 0040308E                     ; ³Caption = "Result"
004010B6        ³.  68 B8304000             push offset 004030B8                     ; ³Text = "You chose NO"
004010BB        ³.  6A 00                   push 0                                   ; ³hOwner = NULL
004010BD        ³.  E8 A0010000             call MessageBoxA                         ; ÀUSER32.MessageBoxA
004010C2        ³.  A3 94324000             mov [MsgBoxRet2], eax
004010C7        ³>  68 ED304000             push offset ??003F                       ; ÚArg2 = HighLevelEmu.??003F
004010CC        ³.  FF35 94324000           push dword ptr [MsgBoxRet2]              ; ³Arg1 = 0
004010D2        ³.  E8 49000000             call dwtoa                               ; ÀHighLevelEmu.dwtoa
004010D7        ³.  68 ED304000             push offset ??003F                       ; ÚArg1 = HighLevelEmu.??003F
004010DC        ³.  E8 A7000000             call StdOut                              ; ÀHighLevelEmu.StdOut


You are printing only MsgBoxRet2 - and that's why clicking NO yields IDOK, while clicking Yes loads MsgBoxRet1 but you still print MsgBoxRet2 :(

hutch--

Its a problem with your assumptions with the debugger, if you look at the macro, each time it is called it provides a unique .DATA? section address which you assign to any name you like using the standard MASM "=" assignment operator. When you re-use a name that has previously been assigned to an earlier address, you lose the address of the earlier assignment. If you want each one to remain unique, you must use unique names for each one.

As you would be familiar, the name "void" usually means that return value is not needed and in the context of the original example without the modified debug code, the YES or NO API calls do not need a return value as the MB style is MB_OK. The original example does exactly what it was designed to do, present a simple MessageBox, test its return value and use the same simple MessageBox to indicate which choice was taken.

The original dis-assembly said it all.

HSE

JJ:
What ml 32? I'm trying with ML14 but not success.
Equations in Assembly: SmplMath

hutch--

This works fine in 32 bit.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;                       Build with "Assemble & Link"
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    MsgBox MACRO args:VARARG
      LOCAL acnt,rval
      acnt = argcount(args)
      IF acnt ne 4
        echo ---------------------------------
        echo MsgBox : incorrect argument count
        echo ---------------------------------
        .err <* incorrect argument count *>
      ENDIF
      .data?
        rval dd ?
      .code
      fn MessageBox,args
      mov rval, eax
      EXITM < rval>
    ENDM

    .code

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

    call main

    exit

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

main proc

    choice = MsgBox(0,"This is a test","Title",MB_YESNO)

    .if choice == IDYES
      void = MsgBox(0,"You selected YES","Result",MB_OK)
    .else
      void = MsgBox(0,"You selected NO","Result",MB_OK)
    .endif

    ret

main endp

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

end start


The DumpPE RESULT

00401000                    start:
00401000 E807000000             call    fn_0040100C
00401005 6A00                   push    0
00401007 E85A000000             call    jmp_ExitProcess

0040100C                    fn_0040100C:                ; Xref 00401000
0040100C 6A04                   push    4
0040100E 680F304000             push    offset off_0040300F   ; 'Title',000h
00401013 6800304000             push    offset off_00403000   ; 'This is a test',000h
00401018 6A00                   push    0
0040101A E841000000             call    jmp_MessageBoxA
0040101F A350304000             mov     [off_00403050],eax
00401024 833D5030400006         cmp     dword ptr [off_00403050],6
0040102B 751A                   jnz     loc_00401047
0040102D 6A00                   push    0
0040102F 6826304000             push    offset off_00403026   ; 'Result',000h
00401034 6815304000             push    offset off_00403015   ; 'You selected YES',000h
00401039 6A00                   push    0
0040103B E820000000             call    jmp_MessageBoxA
00401040 A354304000             mov     [off_00403054],eax
00401045 EB18                   jmp     loc_0040105F

00401047                    loc_00401047:               ; Xref 0040102B
00401047 6A00                   push    0
00401049 683D304000             push    offset off_0040303D   ; 'Result',000h
0040104E 682D304000             push    offset off_0040302D   ; 'You selected NO',000h
00401053 6A00                   push    0
00401055 E806000000             call    jmp_MessageBoxA
0040105A A358304000             mov     [off_00403058],eax
0040105F                    loc_0040105F:               ; Xref 00401045
0040105F C3                     ret


You eill note that this code in 32 bit does not need the argument count as ML already checks against a prototype.

    MsgBox MACRO args:VARARG
      LOCAL acnt,rval
      acnt = argcount(args)
;       IF acnt ne 4
;         echo ---------------------------------
;         echo MsgBox : incorrect argument count
;         echo ---------------------------------
;         .err <* incorrect argument count *>
;       ENDIF
      .data?
        rval dd ?
      .code
      fn MessageBox,args
      mov rval, eax
      EXITM < rval>
    ENDM

HSE

Equations in Assembly: SmplMath

jj2007

Quote from: HSE on April 09, 2017, 01:36:32 AM
JJ:
What ml 32? I'm trying with ML14 but not success.

Sorry for that. Here is a version that assembles also with ML 6.14. Here are the most important lines:;   int 3
    .if choice == IDYES
inc eax ; marker for debugging
result = MsgBox(0,chr$("You chose YES"), chr$("Result"), MB_YESNOCANCEL)
    .else
dec eax ; marker for debugging
result = MsgBox(0, chr$("You chose NO"), chr$("Result"), MB_YESNOCANCEL)
    .endif
    print "in round #2, "
    .if result==IDYES
  print "you clicked YES"
    .elseif result==IDNO
  print "you clicked NO"

HSE

Thank JJ! I was wandering what kind of ML can accept quoted text in Invoke :t
Equations in Assembly: SmplMath

hutch--

32 bit ML cannot directly use quoted text, it requires a macro that gets the text address. the "fn" notation in MASM32 provides the quoted text support, the method that JJ uses is a macro for each text instance.