我有一个455字节的数组,包含13个,35字节的数据结构。
TurnTreeBuff: resb 455 ; TurnNum (1 byte) + MT (16 bytes) + PM (16 bytes)
; + BoardState (2 bytes) = 35 bytes * 13 turns = 455 bytes
最初,我认为我可以通过获取索引,乘以35并将其添加到TurnTreeBuff来访问特定的数据结构。但唯一有效的比例因子是1,2,4和8.
所以这个:
mov word [TurnTreeBuff+ebx*35],ax ; doesn't work
我可以通过将索引复制到另一个寄存器,然后将原始索引值左移5次并将其复制到其移位值3次来实现。但这看起来真的很麻烦。使用MUL命令看起来也很麻烦。我最好只将结构填充为64字节,所以它是2的倍数?这似乎也很浪费。
有更好的方法吗?
(使用NASM 2.10汇编32位二进制文件)
答案 0 :(得分:2)
* 35
确实无法编译:
mov word [TurnTreeBuff+ebx*35],ax ; doesn't work
处理器仅支持2的幂,仅支持前几个:x1,x2,x4和x8。因此,如果您的结构较大,则必须恢复使用乘法。
请注意,mul / imul速度非常快(即与add或sub一样快),所以你不必担心使用它,尽管如果一个简单的移位适用于你的结构(即你提到的64字节) )那么使用班次可能要好得多。 (如果你在下一行使用结果,mul / imul需要更长的时间。)
最后,来自奇数地址的32位进程中的mov不是一个好主意。所以你的结构的大小至少应该是4个字节的倍数,所以在你的情况下是36个字节。
P.S。你也可以使用这两个功能:所以你的索引(ebx)可以设置为0,9,18等,然后在指令中使用x4。然而,在地址字段中使用乘数减慢了一点......但是,如果你想玩得开心,你可以做Jester提出的将裸指数(0,1,2等)乘以的东西。使用lea ecx, [ebx * 8 + ebx]
乘以9,然后在另一个地址中使用x4。这么酷的事情的一大问题是:如果你的结构改变了它的大小......你必须重写很多代码。
现在,假设您循环遍历结构数组,我通常会做的是将结构的大小添加到索引中。例如:
mov ebx, TurnTreeBuff ; get address of first structure
.L1:
...
mov al, [ebx+0] ; TurnNum
mov eax, [ebx+1] ; MT 1st work (should be aligned...)
mov eax, [ebx+5] ; MT 2nd work
..
mov ax, [ebx+33] ; BoardState
...
add ebx, 35 ; again, use a multiple of your architecture: 16, 32, 64 bits...
loop .L1
现在mov
指令非常有效,因为你没有复杂的地址模式会减慢速度(假设你进行了数百万次访问,它会显示!)
请注意,应重新组织您的结构以使事情保持一致:
TurnNum (1 byte)
PAD (1 byte)
BoardState (2 bytes)
MT (16 bytes)
PM (16 bytes)
否则你会一直在不对齐的位置击中记忆,这最终会减慢速度。
P.S。 x2,x4和x8主要添加到处理器中,因此可以访问指针数组,还可以访问这些大小的结构。它在指令中仅使用2位,因此限制范围:1 <&lt;&lt; n其中n为0,1,2,3。