x86程序集在堆栈上创建字符串和数组

时间:2017-05-28 21:49:48

标签: assembly x86

我对如何使用x86程序集在堆栈上创建字符串和空数组感到困惑。

要创建一个字符串,我有......

PUSH .ascii "myString"

我对如何创建一个空数组感到困惑。我理解创建一个元素为0的数组,看起来像......

PUSH 0

不确定如何创建一个空数组,我不确定这是否是在堆栈上创建字符串的正确方法。

1 个答案:

答案 0 :(得分:3)

你可以把它分成3个问题 - 在堆栈上分配(未初始化的)空间,释放空间,然后在分配时初始化/使用空间。

要在堆栈上创建(未初始化的)空间,只需从堆栈指针中减去所需的字节数。例如,要为20(4字节)整数数组分配空间,可以执行sub esp,20*4

要释放堆栈中的空间,请执行与分配它的操作相反的操作。例如,要释放20(4字节)整数数组的空间,可以执行add esp,20*4

要初始化或使用空间,您只需要确定地址即可。这可以是esp

例如,要分配20(4字节)整数的数组,请将数组中的第10个整数设置为0x1234567,然后释放您可以执行的数组:

    sub esp,20*4
    mov dword [esp+9*4],0x1234567
    add esp,20*4

您可以将多个分配组合在一起。例如:

    sub esp,124 + 20*4                  ;Allocate space for a 20 integer array and a 124 character string
    mov dword [esp+9*4 + 124],0x1234567 ;Set 10th element (being careful to skip over the space for the string)
    add esp,124                         ;Free space for the string
    mov dword [esp+9*4],0x89ABCDEF      ;Set 10th element again
    add esp,20*4                        ;Free space for the array

您还可以将分配与初始化相结合。例如:

    push dword 3     ;Allocate "array[3]" and set it to 3
    push dword 2     ;Allocate "array[2]" and set it to 2
    push dword 1     ;Allocate "array[1]" and set it to 1
    push dword 0     ;Allocate "array[0]" and set it to 0
    mov [esp+1*4],5  ;Change "array[1]" to 5
    add esp,4*4      ;Free the array

你可以混合两者。例如:

    push dword 3     ;Allocate "array[3]" and set it to 3
    push dword 2     ;Allocate "array[2]" and set it to 2
    sub esp,2*4      ;Allocate "array[0]" and "array[1]" without initialising them
    mov [esp+1*4],5  ;Change "array[1]" to 5
    add esp,4*4      ;Free the array

然而,"分配期间的初始化"当尺寸与堆叠上的东西的默认大小不匹配时,会变得有点棘手。例如,如果它是一个16位整数数组,您可以这样做:

    push dword (3 << 16) | 2  ;Allocate "array[3]" and "array[2]" and set them
    sub esp,2*2               ;Allocate "array[0]" and "array[1]" without initialising them
    mov [esp+1*2],5           ;Change "array[1]" to 5
    add esp,4*2               ;Free the array

字符串只是数组(字符数组)。例如:

    push dword 'n' | ('g' << 8) | ('.' << 16) | (0 << 24)   ;Allocate space for last 4 chars and set them to "ng.\0"
    push dword 'S' | ('t' << 8) | ('r' << 16) | ('i' << 24) ;Allocate space for middle 4 chars and set them to "Stri"
    push dword 'T' | ('h' << 8) | ('e' << 16) | (' ' << 24) ;Allocate space for first 4 chars and set them to "The "
    mov byte [esp+14],'!'                                   ;Change the string from "The String.\0" to "The String!\0"
    add esp,16*1                                            ;Free the string

请注意,大多数汇编程序提供了将字符组合成更大(例如32位)数字的简写,使事情变得更容易。例如:

    push dword "ng."      ;Allocate space for last 4 chars and set them to "ng.\0"
    push dword "Stri"     ;Allocate space for middle 4 chars and set them to "Stri"
    push dword "The "     ;Allocate space for first 4 chars and set them to "The "
    mov byte [esp+14],'!' ;Change the string from "The String.\0" to "The String!\0"
    add esp,16*1          ;Free the string

请注意,您无法执行push dword "The String."。在这种情况下,汇编器会将字节转换为一个巨大的88位整数(使用相同的value = (char0 << 0) | (char1 << 8) | (char2 << 8*2) | (char3 << 8*3) ... | (charN << 8*N)逻辑),并且得到的88位整数不符合push指令的32位放在堆栈上。

您可以从其他地方的数据初始化堆栈上的字符串。例如:

    section .rodata
defaultString:  db "The String.", 0
.end:
    section .text

    sub esp,16*1                              ;Allocate space for 16 characters
    mov edi,esp                               ;edi = address of the destination string
    mov esi,defaultString                     ;esi = address of the source string
    mov ecx,defaultString.end - defaultString ;ecx = size of the string
    cld
    rep movsb                                 ;Initialise the string (by copying it from defaultString)

    mov byte [esp+14],'!'                     ;Change the string from "The String.\0" to "The String!\0"
    add esp,16*1                              ;Free the string

通过从只读数据复制&#34;初始化&#34;技术适用于任何大小的数组(和字符串)。