如何在MASM程序集中初始化本地结构

时间:2019-06-08 13:28:56

标签: assembly struct x86 masm

我想在堆栈上初始化一个本地结构。

Records         STRUCT
data1           DWORD   ?
data2           DWORD   ?
data3           DWORD   ?
data4           DWORD   ?
Records         ENDS

                .CODE
main:
                mov     ebp, esp
                sub     esp, SIZEOF Records

如何创建struct Records的命名实例,然后可用于初始化数据成员。我想将struct指令与点运算符一起使用,而不要与指针相加。

我从为结构分配空间开始。那怎么了?

1 个答案:

答案 0 :(得分:3)

我将使用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指令来创建类型数组。然后,您可以初始化数组中各个记录的元素。此示例在堆栈上为名为Records的4 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

我将LEAADD分成了单独的指令,以更好地说明正在发生的事情。可以通过删除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

脚语

  • 1 我在汇编文件的顶部使用了.MODEL指令来默认采用 C 样式调用约定:

    .386
    .model flat, C