在程序集 (x86) 中添加 2D 数组



我必须添加两个 3*3 的单词数组并将结果存储在另一个数组中。这是我的代码:

.data 
a1 WORD 1,2,3
WORD 4,2,3
WORD 1,4,3
a2 WORD 4, 3, 8
WORD 5, 6, 8
WORD 4, 8, 9
a3 WORD DUP 9(0)
.code
main PROC
mov eax,0;
mov ebx,0;
mov ecx,0;
mov edx,0;
mov edi,0;
mov esi,0;
mov edi,offset a1
mov esi,offset a2
mov ebx, offset a3
mov ecx,LENGTHOF a2
LOOP:
mov eax,[esi]
add eax,[edi]
mov [ebx], eax
inc ebx
inc esi
inc edi
call DumpRegs
loop LOOP
exit
main ENDP
END main

但这总结了 a2 和 a1 的所有元素。如何逐行和逐列添加它们?我想在另一个一维数组中显示每行的总和的结果(列相同)。

a1 WORD 1,2,3
WORD 4,2,3
WORD 1,4,3

将编译为字节(六进制):

01 00 02 00 03 00 04 00 02 00 03 00 01 00 04 00 03 00

内存可以按字节寻址,所以如果你能找到上面的每个元素,并计算它从第一个元素的位移(第一个被 0 字节取代,即它的地址是a1+0),你应该看到一个模式,如何计算特定 [y][x] 元素的位移(x 是列号 0-2,y 是行号 0-2... 如果你决定这样做, 这取决于你,什么是列/行,但通常人们倾向于认为内存中的连续元素是"一行")。

注意基本类型的字节大小,你以各种方式在任何地方混合它,重读一些关于qword/dword/word/byte如何不同以及你需要如何调整指令以使用正确的内存大小的课程/教程,以及如何正确计算地址(以及eax的大小是多少以及如何使用它的较小部分)。

如果您自己无法弄清楚:

位移 = (y * 3+ x) * 2 => *2 因为元素是word,每个元素占用两个字节。 y * 3,因为单行有 3 个元素长。

例如,在可能实现的 ASM 指令中...

<块引用类>

如果 [x,y] 是 [eax,ebx],则此计算可以按lea esi,[ebx+ebx*2] ; esi = y*3|lea esi,[esi+eax] ; esi = y*3+x|mov ax,[a1+esi*2] ; loads [x,y] element from a1.

现在,如果您知道如何计算特定元素的地址,则可以在每个元素加载之前进行循环执行所有计算,或者只是在头脑中计算地址的差异并编写第一个元素的地址计算(行/列的开头),然后mov+ 2xadd,为接下来的两个元素提供硬编码偏移量(为 3 个元素制作循环比编写展开代码不带循环),并对所有三列/行重复此操作并存储结果。

顺便说一句,那call DumpRegs...没有产生您所期望的效果?调试代码的方式有点乏味,可能值得花点时间让一些调试器工作。


我情不自禁,但要写它,因为它是如此有趣的短代码段,但如果你只是复制它,而不是将其解剖到原子并完全理解它是如何工作的,你以后会后悔的):

column_sums: DW 0, 0, 0
row_sums:    DW 0, 0, 0
...
; columns sums
lea   esi,[a3]    ; already summed elements of a1 + a2
lea   edi,[column_sums]
mov   ecx,3       ; three columns to sum
sum_column:
mov   ax,[esi]    ; first element of column
add   ax,[esi+6]  ; 1 line under first
add   ax,[esi+12] ; 2 lines under
mov   [edi],ax    ; store result
add   esi,2       ; next column, first element
add   edi,2       ; next result
dec   ecx
jnz   sum_column
; rows sums
lea   esi,[a3]    ; already summed elements of a1 + a2
lea   edi,[row_sums]
mov   ecx,3       ; three rows to sum
sum_row:
mov   ax,[esi]    ; first element of row
add   ax,[esi+2]  ; +1 column
add   ax,[esi+4]  ; +2 column
mov   [edi],ax    ; store result
add   esi,6       ; next row, first element
add   edi,2       ; next result
dec   ecx
jnz   sum_row
...

(没有调试它,所以错误是可能的,再加上这期望 A3 包含正确的元素总和,你的原始代码不会产生,所以你必须先修复它......这段代码确实包含了很多提示,如何解决原版的每个问题)

现在我为从你那里夺走写这篇文章的乐趣而感到内疚......没关系,我相信你可以找到更多的任务来练习这个。问题是,你是否掌握了它的原理。如果没有,请询问哪个部分令人困惑以及您目前如何理解它。

不不不不 这个顶级答案太可怕了...... 首先,我们有一个很大的内存访问问题

将数组访问权限更改为:"memtype ptr [memAddr + (index*memSize)]">

():必须在 dword 大小的寄存器中我很确定,我知道一个事实,如果它在寄存器中,它必须是 dword 大小,idk 如果你可以做一个表达式,就像我使用 * 编写它的方式一样......

内存类型 = 字节,字(默认情况下一切都是 dword)

索引 = 数组中的 POS

内存大小:字节 = 1,字 = 2,字 = 4

如果不这样做,所有内存访问都将是 DWORD 类型,并且您可能会越界访问,并且最肯定的是,您将无法获得正确的值,因为它混合了不同事物的内存( dword = 单词 + 单词,所以当你只想要单词时,你必须做一个单词 ptr, 其他iwse它会给你单词+单词,谁知道这个值会是什么)

你的类型大小是word,你也试图把它放在dword寄存器中,你可以做EAX(ax)的字大小寄存器,或者如果你想使用整个寄存器,你可以做movzx把它放在EAX中

接下来以不同格式访问数组

我的意思是,如果您进行了任何基本的编码,这部分应该相当明显,我认为您的最大错误是主要问题

它只是一个普通的数组索引:0->?

所以你只需访问地址 [行 * colSize + col]

你推进循环的方式应该是相当不言自明

最新更新