Adding 2D arrays in Assembly (x86) - arrays

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

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.

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

Related

Incrementing a pointer by 1 in an array of words: loading a word from half way between two words?

Consider the code below. If incrementing SI by 2 gives me the 2nd element of the array, what exactly would incrementing SI by 1 give me?
.data
var dw 1,2,3,4
.code
LEA SI,VAR
MOV AX,[SI]
INC SI
MOV AX,[SI]
Statement var dw 1,2,3,4 tells the assembler to statically define eight bytes in memory at the beginning of .data segment. Layout of the data bytes will be
|01|00|02|00|03|00|04|00|
and the first MOV AX,[SI] will load AL with 01 and AH with 00.
When you increment SI only by 1, the next MOV AX,[SI] will load AL with 00 and AH with 02.
If you want to keep loading AX with the whole 16bit words, increment SI by 2 (ADD SI,2).
You could also replace both MOV AX,[SI] and ADD SI,2 with one single instruction LODSW which does the same and occupies only one byte instead of five. In this case you should be sure to have the Direction flag reset (using the instruction CLD in the beginning of your program).

Increment a value at address of an arrray in NASM assembly

In my .bss section I declare array db 5, 4, 3, 2, 1
I then have a pointer ptr defined as %define ptr dword[ebp-8]
I would like to inc and dec this pointer at will to move from one element in the array to another, and then I would like to have to ability to inc the value in the array that the pointer is pointing to, and have this be updated in the array!
I move through the array with a loop in the form of:
mov ptr, array ; not in loop
mov ebx, ptr
mov al, [ebx]
inc ptr
How can I increment the value and then have it saved in the array instead of just some register as if I did inc al , can I do something like inc [ptr] (This doesnt work ofcourse). Is there a better way to approach this entirely?
Thanks
Edit:
I want my array to be something like 10, 8, 6, 5, 2 i.e increment each element by however many
In my .bss section I declare array db 5, 4, 3, 2, 1
This does not make sense.
By default .bss is defined as nobits, i. e. an uninitialized section (although a modern multi-user OS will initialize it with some values [usually zero] to prevent data leaks).
You probably meant to write .data section.
nasm(1) will issue an “ignored” warning about any db in a nobits section.
I then have a pointer ptr defined as %define ptr dword[ebp‑8]
I would like to inc and dec this pointer […]
No, you have a (case-sensitive) single-line macro ptr.
Any (following) occurrence of ptr will be expanded to dword[ebp‑8].
Use nasm ‑E source.asm (preprocess only) to show this.
[…] then I would like to have to ability to inc the value in the array that the pointer is pointing to […]
Your ptr macro says it’s pointing to a dword – a 32‑bit quantity – but your array consists of db – data Byte, 8‑bit quantity – elements.
This doesn’t add up.
I want my array to be something like 10, 8, 6, 5, 2 i.e increment each element by however many
Well, x + x = 2 × x, calculating the sum of a value plus the same value is the same as multiplying by two.
Any decent compiler will optimize multiplying by a constant factor 2ⁿ as a shl x, n.
Unless you need certain flags (the resulting flags of shl and add marginally differ), you can do something like
lea ebx, [array] ; load address of start of `array`
xor eax, eax ; eax ≔ 0, index in array starting at 0
mov ecx, 5 ; number of elements
head_of_loop:
shl byte [ebx + 1 * eax], 1 ; base address + size of element * index
add eax, 1 ; eax ≔ eax + 1
loop head_of_loop ; ecx ≔ ecx − 1
; if ecx ≠ 0 then goto head_of_loop
The constant factor in [ebx + 1 * eax] can be 1, 2, 4 or 8.
Note, the loop instruction is utterly slow and was used just for the sake of simplicity.

Insert values into array and display, nasm

First of all, this is a homework assignment.
I have a loop to get values of two digits individually, and joining them by doing a multiplication of the first digit by 10 and adding with the second digit to get an integer.
I'm doing all this and saving in my AL register, and now I want to insert that integer into an array and then scan that array and display those numbers.
How can I insert into vector and read from vector?
My array:
section .bss
array resb 200
My digit convert:
sub byte[digit_une], 30h
sub byte[digit_two], 30h
mov al, byte[digit_one]
mov dl, 10 ;dl = 10
mul dl ;al = ax = 10 * digit_one
add al, byte[digit_two] ;al = al + digit_two = digit_one * 10 + digit_two
"arrays", "vectors", etc... all that is higher level concept. The machine has memory, which is addressable by single byte, and what kind of logic you implement with your code, that's up to you. But you should be able to think about it on both levels, as single bytes in memory, each having it's own address, and fully understand your code logic, how it will arrange usage of those bytes to form "array of something".
With your definition of .bss sector you define one symbol/label array, which is equal to the address into memory where the .bss segment starts. Then you reserve 200 bytes of space, so anything else you will add after (like another label) will start at address .bss+200.
Let's say (for example) after loading your binary into memory and jumping to entry point, the .bss is at address 0x1000.
Then
mov dword [array],0x12345678
will store 4 bytes into memory at addresses 0x1000 .. 0x1003, with particular bytes having values 78 56 34 12 (little-endian break down of that dword value).
If you will do mov dword [array+199],0x12345678, you will write value 0x78 into the last officially reserved byte by that resb 200, and remaining 3 bytes will overwrite the memory at addresses .bss+200, .bss+201 and .bss+202 (probably damaging some other data, if you will put something there, or crashing your application, if it will cross the memory page boundary, and you are at the end of available memory for your process).
As you want to store N byte values into array, the simplest logic is to store first value at address array+0, second at array+1, etc... (for dword values the most logical way is array+0, array+4, array+8, ....).
i.e. mov [array+0],al can be used to store first value. But that's not very practical, if you are reading the input in some kind of loop. Let's say you want to read at most 200 values from user, or value 99 will end sooner, then you can use indexing by register, like:
xor esi,esi ; rsi = index = 0
mov ecx,200 ; rcx = 200 (max inputs)
input_loop:
; do input into AL = 0..99 integer (preserve RSI and RCX!)
...
cmp al,99
je input_loop_terminate
mov [array+rsi], al ; store the new value into array
inc rsi ; ++index
dec rcx ; --counter
jnz input_loop ; loop until counter is zero
input_loop_terminate:
; here RSI contains number of inputted values
; and memory from address array contains byte values (w/o the 99)
I.e. for user input 32, 72, 13, 0, 16, 99 the memory at address 0x1000 will have 5 bytes modified, containing (in hexa) now: 20 48 0D 00 10 ?? ?? ?? ....
If you are somewhat skilled asm programmer, you will not only index by register, but also avoid the hardcoded array label, so you would probably do an subroutine which takes as argument target address (of array), and maximum count:
; function to read user input, rsi = array address, rcx = max count
; does modify many other registers
; returns amount of inputted values in rax
take_some_byte_values_from_user:
jrcxz .error_zero_max_count ; validate count argument
lea rdi,[rsi+rcx] ; rdi = address of first byte beyond buffer
neg rcx ; rcx = -count (!)
; ^ small trick to make counter work also as index
; the index values will be: -200, -199, -198, ...
; and that's perfect for that "address of byte beyond buffer"
.input_loop:
; do input into AL = 0..99 integer (preserve RSI, RDI and RCX!)
...
cmp al,99
je .input_loop_terminate
mov [rdi+rcx], al ; store the new value into array
inc rcx ; ++counter (and index)
jnz .input_loop ; loop until counter is zero
.input_loop_terminate:
; calculate inputted size into RAX
lea rax,[rdi+rcx] ; address beyond last written value
sub rax,rsi ; rax = count of inputted values
ret
.error_zero_max_count:
xor eax,eax ; rax = 0, zero values were read
ret
Then you can call that subroutine from main code like this:
...
mov rsi,array ; rsi = address of reserved memory for data
mov ecx,200 ; rcx = max values count
call take_some_byte_values_from_user
; keep RAX (array.length = "0..200" value) somewhere
test al,al ; as 200 was max, testing only 8 bits is OK
jz no_input_from_user ; zero values were entered
...
For word/dword/qword element arrays the x86 has scaling factor in memory operand, so you can use index value going by +1, and address value like:
mov [array+4*rsi],eax ; store dword value into "array[rsi]"
For other sized elements it's usually more efficient to have pointer instead of index, and move to next element by doing add <pointer_reg>, <size_of_element> like add rdi,96, to avoid multiplication of index value for each access.
etc... reading values back is working in the same way, but reversed operands.
btw, these example don't as much "insert" values into array, as "overwrite" it. The computer memory already exists there and has some values (.bss gets zeroed by libc or OS IIRC? Otherwise some garbage may be there), so it's just overwriting old junk values with the values from user. There's still 200 bytes of memory "reserved" by resb, and your code must keep track of real size (count of inputted values) to know, where the user input ends, and where garbage data starts (or you may eventually write the 99 value into array too, and use that as "terminator" value, then you need only address of array to scan it content, and stop when value 99 is found).
EDIT:
And just in case you are still wondering why I am sometimes using square brackets and sometimes not, this Q+A looks detailed enough and YASM syntax is same as NASM in brackets usage: Basic use of immediates (square brackets) in x86 Assembly and yasm

Summing 2-dimensional array in EASy68K assembly

100x100 array A of integers, one byte each, is located at A. Write a program segment to compute the sum of the minor diagonal, i.e.
SUM = ΣA[i,99-i], where i=0...99
This is what I have so far:
LEA A, A0
CLR.B D0
CLR.B D1
ADDA.L #99, D0
ADD.B (A0), D1
ADD.B #1, D0
BEQ Done
ADDA.L #99,A0
BRA loop
There's quite many issues in this code, including (but not limited to):
You use 'Loop' and 'Done', but the labels are not shown in the code
You are adding 100 bytes in D1, also as a byte, so you are definitely going to overflow on the results (the target of the sum should at least be 16 bit, so .w or .l addressing)
I'm perhaps wrong but I think the 'minor diagonal' goes from the bottom left to the upper right, while your code goes from the top left to the bottom right of the array
On the performance side:
You should use the 'quick' variant of the 68000 instruction set
Decrement and branch as mentioned by JasonD is more efficient than add/beq
Considering the code was close enough from the solution, here is a variant (I did not test, hope it works)
lea A+99*100,a0 ; Points to the first column of the last row
moveq #0,d0 ; Start with Sum=0
moveq #100-1,d1 ; 100 iterations
Loop
moveq #0,d2 ; Clear register long
move.b (a0),d2 ; Read the byte
add.l d2,d0 ; Long add
lea -99(a0),a0 ; Move one row up and one column right
dbra d1,Loop ; Decrement d1 and branch to Loop until d1 gets negative
Done
; d0 now contains the sum

Displaying hexadecimal contents in assembly language

Hey guys I'm not sure if I'm going about all this the right way. I need the first 12 numbers of Fibonacci sequence to calculate which its doing already I'm pretty sure. But now I need to display the hexadecimal contents of (Fibonacci) in my program using dumpMem. I need to be getting a print out of : 01 01 02 03 05 08 0D 15 22 37 59 90
But I'm only getting: 01 01 00 00 00 00 00 00 00 00 00 00
Any tips or help is much much appreciated.
INCLUDE Irvine32.inc
.data
reg DWORD -1,1,0 ; Initializes a DOUBLEWORD array, giving it the values of -1, 1, and 0
array DWORD 48 DUP(?)
Fibonacci BYTE 1, 1, 10 DUP (?)
.code
main PROC
mov array, 1
mov esi,OFFSET array ; or should this be Fibonacci?
mov ecx,12
add esi, 4
L1:
mov edx, [reg]
mov ebx, [reg+4]
mov [reg+8], edx
add [reg+8], ebx ; Adds the value of the EBX and 'temp(8)' together and stores it as temp(8)
mov eax, [reg+8] ; Moves the value of 'temp(8)' into the EAX register
mov [esi], eax ; Moves the value of EAX into the offset of array
mov [reg], ebx ; Moves the value of the EBX register to 'temp(0)'
mov [reg+4], eax ; Moves the value of the EAX register to 'temp(4)
add esi, 4
; call DumpRegs
call WriteInt
loop L1
;mov ebx, offset array
;mov ecx, 12
;L2:
;mov eax, [esi]
;add esi, 4
;call WriteInt
;loop L2
;Below will show hexadecimal contents of string target-----------------
mov esi, OFFSET Fibonacci ; offset the variables
mov ebx,1 ; byte format
mov ecx, SIZEOF Fibonacci ; counter
call dumpMem
exit
main ENDP
END main
It seems to me that the problem here is with computing the Fibonacci sequence. Your code for that leaves me somewhat...puzzled. You have a bunch of "stuff" there, that seems to have nothing to do with computing Fibonacci numbers (e.g., reg), and others that could, but it seems you don't really know what you're trying to do with them.
Looking at your loop to compute the sequence, the first thing that practically jumps out at me is that you're using memory a lot. One of the first (and most important) things when you're writing assembly language is to maximize your use of registers and minimize your use of memory.
As a hint, I think if you read anything from memory in the course if computing the sequence, you're probably making a mistake. You should be able to do all the computation in registers, so the only memory references will be writing results. Since you're (apparently) producing only byte-sized results, you should need only one array of the proper number of bytes to hold the results (i.e., one byte per number you're going to generate).
I'm tempted to write a little routine showing how neatly this can be adapted to assembly language, but I suppose I probably shouldn't do that...
Your call to dumpMem is correct, but your program is not storing the results of your calculations at the correct location: the region you call "Fibonacci" remains initialized to 1, 1, and ten zeros. You need to make sure that your loop starts writing at the offset of Fibonacci plus 2, and moves ten times in one-byte increments (ten, not twelve, because you provided the two initial items in the initializer).
I'm sorry, I cannot be any more specific, as any question containing the word "Fibonacci" inevitably turns out to be someone's homework :-)

Resources