遍历二维数组

5
我不太理解如何在x86汇编语言中遍历二维数组。我缺少一些理解。以下是我的代码:
问题在于带有//offset//moving through array的行。 对于//offset行,我得到的错误是“second operand中的非常量表达式”,也出现了“ebx:second operand中的非法寄存器”。 对于下一行,我得到的错误是“edx:second operand中的非法寄存器”。
    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

“need to fix this” 意思是什么?你能解释一下实际的问题是什么吗? - Blorgbeard
那只是一些无关的东西。我编辑了我的帖子以更好地解释我的问题。抱歉,我是新手。 - user6313136
好的。我认为你不能在偏移量中进行太多的数学计算。如果我没记错的话,你只能使用[寄存器+常量偏移量]。你可能需要手动计算偏移量(ADD和MUL),或者随着进程的进行跟踪它。 - Blorgbeard
啊,在这里 - 你可以乘以一个常数,但你不能将两个寄存器相乘。 - Blorgbeard
@Blorgbeard 好的,我将它更改为mov edx,eax*dim(作为参数的行/列数)+ ebx。仍然出现相同的错误。 - user6313136
2个回答

1

请查看标签维基,其中包括地址模式列表

您可以通过常数来扩展索引寄存器,但是您无法在寻址模式中乘以两个寄存器。如果列数不是编译时常量,则必须自行完成此操作(例如使用imul edx,esi)。如果它是2的幂次方常数,则可以进行移位,甚至使用缩放的寻址模式,例如[reg + reg*8])。


关于编辑:如果dim定义为类似dim equ 8的内容,那么*dim应该可以工作。如果它是保存值的内存位置,那么当然不能工作。比例因子可以为1、2、4或8。(机器码格式有2位移位计数的空间,这就是选项受限的原因。)


我建议使用movzx进行加载,将一个字节零扩展到edx中,而不仅仅是写入dl(低字节)。实际上,您的代码不需要这样做。事实上,您覆盖了使用edi加载的值。我认为这是一个错误。
你可以替换


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

使用

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

当然,你可以在内部循环中进行乘法运算,也可以在外部循环中添加columns,这被称为Strength Reduction。所以你需要在每一行中执行p+=1,并且通过p+=cols来遍历每一行。或者,如果不需要关心行和列,你可以直接迭代二维数组的平面存储。

1

一个二维数组只是一系列字节的解释。你需要选择以哪种顺序存储项目。例如,你可以选择"行主序"

我写了一个演示程序,其中缓冲区填充了一系列数字。然后将该序列解释为单维和双维数组。

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上)
nasm -f elf32 -l tx86.lst tx86.s
gcc -Wall -g -O0 -m32 -o tx86 tx86.o

Running

./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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接