将数组初始化为程序集中的特定值(x86)

时间:2017-04-15 20:13:42

标签: assembly x86 nasm

我想在程序集中使用特定值初始化数组。我尝试先在循环中进行,但在数组中得到了垃圾。然后我尝试手动完成并获得相同的垃圾。我想让数组重复0 1 2次。这是我尝试过的一些示例代码。

这是我手动加载数组的尝试。第一个值加载就好了。然而,当我在GDB中检查它时,第二个值加载垃圾。

sub esp, 260
mov [ebp - 12], dword -1
mov [ebp - 16], byte 0
mov [ebp - 17], byte 1
mov [ebp - 18], byte 2
mov [ebp - 19], byte 0
mov [ebp - 20], byte 1
mov [ebp - 21], byte 2
mov [ebp - 22], byte 0
mov [ebp - 23], byte 1
mov [ebp - 24], byte 2
mov [ebp - 25], byte 0

这是我尝试自动完成的。

    sub esp, 260
    mov [ebp - 12], dword -1

again:
    add [ebp - 12], dword 1
    lea eax, [ebp - 16]
    sub eax, [ebp - 12]
    mov [eax], byte 0

    add [ebp - 12], dword 1
    lea eax, [ebp - 16]
    sub eax, [ebp - 12]
    mov [eax], byte 1

    add [ebp - 12], dword 1
    lea eax, [ebp - 16]
    sub eax, [ebp - 12]
    mov [eax], byte 2

    cmp [ebp - 12], dword 255
    jne again
    jmp elsewhere

使用NASM,x86-32,Intel语法。

编辑:当我转换此代码以将数组值存储为DWORD而不是字节时,两种方法都有效。这是为什么?

5 个答案:

答案 0 :(得分:1)

使用NASM,您可以使用times前缀轻松初始化重复数据。例如,要按照问题中的要求重复序列“0 1 2”n次,您可以执行类似以下操作:

section .data

    my_array: times n db 0, 1, 2 

只需将n替换为您想要的常量值即可。有关times前缀的详细信息,请参阅NASM Manual

答案 1 :(得分:1)

假设您希望字节数组占用从 [EBP-260][EBP-16] 的堆栈空间,它将容纳 260 - 16 + 1 = 245 个字节。查看您的示例,我发现最后一个元素是 0。考虑到元素数不能被 3 整除,我可以算出第一个元素必须是 1

(1, 0) followed by 81 times (2, 1, 0)

从循环中取出前两个元素创造了一个机会,可以用几个嵌套循环编写一个有效的解决方案:

  push ebp
  mov  ebp, esp
  sub  esp, 260

  ; Initializing the array with 245 bytes (2 + 81 * 3)
  mov  edx, esp
  mov  eax, 1
  mov  [edx], ax         ; (1, 0)
  inc  eax               ; 1 -> 2
  add  edx, eax
  mov  ecx, 81           ; 81 triplets (2, 1, 0)
Outer:
Inner:
  mov  [edx], al
  inc  edx
  dec  eax               ; 2 -> 1 -> 0 -> -1
  jns  Inner
  add  eax, 3            ; -1 -> 2
  dec  ecx
  jnz  Outer
  mov  byte [edx], -1    ; (*)

但是如果我们一次写入 32 位,我们可以做得更好。内存中的数组表现为:

| EBP-260 == ESP                                      | EBP-20    | EBP-16
v                                                     v           v
1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, ... , 1, 0, 2, 1, 0
\--------/  \--------/  \--------/  ^               ^ \--------/  -
    EAX         EBX         ECX     | repeats       |     EAX     BL
                                    | from here on  |     left-overs

在 245 字节的数组中,这 3 个双字(12 个字节)可以重复 20 次。并且因为数组开始的地址 (ESP) 是双字对齐的,所以我会将重复放在低端。

  push ebp
  mov  ebp, esp
  sub  esp, 260
  mov  byte [ebp-15], -1 ; (*)

  ; Initializing the array with 245 bytes (20 * 12 + 5)

  mov  eax, 01020001h    ; (1, 0, 2, 1)
  mov  ebx, 00010200h    ; (0, 2, 1, 0)
  mov  ecx, 02000102h    ; (2, 1, 0, 2)
  lea  edx, [ebp-32]
  mov  [ebp-16], bl
  mov  [ebp-20], eax
More:
  mov  [edx+8], ecx
  mov  [edx+4], ebx
  mov  [edx], eax
  sub  edx, 12
  cmp  edx, esp
  jae  More

(*) 如果这个 -1 的预期用途是终止列表,那么在 [ebp-15] 处使用 byte -1[ebp-12] 处的 dword -1

答案 2 :(得分:0)

这是我得到的:

;ecx = how much values  ;ds:edi = destination
function:

    pushad                    ;push all 32bit registers to stack

    xor eax,eax               ;clear eax

    function_loop:

        push eax              
        mov ebx,0x00000003    ;we divide by 3

        xor edx,edx           ;clear edx 

        div ebx               ;this stores the remainder of eax/0x03 in edx
        mov DWORD [edi],edx   ;move it to your array

        pop eax               ;we dont need the result of the division

        inc eax 
        add edi,4             ;increment pointer 4 bytes because 4 bytes are one DWORD

    loop function_loop        ;loop til ecx is 0

    popad                     ;pop all 32bit registers
ret

我把它写出了我的头,所以请报告它的任何错误

但你需要做的就是递增一个寄存器并在递增寄存器上用3进行模运算,然后得到0,1,2模式

确保在desitnation上有足够的空间来存储所有n个值

答案 3 :(得分:0)

这可能会引发更多关于在堆栈上分配字节或双字的想法。

您可能希望构建一个可能经常使用的个人函数或宏库,或者找到一些其他库来包含%。

您可以用字节,双字或其他大小解释数组数据,就像处理所有数据元素一样。您必须始终注意数组元素的大小(例如,1对4个字节..)。我会留下任何对齐问题给你解决。

section .data
        _len equ 64
section .text
        %macro mod 2
        mov eax, %1
        mov ebx, %2
        xor edx, edx
        div ebx                 ; div/mul are very slow; but ok for small loops
        mov eax, edx            ; return eax if you wish
        %endmacro

        global _start
_start:
        nop

        sub esp, _len                   ; 

        mov ecx, 1
        L1:

        mod ecx, 3                      ; n mod 3 
        mov byte [esp+ecx], al

        inc ecx
        cmp ecx, _len                   ; array size
        jb L1

        add sp, _len

_exit:
        mov eax, 1
        mov ebx, 0
        int 0x80

GDB示例x / 64d $ esp using next ....

(gdb) 
0xffffd180:     0       1       2       0       1       2       0       1
0xffffd188:     2       0       1       2       0       1       2       0
0xffffd190:     1       2       0       1       2       0       1       2
0xffffd198:     0       1       2       0       1       2       0       1
0xffffd1a0:     2       0       1       2       0       1       2       0
0xffffd1a8:     1       2       0       1       2       0       1       2
0xffffd1b0:     0       1       2       0       1       2       0       1
0xffffd1b8:     2       0       1       2       0       1       0       0
31      v eax, 1
(gdb) 
0xffffd180:     0       1       2       0       1       2       0       1
0xffffd188:     2       0       1       2       0       1       2       0
0xffffd190:     1       2       0       1       2       0       1       2
0xffffd198:     0       1       2       0       1       2       0       1
0xffffd1a0:     2       0       1       2       0       1       2       0
0xffffd1a8:     1       2       0       1       2       0       1       2
0xffffd1b0:     0       1       2       0       1       2       0       1
0xffffd1b8:     2       0       1       2       0       1       0       0
25      cx, 3                   ; n mod 3 
(gdb) 
0xffffd180:     0       1       2       0       1       2       0       1
0xffffd188:     2       0       1       2       0       1       2       0
0xffffd190:     1       2       0       1       2       0       1       2
0xffffd198:     0       1       2       0       1       2       0       1
0xffffd1a0:     2       0       1       2       0       1       2       0
0xffffd1a8:     1       2       0       1       2       0       1       2
0xffffd1b0:     0       1       2       0       1       2       0       1
0xffffd1b8:     2       0       1       2       0       1       0       0
27      cx
(gdb) 
0xffffd180:     0       1       2       0       1       2       0       1
0xffffd188:     2       0       1       2       0       1       2       0
0xffffd190:     1       2       0       1       2       0       1       2
0xffffd198:     0       1       2       0       1       2       0       1
0xffffd1a0:     2       0       1       2       0       1       2       0
0xffffd1a8:     1       2       0       1       2       0       1       2
0xffffd1b0:     0       1       2       0       1       2 

  0   

答案 4 :(得分:0)

可以使用gas(at&t语法)

array:
  .space size, value

您也可以使用 .skip,它与 .space 相同。