どのように...インデックス位置配列の... ESIとしてのポインタ
最初に配列の定義が重要です。連続する要素からなる単純なフラット配列特定の要素のインデックスはあなたが関与する2つのポインタからそれを計算する逆にすることができますEDI
アドレスが指す取得するには(これはESI
でまだ元の開始のアレイポインタが必要です!):
mov eax,edi
sub eax,esi ; eax = (element_pointer - array_pointer)
; divide eax by <size_of_element>
; for example your OP code example suggest
; the array element size is DWORD = 4B
; then the division/4 can be done simply:
; shr eax,2
; for byte arrays there's no need to divide the address
; difference, eax already contains index, as BYTE size = 1B
; for other element sizes, which are *not* power-of-two
; (you can't divide the difference by simply shifting it right)
; it may be more efficient to address them through separate index
; or do the: imul/mul (1/el_size) || idiv/div el_size
; (when there's no way to avoid it)
; after division the eax contains 0, 1, ... index.
場合、要素の大きさ(2の累乗ではない)、または構造が簡単ではない(リンクされたリストなので、2つのポインタの違いが要素のインデックスと相関しない)場合、インデックスを個別にカウントすることができます。それでも、インデックスを取得するたびにインデックスのmul element_size
を避けるため、2つを混在させる価値があるかもしれません。したがって、ポインタを使ってアドレッシングし、インデックスを必要とするものに対してのみ使用されるインデックスを個別にカウントしてください。
また、1
からインデックスを付けることもできますが、プログラマー以外の人間が出力しない限り、避けることにします。ほとんどのASM/C/C++プログラマは、インデックス開始が当然0
how-pointer-mathは私の最初の例で動作します)。
; stolen from Toommylee2k, then modified to focus on my explanation
xor ebx,ebx ; first index will be 1 (!)
; so I initialized ebx = 1 - 1 = 0, because
; I will increment it at beginning of loop
; for indexing from 0 the ebx should be initialized to -1
loop_start:
; update index first, so you can't miss it when branching later
lea ebx,[ebx+1] ; ebx = ebx+1 without flags modification
; since *here* "ebx" works as "index", contains "1" for first item
; do whatever you want with pointers, like "esi" in your sample code
; ...
; move to next element of array (avoids multiplication)
add esi,size_of_element
; although `imul` on modern CPU will perform quite close to `add`
; so when multiplication is unavoidable, go for it.
; the division on the other hand still costs very likely more
; than having separate register/variable for index counting
; loop till ecx is zero (in much faster way than "loop")
dec ecx
jnz loop_start
; "loop" is very slow due to historic reasons, to improve compatibility
そして最後の伸長、素子サイズはの一つである[1、2、4、8]、あなたはで動作するように拡張されたx86のアドレッシング・モードを使用することができます "0、1、..."純粋なポインタの代わりにインデックス:
mov ebx,7 ; index "7" = 8th element of array
lea esi,[array_of_words] ; array pointer
; addressing through index, supported directly by CPU for size 2
mov ax,[esi + ebx*2] ; complex x86 addressing allows this
; here ax = 8
...
.data
array_of_words:
dw 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
ループ内のインデックスを使用すると、これが最適な解決策になる可能性があります。要素のインデックスがまれにしか必要ない場合は、通常は純粋なポインタが最適です。
Count。 'esi'でやっているのと同じですが、0または1から始めて1ずつ進みます。 –
配列の定義方法は表示されません。アセンブリの定義では、データの構造はコードそのものよりも重要な場合があります。定義がなければ、あなたのコードがそのまま動作するかどうかを知ることは難しく、あなたに答えるために変更することも、すでにバグを含んでいるかどうかを知ることもできます(例えば、 'mov eax、[esi]'は疑わしいです。 esi、4'それは大丈夫です)。 [mcve]はアセンブリで非常に重要です。 – Ped7g
しかし、もう一度考えてみると、この問題は、コードなしではもっと意味があります。解決法のコードよりもメソッド/原則、解決方法を尋ねるなら、宿題は有効です。 – Ped7g