The MASM Forum

General => The Campus => Topic started by: hfheatherfox07 on August 28, 2012, 06:36:44 PM

Title: TEXTEQU
Post by: hfheatherfox07 on August 28, 2012, 06:36:44 PM
Some body on the old forum posted this in a reply to something (Forgot what) ....
But I saved it to study later .....
;yes - when you assign a string with EQU, the assembler actually makes it a TEXTEQU, which can be reassigned
;i like to use them when i make my own stack frames   :)
; _________________________________________________________________________________________________________________
_ModeControl  TEXTEQU <[EBP+36]> ;signed/unsigned mode control
_OutBufSize   TEXTEQU <[EBP+32]> ;output buffer size in bytes
_OutBufBase   TEXTEQU <[EBP+28]> ;output buffer base address
_InpValSize   TEXTEQU <[EBP+24]> ;input value size in bytes
_InpValBase   TEXTEQU <[EBP+20]> ;input value base address

;                      [EBP+16]   PROC return address
;                      [EBP+12]   saved ESI contents
;                      [EBP+8]    saved EDI contents
;                      [EBP+4]    saved EBX contents
;                      [EBP]      saved EBP contents

_SignXorMask  TEXTEQU <[EBP-4]>  ;sign XOR mask
_OutLastDword TEXTEQU <[EBP-8]>  ;address of last dword in output buffer
;
;
;
        mov     ecx,_InpValBase  ;mov ecx,[ebp+20]


I looked at it Tonight.....
And I was wondering what does negative mean ?

[ebp-04] 
[ebp-06]
[ebp-10]
[ebp-14]
[ebp-18]


And how to use this ?

Thank you  8)
Title: Re: TEXTEQU
Post by: dedndave on August 28, 2012, 11:44:38 PM
well - it does not have to be that way
but, generally, we use positive offsets from EBP for passed parameters and preserved register values
and we use negative offsets from EBP for local variables
there are cases where you get an advantage by doing things a little differently, but that's another subject

if you look at how the stack frame is created, you might get a better understanding

in this case, the function has 5 passed parameters that are pushed by INVOKE
those are on the stack, above the RET address that is pushed by the call

next, the registers that are to be preserved are pushed
the last of these is the EBP register, that will be used as the stack frame base pointer

at that point, the EBP register is initialized with
        mov     ebp,esp
so, all the things that were pushed previously will have a positive offset, relative to the EBP value

from there, the local variables are created by pushing them onto the stack
they will have a negative offset relative to the value that is in EBP
Title: Re: TEXTEQU
Post by: hfheatherfox07 on August 28, 2012, 11:59:46 PM
Huh ?

[ebp-04]  = ?  [ebp-10] =?

I Looked Here http://www.webalice.it/jj2006/Masm32_Tips_Tricks_and_Traps.htm
Title: Re: TEXTEQU
Post by: Ryan on August 29, 2012, 01:30:15 AM
It is not negative necessarily.  It is a subtraction.

ebp contains an address to a location on the stack.  [ebp-04] offsets the pointer down by 4, while the square brackets tells it to give the value at the offset address.
Title: Re: TEXTEQU
Post by: Ryan on August 29, 2012, 01:34:27 AM
Try creating a small proc with a few LOCAL variables, and do some operations with them.  Once you assemble your code, you can disassemble it to see what the macro assembler does for LOCAL variables.
Title: Re: TEXTEQU
Post by: qWord on August 29, 2012, 01:44:27 AM
maybe he isn't familiar with the x86 memory addressing? scale, index, base, and displacement are known?
Title: Re: TEXTEQU
Post by: hfheatherfox07 on August 29, 2012, 02:03:31 AM
I think I Got Confuse with this Statement :
;yes - when you assign a string with EQU, the assembler actually makes it a TEXTEQU, which can be reassigned
;i like to use them when i make my own stack frames   :)


So If you have something in the .asm Like :
ID_Timer    EQU    1   
Than the "assembler actually makes it a TEXTEQU"  So Only if you look at it with a disassembler will you see :
TEXTEQU <[EBP+28]>

How does it determine the # in the EBP brakets ?
I don't think I get that ?

I looked at random .exe's that I have made and I see stuff like this?????

MOV EAX,DWORD PTR SS:[EBP-10]          ; <- What Does [EBP-10] even mean ???
MOV EDX,DWORD PTR SS:[EBP-4]            ; <- What Does [EBP-4] even mean ???
MOVZX EAX,BYTE PTR DS:[EAX+EDX-1]     ; <- What Does [EAX+EDX-1]  even mean ???

I don't really do any debugger work ....Is that the only place were you would see these textequo's ?

I have not found a single tutorial on how to use a debugger to trace a crashing app....
and what is wrong that makes it crash ......

If you Google asm and debug ...al the tuts are on fishing .... you know what
That does not explain where an app crashed and why ? 

Were do you learn that?
like a simple  Helloworld.exe that crashes and a tut to explain how to trace what and why
Most of the recommended literature on MASM looks like a wiring schematic for the Manhattan project
Title: Re: TEXTEQU
Post by: Ryan on August 29, 2012, 02:44:55 AM
TEXTEQU performs a Find/Replace in a sense.

_OutBufBase   TEXTEQU <[EBP+28]>
The above statement tells the assembler to replace all occurrences of _OutBufBase with [EBP+28].  If the location on the stack for this variable (_OutBufBase) were to change, it would be easiest to change one statement, instead of searching the entire code for the occurrences.  I believe that is the point of the statement "can be reassigned".

The # in the EBP brackets is an offset.  A word is 2 bytes; a dword is 4 bytes.  If allocation for a dword is desired, the # would be 4 less than the previous variable on the stack.  This is the hard way to do things in my opinion.  It makes code harder to read, and MASM has very good handling of local variables built in.
Title: Re: TEXTEQU
Post by: hfheatherfox07 on August 29, 2012, 03:00:26 AM
SO .... in MOV EAX,DWORD PTR SS:[EBP-10]    for example in a draw text.exe
The [EBP-10]  is the occurrences of the letters being drawn or hdc in the
 
LOCAL  hdc:HDC

Or it could be the

sZText  db ' Flashing Text',0

And than the assembler just chooses the letters in the bracket per order of the .asm


So Now I am Getting into   word and  dword which I don't get that well....
I know that WORD is 16-bit unsigned integer and DWORD is 32-bit unsigned integer.



Title: Re: TEXTEQU
Post by: Ryan on August 29, 2012, 03:18:40 AM
[EBP-10] could point to anything.  It's impossible to know what it is without more information.

mov eax, hdc
would translate to:
mov eax, dword ptr [ebp-4]
assuming hdc is the only local variable.  HDC is really a dword, so it would result in an offset of 4 bytes.

szText is not a variable on the stack, so ebp does not apply.
Title: Re: TEXTEQU
Post by: dedndave on August 29, 2012, 03:25:35 AM
let's start with "EQU" and "TEXTEQU"
they are somewhat similar, with 2 very important differences

numeric values assigned with EQU may not be redefined later in the source
SomeEqu  EQU 1
if you try to assign SomeEqu a different value later on, the assembler will bark a redefinition error
it is important to understand that 1, in this case, is a number - not a string
the assembler resolves it to a numeric value

you can assign a string to an EQU
if you do, it behaves more like TEXTEQU
SomeText TEXTEQU <xyzzy>
TEXTEQU finds the occurances of "SomeText" in the source and replaces it with "xyzzy" before evaluating a line of code
TEXTEQU labels may be reassigned to different values later in the source
the assembler will use the most recent definition when evaluating a line of code
notice that if you assign a value "1" in a TEXTEQU, it is treated as a replacement string - not a numeric value

now - let's hit on stack frames a bit...

the EBP register is often used as a stack frame Base Pointer
during execution of a proc, it holds a stable address, which is simply a reference point on the stack
by stable, i mean that it does not change when values are pushed on or popped off the stack
ESP does change each time you push or pop - and thus would be inconvenient to use this way

let's make a simple stack frame.....
        push    1
        push    2
        push    3
        mov     ebp,esp
        push    4
        push    5
        push    6

the EBP register is used to establish a stable address on the stack
in this case, it will always point to our 3 value
        mov     eax,[ebp]     ;EAX = 3
at the location [EBP-4], we have a 4
at the location [EBP-8], we have a 5
at the location [EBP+8], we have a 1
these references will not change if we push/pop other values onto the stack
on 32-bit processors, we generally try to keep the stack 4-aligned
so, [EBP-10] will not be seen as often as, say, [EBP-12]   :P

stack frames are used to hold temporary data
when the proc exits, the stack frame is destroyed, and anything we had on it is essentially lost

if you look at disassembled code, you might see something like this
        push    ebp
        mov     ebp,esp
        sub     esp,32

here, stack space has been reserved for 8 dwords (or maybe a 32 byte string)
they are not initialized with any particular value, however
Title: Re: TEXTEQU
Post by: jj2007 on September 02, 2012, 07:04:57 AM
Quote from: hfheatherfox07 on August 29, 2012, 02:03:31 AM
I have not found a single tutorial on how to use a debugger to trace a crashing app....
and what is wrong that makes it crash ......

That is easy. Assemble & link the mini-app below, and open the exe in Olly. Then press F7 and see what happens...

include \masm32\include\masm32rt.inc

MyTest PROTO: DWORD, :DWORD

.code
AppName db "Masm32 is great!", 0
Hello db "A message:", 0

start:
int 3
invoke MyTest, offset AppName, addr Hello
exit

MyTest proc arg1:DWORD, arg2:DWORD
LOCAL lv1, lv2, locbuf[260]:BYTE
nop
mov lv1, 123
nop
mov lv2, eax
nop
mul lv2
nop
  MsgBox 0, arg1, arg2, MB_OK
  ret
MyTest endp

end start
Title: Re: TEXTEQU
Post by: hfheatherfox07 on September 02, 2012, 12:17:20 PM
@ jj2007
I meant a tutorial ...explaining every line in that ....and what it means
I don't know how to read debugger
Title: Re: TEXTEQU
Post by: jj2007 on September 02, 2012, 05:57:23 PM
You don't have to "read debugger". Just press F7 and watch in the upper right corner how the contents of eax changes when you hit a mov eax, 123 etc

Just do it. Olly won't bite you, promised 8)
Title: Re: TEXTEQU
Post by: Gunther on September 02, 2012, 07:21:39 PM
Quote from: jj2007 on September 02, 2012, 05:57:23 PM
Just do it. Olly won't bite you, promised 8)

yes, Jochen is right. Olly won't bite you.

Gunther
Title: Re: TEXTEQU
Post by: hfheatherfox07 on September 03, 2012, 01:57:45 AM
Frustrating..... :(

That why I mentioned that there is no tuts out there ....

I looked there and did not understand a thing ..... It takes me straight into ntdll

I commented out INT 3 and it works ....

Why did you ad a debugger trap? of course it will stop
If you comment out the ret after  MsgBox 0, arg1, arg2, MB_OK
than the program crashes after close

That is what I meant by a tut ....  a normal helloworld.exe that works and every thing commented in the disassem

Then a Helloworld.exe that crashes ....
And to show how to find that and why ....

For now I don't really need to know debug ...I will stay a way from it until I find a proper tut ...I am just going to get frustrated     :icon_cool:

Title: Re: TEXTEQU
Post by: qWord on September 03, 2012, 03:14:30 AM
Quote from: hfheatherfox07 on September 03, 2012, 01:57:45 AM
That why I mentioned that there is no tuts out there ....
There are thousands of 'tutorials' whereas most of them are related to RE....

Quote from: hfheatherfox07 on September 03, 2012, 01:57:45 AMI commented out INT 3 and it works ....

Why did you ad a debugger trap? of course it will stop
It is a simple method to find the point of interest in your program - you can step over the INT3.

Quote from: hfheatherfox07 on September 03, 2012, 01:57:45 AMIf you comment out the ret after  MsgBox 0, arg1, arg2, MB_OK
than the program crashes after close
What did you expect?

Quote from: hfheatherfox07 on September 03, 2012, 01:57:45 AM
Then a Helloworld.exe that crashes ....
And to show how to find that and why ....
Olly stops at the instruction that cause the exception. The status bar shows what kind of exception occurs at this point. The problem for you is maybe that a crash can also occur in API functions - looking up the calling chain in the stack (-window) is useful in this case.
Title: Re: TEXTEQU
Post by: hfheatherfox07 on September 05, 2012, 04:14:47 AM
Lets go back to this....
Originally this was posted :


_SignXorMask  TEXTEQU <[EBP-4]>  ;sign XOR mask
_OutLastDword TEXTEQU <[EBP-8]>  ;address of last dword in output buffer


what is a sign XOR mask?

Thank you
Title: Re: TEXTEQU
Post by: MichaelW on September 05, 2012, 06:00:21 AM
I don't know what a sign XOR mask is, but _SignXorMask is a DWORD local variable.
Title: Re: TEXTEQU
Post by: hfheatherfox07 on September 05, 2012, 07:36:17 AM
Thanks...
But I ment what is "_SignXorMask" ?

So:

LOCAL  _SignXorMask: DWORD

What does that mean in an assembly ?
Like hdc  I thought SignXorMask was something specific
Title: Re: TEXTEQU
Post by: dedndave on September 05, 2012, 09:32:13 AM
don't get caught up on the wrong part of the story - lol

i only used those as examples - they are from a routine of mine that converts binary to decimal string
the names could be anything you like - meaningful to your specific code

in this case, the sign xor mask is a stored value that represents the binary sign of the input value
if the sign bit of the input value is 0 (positive), the value is initialized to 0 (dword)
if the sign bit of the input value is 1 (negative), the value is initialized to -1 (dword)
that mask is then used to XOR onto the dwords of the input value
at the end of conversion, the XOR mask is also added to the result
that way, the routine can handle positive or negative values the same way

(+1 xor 0) + 0 = +1
(-1 xor -1) + (-1) = -1

the routine is designed to handle signed or unsigned values, depending on a flag bit
so - if the flag bit is set - and the value is negative, the mask is set to -1
if the flag bit is not set - or the value is positive, the mask is set to 0
Title: Re: TEXTEQU
Post by: MichaelW on September 05, 2012, 09:56:55 AM
I did not have time to do much checking of this, so apologies for any errors.

This applies only to 32-bit code.

The stack is functionally a last in, first out (LIFO) data structure. The PUSH instruction subtracts 4 from the stack pointer (ESP) and then copies the contents of its operand (a 32-bit register or memory operand, or an immediate operand) to the stack at the address specified by ESP. The POP instruction copies the 32-bit value from the stack address specified by ESP to its operand (a 32-bit register or memory operand) and then adds 4 to ESP. As values are pushed, the stack "grows" down in memory. Barring direct manipulation of ESP it always points to the "top" of the stack, the location of the last item pushed and the next in line to be popped. Positive offsets from ESP point into the "active" stack space, and negative offsets into the "free" stack space.

The CALL instruction effectively pushes the return address (the address of the instruction following the CALL instruction) and then jumps to the address specified by its operand. The RET instruction effectively pops the value at the "top" of the stack and uses it as a jump destination.

The programmer can manipulate ESP indirectly using the CALL, RET, PUSH, and POP instructions as described above, or directly by using it as an instruction operand, typically for the ADD or SUB instructions. A key requirement here is that any adjustments to the address in ESP must preserve its 4-byte alignment, and this is normally accomplished by adding or subtracting some multiple of 4.

For both of the most common 32-bit calling conventions, STDCALL and CDECL, the procedure parameters are pushed (prior to the procedure call) in right to left order as they appear in the procedure definition or declaration. For STDCALL the called procedure is responsible for removing the parameters from the stack. This is normally done by appending a constant to the RET instruction that specifies the number of bytes to release, which will be 4 * the number of 32-bit parameters. For CDECL the caller is responsible for removing the parameters from the stack, so the procedure returns with a RET instruction with no constant appended.


;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
.data
.code
;==============================================================================

;-----------------------------------------------------------------------------
; These options effectively turn off the automatically generated prologue and
; epilog code, so the only code in the procedure is the code that you see in
; the source.
;-----------------------------------------------------------------------------

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

Test1 proc arg1:DWORD, arg2:DWORD, arg3:DWORD, arg4:DWORD

    ;----------------------------------------------
    ; At entry the relevant contents of the stack
    ; expressed as offsets from ESP, are:
    ; [esp+16]  arg4
    ; [esp+12]  arg3
    ; [esp+8]   arg2
    ; [esp+4]   arg1
    ; [esp+0]   return address
    ;----------------------------------------------

    ;------------------------------------------------------
    ; Preserve EBP and set it to the current value of ESP,
    ; preparing it for use as a stack frame pointer.
    ;------------------------------------------------------

    push ebp
    mov ebp, esp

    ;---------------------------------------------
    ; At this point the relevant contents of the
    ; stack expressed as offsets from EBP, are:
    ; [ebp+20]  arg4
    ; [ebp+16]  arg3
    ; [ebp+12]  arg2
    ; [ebp+8]   arg1
    ; [ebp+4]   return address
    ; [ebp+0]   preserved EBP
    ;---------------------------------------------

    ;--------------------------------------------
    ; Reserve space on the stack for local data,
    ; in this case 4 dwords.
    ;--------------------------------------------

    sub esp, 16

    ;---------------------------------------------
    ; At this point the relevant contents of the
    ; stack expressed as offsets from EBP, are:
    ; [ebp+20]  arg4
    ; [ebp+16]  arg3
    ; [ebp+12]  arg2
    ; [ebp+8]   arg1
    ; [ebp+4]   return address
    ; [ebp+0]   preserved EBP
    ; [ebp-4]   local1
    ; [ebp-8]   local2
    ; [ebp-12]  local3
    ; [ebp-16]  local4
    ;---------------------------------------------

    _arg1 equ <DWORD PTR [ebp+8]>
    _arg2 equ <DWORD PTR [ebp+12]>
    _arg3 equ <DWORD PTR [ebp+16]>
    _arg4 equ <DWORD PTR [ebp+20]>

    local1 equ <DWORD PTR [ebp-4]>
    local2 equ <DWORD PTR [ebp-8]>
    local3 equ <DWORD PTR [ebp-12]>
    local4 equ <DWORD PTR [ebp-16]>

    mov eax, _arg1
    mov ebx, _arg2
    mov ecx, _arg3
    mov edx, _arg4

    mov local1, eax
    mov local2, ebx
    mov local3, ecx
    mov local4, edx

    printf("%d\t", local1)
    printf("%d\t", local2)
    printf("%d\t", local3)
    printf("%d\n\n", local4)

    ;-----------------------------------------------------------------
    ; Restore the entry-point value of ESP. This step is essential so
    ; the following POP and RET instructions will access the correct
    ; stack addresses.
    ;-----------------------------------------------------------------

    mov esp, ebp

    ;---------------------------------
    ; Recover the entry value of EBP.
    ;---------------------------------

    pop ebp

    ;---------------------------------------------------
    ; Return to the caller and adjust the stack pointer
    ; to remove the parameters (4 * 4 bytes each) from
    ; the stack, as per the stdcall calling convention.
    ;---------------------------------------------------

    ret 16

Test1 endp

;---------------------------------------------------------------
; Turn the default prologue and epilog code generation back on.
;---------------------------------------------------------------

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef

;==============================================================================
start:
;==============================================================================

    push 4
    push 3
    push 2
    push 1
    call Test1

    inkey
    exit
;==============================================================================
end start