Reputation: 223
I want to initialize a local struct on the stack.
Records STRUCT
data1 DWORD ?
data2 DWORD ?
data3 DWORD ?
data4 DWORD ?
Records ENDS
.CODE
main:
mov ebp, esp
sub esp, SIZEOF Records
How do I make a named instance of struct Records
that I can then use to initialize the data members? I want to use the struct
directive with the dot operator and not pointer addition.
I started out by allocating space for the struct, then what should I do?
Upvotes: 4
Views: 3920
Reputation: 47653
I would use the power of the PROC
directive to define functions1 and the LOCAL
directive to allocate variables in a function. The assembler will deal with the prologue and epilogue code and you can associate a type with the local.
You could write a function that looks like:
main PROC
LOCAL rec1: Records
mov rec1.data1, 1
mov rec1.data2, 2
mov rec1.data3, 3
mov rec1.data4, 4
ret
main ENDP
The code will allocate space on the stack for a variable called rec1
and the remaining lines initialize the structure fields with the values 1,2,3,4. The generated assembly code would look something like:
Segment: _TEXT DWORD USE32 00000033 bytes 0000 _main: 0000 55 push ebp 0001 8B EC mov ebp,esp 0003 83 EC 10 sub esp,0x00000010 0006 C7 45 F0 01 00 00 00 mov dword ptr -0x10[ebp],0x00000001 000D C7 45 F4 02 00 00 00 mov dword ptr -0xc[ebp],0x00000002 0014 C7 45 F8 03 00 00 00 mov dword ptr -0x8[ebp],0x00000003 001B C7 45 FC 04 00 00 00 mov dword ptr -0x4[ebp],0x00000004 0022 C9 leave 0023 C3 ret
The assembler created a stack frame and computed all the offsets on the stack for you relative to EBP. If you wanted to get the address of rec1
into a register and work with it as a structure you can use LEA
to get the effective address of the variable on the stack and use ASSUME
to apply a pointer type to it:
main PROC
LOCAL rec1: Records
lea eax, [rec1]
ASSUME eax: ptr Records
mov [eax].data1, 1
mov [eax].data2, 2
mov [eax].data3, 3
mov [eax].data4, 4
ret
main ENDP
The generated assembly code would be:
Segment: _TEXT DWORD USE32 00000035 bytes 0000 _main: 0000 55 push ebp 0001 8B EC mov ebp,esp 0003 83 EC 10 sub esp,0x00000010 0006 8D 45 F0 lea eax,-0x10[ebp] 0009 C7 00 01 00 00 00 mov dword ptr [eax],0x00000001 000F C7 40 04 02 00 00 00 mov dword ptr 0x4[eax],0x00000002 0016 C7 40 08 03 00 00 00 mov dword ptr 0x8[eax],0x00000003 001D C7 40 0C 04 00 00 00 mov dword ptr 0xc[eax],0x00000004 0024 C9 leave 0025 C3 ret
You can use the LOCAL
directive to create an array of types as well. You can then initialize elements of individual records in the array. This example allocates space on the stack for an array of 4 Records
called rec1
and initializes the the third element (array index 2 since array element numbering is zero based):
main PROC
LOCAL rec1[4]: Records
; Compute address of third Record structure in array
lea eax, [rec1]
ASSUME eax: ptr Records
add eax, 2*(SIZEOF Records)
; Initialize the the third Record structure
mov [eax].data1, 1
mov [eax].data2, 2
mov [eax].data3, 3
mov [eax].data4, 4
ret
main ENDP
The generated assembly code would be:
Segment: _TEXT DWORD USE32 00000038 bytes 0000 _main: 0000 55 push ebp 0001 8B EC mov ebp,esp 0003 83 EC 40 sub esp,0x00000040 0006 8D 45 C0 lea eax,-0x40[ebp] 0009 83 C0 20 add eax,0x00000020 000C C7 00 01 00 00 00 mov dword ptr [eax],0x00000001 0012 C7 40 04 02 00 00 00 mov dword ptr 0x4[eax],0x00000002 0019 C7 40 08 03 00 00 00 mov dword ptr 0x8[eax],0x00000003 0020 C7 40 0C 04 00 00 00 mov dword ptr 0xc[eax],0x00000004 0027 C9 leave 0028 C3 ret
I split the LEA
and the ADD
into separate instructions to better illustrate what is going on. It can be simplified by removing the ADD
and using LEA
to add the offset to the base pointer of the rec1
array directly. Preferably it would have been written as:
lea eax, [rec1 + 2*(SIZEOF Records)]
ASSUME eax: ptr Records
If you create structures at global scope (not locals on the stack) you can declare and initialize them this way:
.DATA
rec2 Records <1,2,3,4>
Each field in the structure is separated by a comma. The structure would appear in the _DATA
segment like this:
Segment: _DATA DWORD USE32 00000010 bytes 0000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................
The data is printed in bytes. Each individual DWORD appears with LSB (least significant byte) to MSB (most significant byte). If displayed as DWORDs they would appear as
0000 00000001 00000002 00000003 00000004
1I used a .MODEL
directive at the top of the assembly file to assume C style calling convention by default:
.386
.model flat, C
Upvotes: 7