我想在程序集中使用特定值初始化数组。我尝试先在循环中进行,但在数组中得到了垃圾。然后我尝试手动完成并获得相同的垃圾。我想让数组重复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而不是字节时,两种方法都有效。这是为什么?
答案 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 相同。