Array manipulation 

Not like high level languages, Assembly language has no notion of an array at all. Arrays like variables are treated as a block of memory that could be alloted with a single directive, where the first element is given a label.

The array as the most important and most general data structure has the following properties:

All elements must be the same size. The array is an homogeneous data structure.
The size of an array is fixed. The number of elements is fixed.
A label (address) is tied to the first element of the array.
Traversing each element of an array needs an index or indices and the label as the array's name.

Array Declaration

With reference to the above properties, in assembly language to declare an array it requires:

A label name,
The number of elements,
The size of each element,
The initial value of each element.

 Example: A declaration of a ten-element array of byte-sized elements
table1 db 10 dup(0)

Each element is initialized to be zero. Remember that there is no interpretation in Assembly language.

 Example: A declaration of a ten-element array of word-sized elements
array1dw 12EFh, 2500, 4500, 0
 dw 6 dup(2)

Traversing One-dimensional Array

To access every element of an array, we have to know the address of that element. Because all elements have the same size, the address of an element of the array can be formulated as:

byte address of element i = starting address + size-of-element * i

It presumes that the first element of the array is indexed 0.

The size-of-element is the number of bytes in a single array element.

If the size-of-element is either 1, 2, 4, or 8, the implementation of the formula is very straighforward using 32-bit memory addressing mode.

To access the sixth element of table1:
 mov AL, [table1 + 5]	; AL = table1[5]
 mov ESI, 5
 mov BYTE PTR [table1 + SI], 3	; table1[5] = 3
 mov BL, [table1 + ESI*1]	; BL = table1[5]

To access the fifth element of array1:
 add WORD PTR [array1 + 8], 10	; array1[4] = array1[4] + 10
 mov BX, 8
 sub [array1 + BX], CX		; array1[4] = array1[4] - CX
 mov ECX, 4
 mov [array1 + ECX*2], AX	; array1[4] = AX

Two-dimensional Arrays

Two or higher dimensional arrays are treated as the same as simple one-dimensional arrays.

To declare the array M[rows][cols] of byte-sized elements,

Calculate the number of elements in the array: number-of-elements = rows * cols
Then you may declare as:
M db number-of-elements DUP(0)
M db rows DUP( cols DUP(0))
M db cols DUP( rows DUP(0))

Note that those above declaration are equivalent. There is no distinction for the dimensions of the array.

To declare the array var2d[8][9] of double-word-size elements,

var2d dd 72 DUP(0)
var2d dd 8 DUP(9 DUP(0))
var2d dd 0, 0, 0, 69 DUP(0)

Storage Order

As mentioned before that memory is organized as a one-dimensional array. Two-dimensional arrays must be treated as simple one-dimensional arrays. Then, in assembly language to declare two-dimensional arrays, we have to arrange the arrays as one-dimensional arrays.

To do this, we have to know how to organize all elements of an array. There are two different ways to organize the elements of two-dimensional array:

Row-major order:The array is organized as a sequence of ROWS
Column-major order:The array is organized as a sequence of COLUMNS

 Example: An array organized as row-major order and column-major order

Suppose the array size is 2 * 3:

(0,0)(0,1)(0,2)
(1,0)(1,1)(1,2)

The array stored in row-major order:

(0,0)
(0,1)
(0,2)
(1,0)
(1,1)
(1,2)
Lower address
 
 
 
 
Higher address

The array stored in column-major order:

(0,0)
(1,0)
(0,1)
(1,1)
(0,2)
(1,2)
Lower address
 
 
 
 
Higher address

Address Calculation

Assume the row and column index starts from 0. The general formula to calculate the byte address of the element [a, b] can be expressed as:

 Row-major order
Starting Address + Size-of-element * ( a * number-of-columns + b)

 Column-major order
Starting Address + Size-of-element * ( b * number-of-rows + a)

 Example: Translating Java-like HLL into AL
Java-like HLLAssembly Language
int M[][] = new int[9][4];
 
M[2][3] = 7;
.DATA
M dd 9 DUP(4 DUP(0))
; The size-of-element = 4 bytes, because in Java int = 4 bytes
; a = 2, b = 3, number-of-columns = 4 ; Then, the offset of M[3][4] is
; 4 * ( 2 * 4 + 3 ) = 44 .CODE
 
mov M[44], 7

 Example: More about translating Java-like HLL into AL
Java-like HLLAssembly Language
int M[][] = new int[9][4];
 
for(int j=0; j<9; j++)
M[j][3] = 7;
.DATA
M dd 9 DUP(4 DUP(0))
; The size-of-element = 4 bytes, because in Java int = 4 bytes
; a = j, b = 3, number-of-columns = 4 ; Then, the offset of M[3][4] is
; 4 * ( j * 4 + 3 ) = 4*(4*j) + 12 .CODE
 
mov ECX, 0
@1: cmp ECX, 9
jae @2
mov EAX, ECX
shl EAX, 4
mov M[EAX + 12], 0
inc ECX
jmp @1
@2: ...

In above example, A more efficient solution but possibly less clear is

More efficient solution
.DATA
M dd 9 DUP( 4 DUP(0))
 
.CODE
	mov ECX, 0
	mov EAX, 0
L1:	cmp ECX, 9
	jae L2
	mov M[EAX + 12], 0
	add EAX, 16
	inc ECX
	jmp L1
L2: