2016-05-10 4 views
3

2次元配列をx86アセンブリ言語でトラバースする方法を理解できません。私は少しの理解を欠いている。これは私がこれまで持っていたものです。2次元配列を横切る

の場合:「第二オペランドの違法レジスタEBX」

問題は、私が取得していますエラーが とも である「第二オペランドの非定数式」//offsetラインについては//offset//moving through array と行です次の行は、私はエラー 「EDXを:違法レジスタを第二オペランドに」取得

mov esi, dim 
    mul esi 
    mov eax, 0 // row index 
    mov ebx, 0 // column index 
    mov ecx, dim 
StartFor: 
    cmp ecx, esi 
    jge EndFor 
    lea edi, image; 
    mov edx, [eax *dim + ebx] // offset 
    mov dl, byte ptr [edi + esi*edx] // moving through array 
    mov edx, edi 
    and edx, 0x80 
    cmp edx, 0x00 
    jne OverThreshold 
    mov edx, 0xFF 


OverThreshold: 
    mov edx, 0x0 
+0

を実行していますか?実際の問題は何か説明できますか? – Blorgbeard

+0

それはちょうど無関係だった。私は私の問題をよりよく説明するために投稿を編集しました。申し訳ありません、新しいポスター – user6313136

+0

OKです。私はあなたがオフセットで多くの数学をすることはできないと思います。 IIRCでは、[REGISTER + CONSTANT_OFFSET]に制限されています。オフセットを手動で計算する必要があるかもしれません(ADDとMUL)。 – Blorgbeard

答えて

1

list of addressing modesを含め、タグのwikiを参照してください。 。

インデックスレジスタは定数でスケーリングできますが、アドレッシングモードでは2つのレジスタを乗算することはできません。あなたはそれを自分で行う必要があります(例えば、imul edx, esiの場合、列の数がコンパイル時定数でない場合、2の累乗の定数であればシフトできます。または[reg + reg*8]のようなスケールされたアドレッシングモードを使用することもできます) 。


再:編集:dimdim equ 8のようなものと定義されている場合*dimは動作するはずです。それが価値のある記憶場所であれば、それはうまくいかないでしょう。スケールファクタは、(マシンコードフォーマットオプションは限られている理由である2ビットのシフト・カウント、の余地がある。)1、2、4、または8であることができる


Iはまた、お勧めmovzxをロードして、dl(下位バイト)のみを書き込むのではなく、1バイトをedxにゼロ拡張します。実際には、あなたのコードはそれを必要としません。実際には、読み込んだ値をediで上書きします。私はバグだと思う。


あなたは代わりに内部ループの内側に掛けるの、あなただけの外側のループでcolumnsを追加することができ、もちろん

imul edx, esi 
test 0x80, byte ptr [edi + edx] ; AND, discard the result and set flags. 
jnz 

imul edx, esi 
mov dl, byte ptr [edi + edx] ; note the different addressing mode 
mov edx, edi     ; bug? throw away the value you just loaded 
and edx, 0x80     ; AND already sets flags according to the result 
cmp edx, 0x00     ; so this is redundant 
jne OverThreshold 

を置き換えることができます。これはStrength Reductionと呼ばれます。したがって、各行に沿ってp+=1を実行し、行ごとに移動するにはp+=colsを実行します。また、行と列を気にする必要がない場合は、2D配列のフラット・メモリーを繰り返し処理できます。

1

2次元配列は単なるバイトシーケンスの解釈です。アイテムをどの順序で保存するかを選択する必要があります。たとえば、"row-major order"を選択します。

私はバッファに一連の数字が入っているデモを書いています。次に、配列は一次元および二次元配列として解釈されます。

tx86。S

%define ITEM_SIZE 4 

    extern printf 

    section .bss 

cols: equ  3 
rows: equ  4 
buf: resd cols * rows 
c:  resd 1 
r:  resd 1 

    section .data 

fmt:  db "%-4d", 0   ; fmt string, '0' 
fmt_nl:  db 10, 0    ; "\n", '0' 

    section .text   ; Code section. 

    global main 

main: 
    push ebp 
    mov  ebp, esp 

    ; fill buf 
    mov  ecx, cols * rows - 1 
    mov  [buf + ITEM_SIZE], ecx 
.fill_buf: 
    mov  [buf + ecx * ITEM_SIZE], ecx 
    dec  ecx 
    jnz  .fill_buf 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; buf as 1-dimensional array 
; buf[c] = [buf + c * ITEM_SIZE] 
    xor  ecx, ecx 
    mov  [c], ecx 
.lp1d: 
    mov  ecx, [c] 

    push dword [buf + ecx * ITEM_SIZE] 
    push dword fmt 
    call printf 

    mov  ecx, [c] 
    inc  ecx 
    mov  [c], ecx 
    cmp  ecx, cols * rows 
    jl  .lp1d 

    ; print new line 
    push dword fmt_nl 
    call printf 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
; buf as 2-dimensional array 
; buf[r][c] = [buf + (r * cols + c) * ITEM_SIZE] 
    xor  ecx, ecx 
    mov  [r], ecx 
.lp1: 
    xor  ecx, ecx 
    mov  [c], ecx 
.lp2: 
    ; calculate address 
    mov  eax, [r] 
    mov  edx, cols 
    mul  edx   ; eax = r * cols 
    add  eax, [c] ; eax = r * cols + c 

    ; print buf[r][c] 
    push dword [buf + eax * ITEM_SIZE] 
    push dword fmt 
    call printf 

    ; next column 
    mov  ecx, [c] 
    inc  ecx 
    mov  [c], ecx 
    cmp  ecx, cols 
    jl  .lp2 

    ; print new line 
    push dword fmt_nl 
    call printf 

    ; next row 
    mov  ecx, [r] 
    inc  ecx 
    mov  [r], ecx 
    cmp  ecx, rows 
    jl  .lp1 


    mov  esp, ebp 
    pop  ebp   ; restore stack 

    xor  eax, eax ; normal exit code 
    ret 

(Linuxの場合)Buidling

nasm -f elf32 -l tx86.lst tx86.s 
gcc -Wall -g -O0 -m32 -o tx86 tx86.o 

`意味this`を修正する必要がない何

./tx86 
0 1 2 3 4 5 6 7 8 9 10 11 
0 1 2 
3 4 5 
6 7 8 
9 10 11