News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

progress

Started by drifter, February 28, 2013, 06:26:01 AM

Previous topic - Next topic

drifter

I set up VS2005 for assembler projects - but after checking out Steve's Quick Editor more thourouly, I've decided that's the IDE I prefer for now.  Truely awsome - everything you need is just a click away (cmd prompt,assemble & link,procedure browser,browse masm32 lib,map app procedures,masm32 folder,disassemble exe file,format dumpPE output,create EXE makit.bat - just to mention a few.  The rest I'll discover when I get to them.  kudos!

I've also replaced ml with jwasm.  I'm afraid to leave it behind, but jwasm seems to work perfectly as a replacement - and having such beautiful source code available for it is priceless.  As for it being faster, watching  these things assemble and link is better than porn - I can't wait to start building bigger projects.

So, today's will be to press 'Create New Console Application', then press 'Debug print' - and write a routine that prints the register and flag values.  Hopefully it will work anywhere I place it in code and can be used for a quick check without having to use a debugger.  Then it's on to improve my command line parser until it's uncrashable.

Stan

QuoteI've also replaced ml with jwasm. 
What specifics did you do?  I attempted to swap but hit bumps; it's something on my list.


drifter

on: Feburary 27, 2013 at 10:28:02 AM Stan wrote:
QuoteWhat specifics did you do?  I attempted to swap but hit bumps; it's something on my list.

I did it the easy way - I renamed ml.exe to ml8.exe, and then jwasm.exe to ml.exe (all this in the masm32/bin directory).

progress -> completed the register routine, working on the flags.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;             Build this console app with "MAKEIT.BAT" on the PROJECT menu
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

include \masm32\include\masm32rt.inc

    True                    EQU 1
    False                   EQU 0
    CRLF                    EQU 13,10
    TWOCRLF                 EQU 13,10,13,10
    RegSizeInBytes          EQU  4
    FlagSizeInBytes         EQU  4
   
    Init     PROTO
    Fini     PROTO

    .data?
      value dd ?

    .data
      eaxhex db "eax=",0
      ebxhex db "ebx=",0
      ecxhex db "ecx=",0
      edxhex db "edx=",0
      esihex db "esi=",0
      edihex db "edi=",0
      ebphex db "ebp=",0
      esphex db "esp=",0
      ecshex db "ecx=",0
      eiphex db "eip=",0
      eflhex db "flags=",0

    .code

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

    invoke Init
    call   main
    invoke Fini

    exit

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

main proc

    ;cls

      xor eax,eax      ; testing
      ; mov eax,1      ; testing
     
      ;          <-----state of the registers and flags is measured here----->
     
      pushad
      pushfd

      ;---------------------------------------------------------------------------
     
      print OFFSET eiphex
      print uhex$([esp + ( (RegSizeInBytes * 9) + FlagSizeInBytes )]),CRLF   ; eip

      print OFFSET eaxhex
      print uhex$([esp + ( (RegSizeInBytes * 8) + FlagSizeInBytes )]),CRLF   ; eax

      print OFFSET ecxhex
      print uhex$([esp + ( (RegSizeInBytes * 7) + FlagSizeInBytes )]),CRLF   ; ecx

      print OFFSET edxhex
      print uhex$([esp + ( (RegSizeInBytes * 6) + FlagSizeInBytes )]),CRLF   ; edx

      print OFFSET ebxhex
      print uhex$([esp + ( (RegSizeInBytes * 5) + FlagSizeInBytes )]),CRLF   ; ebx
     
      print OFFSET esphex
      print uhex$([esp + ( (RegSizeInBytes * 4) + FlagSizeInBytes )]),CRLF   ; esp
     
      print OFFSET ebphex
      print uhex$([esp + ( (RegSizeInBytes * 3) + FlagSizeInBytes )]),CRLF   ; ebp
     
      print OFFSET esihex
      print uhex$([esp + ( (RegSizeInBytes * 2) + FlagSizeInBytes )]),CRLF   ; esi
     
      print OFFSET edihex
      print uhex$([esp + ( (RegSizeInBytes * 1) + FlagSizeInBytes )]),CRLF   ; edi

      ;---------------------------------------------------------------------------

      print OFFSET eflhex
      print uhex$([esp + FlagSizeInBytes ]),CRLF                             
      ;flags

      ;---------------------------------------------------------------------------
     

      ;---------------------------------------------------------------------------

      popfd
      popad
     
     return 0

main endp

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

Init proc   

    ; cls
   
    ret

Init endp

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

Fini proc

    ; inkey

    ret

Fini endp

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

end start

jj2007

print uhex$([esp + ( (RegSizeInBytes * 9) + FlagSizeInBytes )]),CRLF   ; eip

Very cute :t

How did you find this one? It's the Campus here, so maybe you should explain how it works ;-)

drifter

Today at 05:48:33 PM jj2007 wrote:
QuoteHow did you find this one? It's the Campus here, so maybe you should explain how it works ;-)

Well, like I mentioned, I started with the 'Debug Print' script which pushes and pops the registers and flags via pushad/pushfd and popfd/popad.  So with these values on the stack - it's just a matter of reading them off in the correct order (they aren't exactly eax, ebx, ecx, etc).

I tried making the code self-explainatory, but I'll add comments before I'm finished.  To calculate a registers position in the stack you mulitiply the register size by it's ordinal position in the stack.  For the registers, you also have to jump over the flag register that was pushed last.

The instruction pointer points to the return address after the program is finished.  That probably won't be of much use if this is a macro and used in a debugging situation.

For the flags - my first thought was to use masks, but I think the left shift is more appropriate.  I'm not sure my loops are coded very efficiently, but it appears to work.  I've only checked the carry flag, but if it's right, the rest should be.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
;             Build this console app with "MAKEIT.BAT" on the PROJECT menu
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

include \masm32\include\masm32rt.inc

    True                    EQU 1
    False                   EQU 0
    CRLF                    EQU 13,10
    TWOCRLF                 EQU 13,10,13,10
    RegSizeInBytes          EQU  4
    FlagSizeInBytes         EQU  4
   
    Init     PROTO
    Fini     PROTO

    .data?
      flags dd ?
     

    .data
      none db True

    .code

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

    invoke Init
    call   main
    invoke Fini

    exit

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

main proc

    ;cls

      xor eax,eax      ; testing
      ; mov eax,1      ; testing
      stc              ; testing
     
      ;       <-----state of the registers and flags is measured here----->
     
      pushad
      pushfd

      ;---------------------------------------------------------------------------

      print "eax="
      print uhex$([esp + ( (RegSizeInBytes * 8) + FlagSizeInBytes )])

      print "   esi="
      print uhex$([esp + ( (RegSizeInBytes * 2) + FlagSizeInBytes )]),CRLF

      print "ebx="
      print uhex$([esp + ( (RegSizeInBytes * 5) + FlagSizeInBytes )])

      print "   edi="
      print uhex$([esp + ( (RegSizeInBytes * 1) + FlagSizeInBytes )]),CRLF


      print "ecx="
      print uhex$([esp + ( (RegSizeInBytes * 7) + FlagSizeInBytes )])
     
      print "   ebp="
      print uhex$([esp + ( (RegSizeInBytes * 3) + FlagSizeInBytes )]),CRLF


      print "edx="
      print uhex$([esp + ( (RegSizeInBytes * 6) + FlagSizeInBytes )])

      print "   esp="
      print uhex$([esp + ( (RegSizeInBytes * 4) + FlagSizeInBytes )]),CRLF


      print "eip="
      print uhex$([esp + ( (RegSizeInBytes * 9) + FlagSizeInBytes )])
           
      print " flags="
      print uhex$([esp + FlagSizeInBytes ]),CRLF
     
      pop eax
      mov flags,eax
      push eax
     
      popfd
      popad
     
      ;---------------------------------------------------------------------------
 
     
      print "                                           AC VM  FLAG", CRLF
      mov edx,10h
      mov eax,flags
bitloop1:
      push edx
      shl eax,1
      push eax
      jc @F
      print "  0",0
      jmp there1
@@:
      print "  1",0
there1:
      pop eax
      pop edx
      dec edx
      jnz bitloop1
      push eax
      print " ",CRLF
      print " 1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10  HEX ",TWOCRLF


     
      print "  R  -NT- PR  O  D  I  T  S  Z     A     P     C  FLAG",CRLF
       mov edx,10h
       pop eax
bitloop2:
      push edx
      shl eax,1
      push eax
      jc @F
      print "  0",0
      jmp there2
@@:
      print "  1",0
there2:
      pop eax
      pop edx
      dec edx
      jnz bitloop2
      print " ",CRLF

     
      print " 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00  HEX ",CRLF
     return 0

main endp

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

Init proc   

    ; cls
   
    ret

Init endp

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

Fini proc

    ; inkey

    ret

Fini endp

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

end start


Still a work in progres...

Gunther

Hi drifter,

well done.  :t

Gunther
You have to know the facts before you can distort them.

dedndave

nice - that's very much what it would look like if i wrote it   :P

well - except, i am an old fart - lol
i would try to follow the old debug layout
AX=0000  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B89  ES=0B89  SS=0B89  CS=0B89  IP=0100   NV UP EI PL NZ NA PO NC

(use extended registers, of course)

the flags were
NV/OV  overflow
UP/DN  direction
DI/EI  interrupt enable (probably would omit this one for 32-bit)
PL/NG  sign
NZ/ZR  zero
NA/AC  auxilary carry
PO/PE  parity
NC/CY  carry


also, for flat model win32, the segment registers DS, ES, SS, CS all point to the same section
not sure i would display any of them - kind of meaningless, really
and - we have FS and GS - the value is also somewhat meaningless
in 16-bit DOS, the segment registers were something you had to keep an eye on

drifter

jj207, Gunther, Dave - thanks!

on: February 28, 2013, 11:17:41 PM dedndave wrote:
Quotei would try to follow the old debug layout

yeah - I miss debug (and com files) - I'll probably do that.  I wanted to see the shl loop paint the bits, but now it's more about screen real estate.

Where do you find the segment registers?  If I recall from my DOS daze, they were in some of the registers when the program starts - but if I'm using this as a debugging macro, those may have changed by the time it's called.

Quoteexcept, i am an old fart - lol

yeah - us old farts age like cheese rather than wine I'm afraid.  I used to live and breath this stuff back in the 80's, but my career took a different path.  When I was making money and had no time, I tried to keep my hand in by buying some of the toys I knew I'd want later - Visual Studio, IDA Pro (getting that was a real pita), etc.  Now I'm broke, almost homeless :eusa_boohoo: and have all the time in the world - but at least I have my toys - and the thrill is back!

dedndave

in 16-bit DOS, the segment registers were used to control which sections of memory were "visible"

in the win32 flat model, you can directly address 4 gb of memory space
so, we no longer have to worry about segment registers

and - they don't work the same way in protected mode, anyways
they point to an entry in a table that has the real information (global descriptor table)
the tables are based in memory, which is referenced by the GS register
CS, DS, ES, SS point to what are now refered to as "sections", rather than "segments",
and are the same value in a given process

the FS register is of some interest, but the value that's in it isn't - lol
we may access information there, but the specific value is what it is, and has little signifigance
at FS:0, you will find the TIB ("thread information block" or "thread environment block")

http://en.wikipedia.org/wiki/Win32_Thread_Information_Block

you can get the value at FS:[18h] and use that to access the TIB in linear memory
you'll play with it more, when you get to SEH Structured Exception Handling

many of us use Olly as a debugger...
http://www.ollydbg.de/

drifter

on: Feburary 28,2013 at 06:35:49 AM dedndave wrote:
Quotemany of us use Olly as a debugger...

I've installed that and still learning how to use it.  Most of the stuff I'm doing now is just practice to get back into coding again.  Finding my way around and knowing how to access the command line will be useful for later projects.  Command line console apps will keep me happy for awhile, but I'm sure I'll eventually crack the windows.

After I finish these I want to write a routine that will do number conversions to any arbitrary base.  Decimal, hex, octal, and binary are certainly useful - but for music, duodecimal (base 12) and septenary (base 7) are handy.  So, for a pattern generator I have in mind - I want to be able to generate numbers in any base.  The only limit will be the number of unique symbols you can use.

MichaelW

Quote from: dedndave on March 01, 2013, 06:35:49 AM
CS, DS, ES, SS point to what are now refered to as "sections", rather than "segments",
and are the same value in a given process

I keep seeing statements that CS, DS, ES, and SS are all the same, but in my tests they never have been.

;==============================================================================
    include \masm32\include\masm32rt.inc
;==============================================================================
    .data
    .code
;==============================================================================
start:
;==============================================================================
    xor ebx, ebx
    mov bx, cs
    printf("CS: %Xh\n", ebx)
    mov bx, ds
    printf("DS: %Xh\n", ebx)
    mov bx, es
    printf("ES: %Xh\n", ebx)
    mov bx, ss
    printf("SS: %Xh\n", ebx)
    mov bx, fs
    printf("FS: %Xh\n", ebx)
    mov bx, gs
    printf("GS: %Xh\n\n", ebx)
    inkey
    exit
;==============================================================================
end start


CS: 1Bh
DS: 23h
ES: 23h
SS: 23h
FS: 3Bh
GS: 0h

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

dedndave

that is interesting, Michael
however, it would seem that the GDT table entries point to the same place in memory
(code is accessible as read data, for example)

it may be they have seperate entries because the sections have different access attributes
as you know, the code section has a PAGE_EXECUTE_READ attribute
DS, ES, and SS point to an entry that has a PAGE_READWRITE attribute

drifter

on: Feburary 28, 2013 at 08:07:12 AM MichaelW wrote:
Quoteprintf("CS: %Xh\n", ebx)
    mov bx, ds
    printf("DS: %Xh\n", ebx)
    mov bx, es
    printf("ES: %Xh\n", ebx)
    mov bx, ss
    printf("SS: %Xh\n", ebx)
    mov bx, fs
    printf("FS: %Xh\n", ebx)
    mov bx, gs
    printf("GS: %Xh\n\n", ebx)

Thanks!

dedndave

the code below should display something like this
EAX=12345678  EBX=12345678  ECX=12345678  EDX=12345678  EIP=12345678
ESI=12345678  EDI=12345678  EBP=12345678  ESP=12345678  NV UP PL NZ NA PO NC


untested   :biggrin:
DbgRegs PROC

    pushfd
    pushad
    mov     ebp,esp

;[EBP+36]  ;RETurn address
;[EBP+32]  ;EFlags
;[EBP+28]  ;EAX
;[EBP+24]  ;ECX
;[EBP+20]  ;EDX
;[EBP+16]  ;EBX
;[EBP+12]  ;ESP (points to EFlags)
;[EBP+8]   ;EBP
;[EBP+4]   ;ESI
;[EBP]     ;EDI

    print   chr$(13,10,'EAX=')
    print   uhex$([ebp+28]),32,32
    print   chr$('EBX=')
    print   uhex$(ebx),32,32
    print   chr$('ECX=')
    print   uhex$([ebp+24]),32,32
    print   chr$('EDX=')
    print   uhex$([ebp+20]),32,32
    print   chr$('EIP=')
    print   uhex$([ebp+36]),13,10
    print   chr$('ESI=')
    print   uhex$(esi),32,32
    print   chr$('EDI=')
    print   uhex$(edi),32,32
    print   chr$('EBP=')
    print   uhex$([ebp+8]),32,32
    print   chr$('ESP=')
    mov     eax,[ebp+12]
    add     eax,8
    print   uhex$(eax),32,32

;8 NV/OV  overflow
;7 UP/DN  direction
;4 PL/NG  sign
;3 NZ/ZR  zero
;2 NA/AC  auxilary carry
;1 PO/PE  parity
;0 NC/CY  carry

    mov     ebx,[ebp+32]
    bt      ebx,8
    .if CARRY?
        print   chr$('OV ')
    .else
        print   chr$('NV ')
    .endif
    bt      ebx,7
    .if CARRY?
        print   chr$('DN ')
    .else
        print   chr$('UP ')
    .endif
    bt      ebx,4
    .if CARRY?
        print   chr$('NG ')
    .else
        print   chr$('PL ')
    .endif
    bt      ebx,3
    .if CARRY?
        print   chr$('ZR ')
    .else
        print   chr$('NZ ')
    .endif
    bt      ebx,2
    .if CARRY?
        print   chr$('AC ')
    .else
        print   chr$('NA ')
    .endif
    bt      ebx,1
    .if CARRY?
        print   chr$('PE ')
    .else
        print   chr$('PO ')
    .endif
    bt      ebx,0
    .if CARRY?
        print   chr$('CY '),13,10
    .else
        print   chr$('NC '),13,10
    .endif
    popad
    popfd
    ret

DbgRegs ENDP

sinsi

>the tables are based in memory, which is referenced by the GS register
No, the GDT limit and address are stored in the GDTR

>CS, DS, ES, SS point to what are now refered to as "sections", rather than "segments",
Selectors rather than sections

>and are the same value in a given process
CS will be different because it is a code descriptor, DS=ES=SS usually, FS is used by Windows, GS is available to us.

A selector is an index into the GDT, pointing to an 8-byte descriptor.
The lower 3 bits of a selector are used for protection - in user land bits 0 and 1 are always set (meaning ring3).
So if CS=1Bh the descriptor starts at offset 18h in the GDT, if DS=23h it points to offset 20h and so on.