'Adding 2D arrays in Assembly (x86)

I have to add two 3*3 arrays of words and store the result in another array. Here is my code:

.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

But this sums all elements of a2 and a1. How do I add them row by row and column by column? I want to display the result of sum of each row in another one dimensional array(Same for columns).



Solution 1:[1]

The

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

will compile as bytes (in hexa):

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

Memory is addressable by bytes, so if you will find each element above, and count it's displacement from the first one (first one is displaced by 0 bytes, ie. it's address is a1+0), you should see a pattern, how to calculate the displacement of particular [y][x] element (x is column number 0-2, y is row number 0-2... if you decide so, it's up to you, what is column/row, but usually people tend to consider consecutive elements in memory to be "a row").

Pay attention to the basic types byte size, you are mixing it everywhere in every way, reread some lesson/tutorial about how qword/dword/word/byte differ and how you need to adjust your instructions to work with correct memory size, and how to calculate the address correctly (and what is the size of eax and how to use smaller parts of it).

If you have trouble to figure it on your own:

displacement = (y * 3 + x) * 2 => *2 because element is word, each occupies two bytes. y * 3 because single row is 3 elements long.

In ASM instructions that may be achieved for example...

If [x,y] is [eax,ebx], this calculation can be done as 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.

Now if you know how to calculate address of particular element, you can do either loop doing all the calculation ahead of each element load, or just do the math in head how the addresses differ and write the address calculation for first element (start of row/column) and then mov + 2x add with hardcoded offsets for next two elements (making loop for 3 elements is sort of more trouble than writing the unrolled code without loop), and repeat this for all three columns/rows and store the results.

BTW, that call DumpRegs ... is not producing what you expected? And it's a bit tedious way to debug the code, may be worth to spend a moment to get some debugger working.


Couldn't help my self, but to write it, as it's such funny short piece of code, but you will regret it later, if you will just copy it, and not dissect it to atoms and understand fully how it works):

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

(didn't debug it, so bugs are possible, plus this expect a3 to contain correct element sums, which your original code will not produce, so you have to fix it first ... this code does contain lot of hints, how to fix each problem of original)

Now I feel guilty of taking the fun of writing this from you... nevermind, I'm sure you can find few more tasks to practice this. The question is, whether you got the principle of it. If not, ask which part is confusing and how you currently understand it.

Solution 2:[2]

no no no no this top answer so terrible... first we have a big memory access issue

change ur array access to be: "memtype ptr [memAddr + (index*memSize)]"

(): must be in a register of dword size im pretty sure, i know for a fact if its in a register it must be dword size, idk if u can do an expression like the way ive written it using the *...

memtype = byte, word (everything is a dword by default)

index = pos in array

memSize: byte = 1, word = 2, dword = 4

IF YOU DO NOT DO THIS, ALL MEMORY ACCESS WILL BE OF TYPE DWORD, AND YOU MIGHT ACCESS OUT OF BOUNDS AND MOST DEFINETELY YOU WILL NOT GET THE CORRECT VALUES BECAUSE IT IS MIXING MEMORY OF DIFFERENT THINGS( dword = word + word, so when u only want the word u have to do a word ptr, otheriwse it will give u the word+word and who knows what that value will be)

your type size is word, and your also trying to put it in a dword register, u can do the word size register of eax(ax) instead, or u can do movzx to place it in eax if you want to use the whole register

next accessing the array in different formats

i mean this part should be fairly obvious if you have done any basic coding, i think ur top error is the main issue

its just a normal array indexs: 0->?

so then you just access the addr [row * colSize + col]

and the way u progress your loop should be fairly self explanatory

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2