Я бы использовал силу директивы PROC
для определения функций 1 и директивы LOCAL
для распределения переменных в функции.Ассемблер будет иметь дело с кодом пролога и эпилога, и вы можете связать тип с локальным.
Вы можете написать функцию, которая выглядит следующим образом:
main PROC
LOCAL rec1: Records
mov rec1.data1, 1
mov rec1.data2, 2
mov rec1.data3, 3
mov rec1.data4, 4
ret
main ENDP
Код будет выделять пространство настек для переменной с именем rec1
, а остальные строки инициализируют поля структуры значениями 1,2,3,4.Сгенерированный ассемблерный код будет выглядеть примерно так:
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
Ассемблер создал кадр стека и рассчитал для вас все смещения в стеке относительно EBP .Если вы хотите получить адрес rec1
в регистр и работать с ним как со структурой, вы можете использовать LEA
, чтобы получить эффективный адрес переменной в стеке, и использовать ASSUME
, чтобы применить к ней тип указателя.:
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
Сгенерированный код сборки будет:
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
Вы также можете использовать директиву LOCAL
для создания массива типов.Затем вы можете инициализировать элементы отдельных записей в массиве.В этом примере выделяется место в стеке для массива 4 Records
, называемого rec1
, и инициализируется третий элемент (индекс массива 2, поскольку нумерация элементов массива начинается с нуля):
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
Сгенерированная сборкакод будет:
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
Я разбил LEA
и ADD
на отдельные инструкции, чтобы лучше проиллюстрировать происходящее.Это можно упростить, удалив ADD
и используя LEA
для непосредственного добавления смещения к базовому указателю массива rec1
.Предпочтительно это было бы записано как:
lea eax, [rec1 + 2*(SIZEOF Records)]
ASSUME eax: ptr Records
Структуры в глобальной области действия
Если вы создаете структуры в глобальной области действия (не локальные в стеке), вы можете объявить и инициализировать ихтаким образом:
.DATA
rec2 Records <1,2,3,4>
Каждое поле в структуре разделено запятой.Структура будет выглядеть в сегменте _DATA
следующим образом:
Segment: _DATA DWORD USE32 00000010 bytes
0000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................
Данные печатаются в байтах.Каждый отдельный DWORD отображается с LSB (младший байт) до MSB (старший значащий байт).Если они отображаются как DWORD, они будут отображаться как
0000 00000001 00000002 00000003 00000004
Сноски