Site hosted by Angelfire.com: Build your free website today!
NaN Title


Dont get hung up on structures.. they are not a hassle at all...

The point of structures is yes, to localize alot of data under one premise
(or tag name). However, they are still a bit abstract from ASM programming,
which is why i suspect you have been having problems in the past. They are
simply a template to help organize data, but they are NOT data in 
themselves. I better go to examples at this point:

I could say.. 

Point1_x  dd 0
Point1_y  dd 0
Point2_x  dd 0
Point2_y  dd 0 etc. etc.


And in using them i would have to reference each member directly:

mov eax, Point2_y

or

lea ebx, Point1_x
mov eax, [ebx + 12]  ; 12'th byte after the first as defined above


This is ok, but it would be easier to use data if they are grouped together as 
one type of data:

My_Point struc
   x   dd  ?
   y   dd  ?
My_Point ends

and in .data
  
  Point1  My_Point  <0,0>  ; initialize x,y to 0,0
  Point2  My_Point  <2,0>  ; initialize x,y to 2,0

or in .data?
   
  Point3  My_Point <>  ; uninitialized data 
  Point4  My_Point <>


The in the data segments, the stucture is used as a template to allocate the 
amount of memory (dd's) in the order they appear in the template. This
is why i say stucts are NOT data in themselves. Now, if i were to 
disassemble the data segment of this one or the pervious above, they 
data would be in the same order (point1's x data, point1's y data, 
point2's x data, point2's y data). The difference is by simply telling 
MASM this will by a structured define, you can skip the redundancy of 
typing it all out in order.

The code to use these are now:

  mov eax, Point2.y  

  ; y is the structure member that masm used to determin the offset
  ; this is the same as
  ;    lea ebx, Point2
  ;    mov eax, [ebx + 4]  ; 4 bytes after the first (y data)


One of the benifits is the fact the data HAS to be grouped together as prescibed 
in the structure template.. my origional example of separated data IS 
grouped together, but doesnt has to be. It could be a random like such:

  Point1_x dd 0
  MyFlag   dd 0
  Point1_y dd 0
  Point2_x dd 0
  IsOn     dd 0
  Point2_y dd 0

If i were asked to have the address to a point in this setup, you couldnt do it, 
because MyFlag is inbetween Point1_x and Point1_y:

  invoke SomeFunct, addr Point1_x

will be used as:

  mov ebx, Point1_x  ; base address of a point
  mov eax, [ebx]     ; get the x data
  mov eax, [ebx + 4] ; get the y data (assumed 4 bytes after the base)

The problem here is, 4 bytes after the first is MyFlag!!!! Using structures 
insures this problem is always taken care of (assuming the structure is 
defined in the correct order).

Taking this a step further, you can also NEST structures to build more 
complex bounded data:

My_Circle sturct
  Center  My_Point <>
  Radius  dd       ?
My_Circle ends

Colored_Circle struct
  Circle  My_Circle <>
  Color   dd        ?
Colored_Circle ends

By simple defining in .data? 

  RGB_Circle  Colored_Circle  <>

i have allocated memory in the data segment in this order:

RGB_Circle:  4 bytes, Referenced as (this).Circle.Center.x
            +4 bytes, Referenced as (this).Circle.Center.y
            +4 bytes, Referenced as (this).Circle.Raduis
            +4 bytes, Referenced as (this).Color

NOTE: (this) refers to the name of the defined data for 'this' structure type,
in this case it would be RGB_Circle.Circle.Center.x

ALSO NOTE: the 'SIZEOF Colored_Circle' command would return the above
evaluation = 16 bytes.


As a final thought, the use of stuctures are also advantageous when dealin with 
them as pointer, by simply passing a simple 4 byte pointer, it can be 
used to directly reference (in the above case) 16 bytes of data. (this 
speeds up your function calling, because less is being pushed on the 
stack).

; my fuction used a colored circle...
My_Fuction proc lpColoredCirlce:DWORD
 ...
 mov ebx, lpColoredCircle
 mov eax, (Colored_Circle PTR [ebx]).Circle.Center.x   ;get x
 mov edx, (Colored_Circle PTR [ebx]).Circle.Center.y   ;get y
 mov esi, (Colored_Circle PTR [ebx]).Radius            ;get Rad
 mov edi, (Colored_Circle PTR [ebx]).Color             ;get Color

 add edi, 20h
 mov (Colored_Circle PTR [ebx]).Color, edi             ;set Color
 ...

ret
My_Function endp


If your thinking there is still alot of keystrokes 
involved here a simpler trick is to use the ASSUME directive on a 
register as follows:

; my fuction used a colored circle...
My_Fuction proc lpColoredCirlce:DWORD
 ...
 mov ebx, lpColoredCircle
 ASSUME ebx:PTR Colored_Circle  ; saves redundant typing
 mov eax, [ebx].Circle.Center.x   ;get x
 mov edx, [ebx].Circle.Center.y   ;get y
 mov esi, [ebx].Radius            ;get Rad
 mov edi, [ebx].Color             ;get Color

 add edi, 20h
 mov [ebx].Color, edi             ;set Color
 ...
 ASSUME EBX:NOTHING  ; unassume ebx
ret
My_Function endp


Well there is my crash-course tutorial on Structures , im only a modest 
programmer my self, so with the volume of info i tossed at you its 
possible i overlooked some minor detail, but in essence this is it.. 
Hope it helps you out...

NaN

(( REPLY BY ERNIE ))

Everything Nan said he said well and true. However, a few thoughts 
on using assume.

We all know, when you ASSUME something, you make an ASS of U and ME.
Trite, but still true.

If you assume a register, then forget to unassume it, you can get 
strange results. Or, the assume could be so far from the line that 
needs it the meaning is left unclear (to the human reading the code). 
I'm not a big fan of weird "action at a distance" operators like this.

I am a devoted user of structures, they are just so handy. I used to 
use the syntax Nan stated, until I found a slightly more compace (but 
just as readable) form MASM accepts:

 mov ebx, lpColoredCircle
 mov eax, (Colored_Circle PTR [ebx]).Circle.Center.x   ;get x
 mov edx, (Colored_Circle PTR [ebx]).Circle.Center.y   ;get y
 mov esi, (Colored_Circle PTR [ebx]).Radius            ;get Rad
 mov edi, (Colored_Circle PTR [ebx]).Color             ;get Color

may also be stated as:

 mov ebx, lpColoredCircle
 mov eax, [ebx].Colored_Circle.Circle.Center.x   ;get x
 mov edx, [ebx].Colored_Circle.Circle.Center.y   ;get y
 mov esi, [ebx].Colored_Circle.Radius            ;get Rad
 mov edi, [ebx].Colored_Circle.Color             ;get Color

Ernie

(( REPLY BY MIRNO ))

The idea of a structure is purely for us the programmer.
All the computer sees is data, for example:

MyStruct STRUCT
  a DWORD ?
  b BYTE  ?
  c WORD  ?
  d BYTE 3 DUP (?)
MyStruct ENDS

As far as memory allocation is concerned this is 10 bytes, nothing else. To the 
assembler, it is also a method of formating accesses to that data, and 
it is possible to apply that formating to any piece of memory.

This allows the following code:

FourLetterWord STRUCT
  FirstLetter    BYTE ?
  SecondLetter   BYTE ?
  ThirdLetter    BYTE ?
  FourthLetter   BYTE ?
  NullTerminator BYTE ?
FourLetterWord ENDS

.data
 Word1 db "spam",0
 Word2 db "clam",0

.code
start:
  mov edx, ADDR Word1
  mov (FourLetterWord PTR [edx]).FirstLetter, 'c'

  invoke ExitProcess, 0
end start

Although we declared Word1 as a string of bytes, we can apply the formating of 
the FourLetterWord structure to it.

So in the case of GlobalAlloc, you need to do something like:

  invoke GlobalAlloc, ACCESS_TYPE, SIZEOF MyStruct * number_needed


This will create enough data to apply the format of MyStruct without causing 
errors.

Mirno

(( REPLY BY NaN ))

Exactly, your simply allocating a bunch of bytes.. but if you keep 
control of all your allocated bytes of data (ie, add proper offsets to 
your global data pointer), then you can use the above methods with 
pointers as Ernie outlined.

Structures are simply masks or templates to make your memory 'look' 
organized... as Mirno demonstrates (good example BTW).

I could still allocate 5 bytes of heap memory, and use my above 
structure (size 16 bytes templated) to reference it! The catch is, i 
would only be able to access:

  mov ebx, GlobalDataPointer
  mov eax, (Colored_Circle PTR [ebx]).Cricle.Center.x 

Because this is the first 4 bytes templated by my structure. To try to go to 'y' 
would violate the heap space alocated, since in my example i have only 
allocated 5 bytes in all. This is why Mirno suggests 'N * sizeof 
Colored_Circle' where N is Integers > 1. That way you will always have 
just enough data, to imply an array of N Colored_Cirlce structures, 
and know you have enough data set asside for each memeber!

NaN

Go Back?