Here's one way to implement an array in assembly language (32-bit).
This creates a 1-dimension (linear) array of 100 elements, fills it with values and prints the values.
There are other ways to do this; this is just one example.
;===================================
; Simple array in assembly languge
; Single-dimension (linear) array
;===================================
; Declare the array in the data section:
.data
Array DD 100 DUP(?)
; Put values into the array:
.code
MOV ECX, 100 ;Size of arrray
MOV EDX, OFFSET Array
MOV EAX, 1 ;Value to stuff into arrray elements
putlp: MOV [EDX], EAX ;Put in the value
INC EAX ;Increment the value
ADD EDX, 4 ;Point to next array element
LOOP putlp
; Now you can print the values:
PUSH EBX ;Save the "sacred" register
MOV EBX, OFFSET Array
MOV ECX, 100
print: PUSH ECX ;Save this so it doesn't get clobbered
; Using pseudocode here, since there are lots of ways to print something:
Print "Element = ", [EBX]
POP ECX ;Recover count
ADD EBX, 4 ;Next array element
LOOP print
"Print" is a made-up instruction: there are many ways to display data.
Hey NotC,
As a side and useless note. ADD used to be faster than INC.
add eax, 1
vs
inc eax
OK, whatever.
Not even commenting on optimization for this simple, simple example.
Hello,
Here is a similar version for Masm64 :
EXTERN ExitProcess:PROC
EXTERN printf:PROC
.data?
array dq 100 dup(?)
.data
string db 'Member[%u] = %u'
db 13,10,0
.code
main PROC uses rsi rbx
sub rsp,4*8+8
mov rcx,100
lea rdx,array
mov rax,1
@@:
mov QWORD PTR [rdx],rax
inc rax
add rdx,8
loop @b
mov rbx,1
mov rsi,OFFSET array
@@:
lea rcx,string
mov rdx,rbx
mov r8,QWORD PTR [rsi]
call printf
inc rbx
add rsi,8
cmp rbx,101
jne @b
xor rcx,rcx
call ExitProcess
main ENDP
END
And if you want a 2-dimensional array, here's how to compute the address of an array element:
2d array addressing.gif
i is the column index (position in the row) and j is the row index (the position in the column). Both are 0-based.
Important: w is the width of one row in bytes, not the number of elements. (h is the number of rows.)
So if there are 6 elements per row and each element is a DWORD (4 bytes), then the width is 24 bytes.
(Coding is left as an exercise for the reader)
@nocforme
Old trick for using 256*256 2d array is use BL for x and BH for y
@lord adef
Depending on CPU,that advice was for P4
If I have slow loop,for example loop that contains api calls that take milliseconds
It doesn't matter,might be more convenient with
Dec variable
Than register preservation push/pop + Dec reg or sub reg,1
Can we please leave out the optimizations and just focus on the simple problem at hand for the OP's sake?
They can deal with optimizing things later, once they've figured out how to handle arrays.
Hi,
Usual comment; if the original poster of this thread, or a moderator,
thinks this is an inappropiate addition to this thread, have at it.
This thread was about how an array is set up in an assembly program.
This post is partly that, and partly something else all together. I
hope it helps someone to see how to use an array a bit clearer.
An array can be used to represent a matrix. A matrix is a: "A
rectangular array of numerical or algebraic quantities treated as an
algebraic entity." Nifty, that's what you get from a dictionary. Here
I will use an array of numbers in a three by three square as my subset
of matrices. Matrices are used as a shorthand to apply mathematical
operations to a system of equations. Multiple algebraic operations
applied to a set of numbers in a specified order shown as numbers en-
closed by brackets. Well, numbers arranged in a rectangle, enclosed in
brackets is a matrix. The operations use the matrices.
This post will discuss my implementation of a program to display
a set of elementary matrix operations to a user. The program shows
how the matrix is changed by each action. It was originally a DOS
program that I later converted to a Windows program. Thanks to Raymond
for his Windows FPU library routines.
I was using the extended ASCII characters from the default code page
(437) in a VDM for my ease of use to draw the matrix. This does not
work in Wordpad or Notepad. Wordpad has an option when opening a file
to open as a "DOS text file". That doesn't work to do anything. I
tried using Word, but that did not work either. Though admittedly an
ancient version. I had thought the forum editor had an insert symbol
option, but I must have been wrong.
So a matrix should be shown as (Big left bracket), (Numbers), and
(Big right bracket). I will use the following notation.
| 1 2 3 |
| 4 5 6 |
| 7 8 9 |
Ugly but workable.
A matrix uses a one based indexing system in row then column order.
Here the matrix is represented as elements with the address of the
element as numbers in the form below.
| a11 a12 a13 |
A = | a21 a22 a23 |
| a31 a32 a33 |
High level languages like BASIC or FORTRAN use one based addressing
as well. Text and reference books use the one based addressing for the
matrices they use. As mentioned in Reply #4, MASM assembly language
programs normally use zero based addressing for arrays. So, the main
problem for a programmer is that the machine wants a zero based address
and the user wants the display to be using one based indicies.
I can use one based indexing by ignoring the zeroth element in the
array to represent a matrix. That way I can sort of think of it as a
one based array.
An array is laid out in a linear fashion in memory.
0 1 2 3 4 5 6 7 8 9
When used as a matrix we order the elements into a square.
0 1 2 3 | 11 12 13 |
4 5 6 => | 21 22 23 |
7 8 9 | 31 32 33 |
Not using the zeroth element is used to think about the ordering of
the elements in the matrices. It was to make programming simpler. Or
actually to make debugging the program and displaying intermediate
results easier. The following discussion is about how I worked on the
programming. It is not necessary for anyone else to use this. It made
things easier for me, and did not violate the 15% rule.
So now for some code to show how things were written. These are
snippets and just show some of the thought behind the program operation
and is not intended to be used as your program's organization. Do your
own thing.
I am using three by three maticies with floating point numbers to be
used with the FPU.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; - - - EQUates. - - -
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Element EQU 3 ; Number of elements in a column or row.
ElSize EQU 10 ; Ten bytes per floating point number.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; - - - 3 x 3 matrices with leading zero element for addressing.
IdentWrk DT 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0
IdentTmp DT 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0
IdentRes DT 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0
MatrixWk DT 0.0, 3.0,-2.0, 2.0, 1.0, 2.0,-3.0, 4.0, 1.0, 2.0
MatrixW2 DT 0.0, 3.0,-2.0, 2.0, 1.0, 2.0,-3.0, 4.0, 1.0, 2.0
ColumnWk DT 10 DUP( 0.0 )
RowWork DT 10 DUP( 0.0 )
TempWork DT 10 DUP( 0.0 )
ColI DW 0
ColJ DW 0
RowI DW 0
IndxWrk DW 0
Matrix DD OFFSET MatrixWk ; Defines an OFFSET to the wanted matrix.
Three DW Element
Ten DW ElSize
; - - - Matrix OFFSETs for FMatMul
MatrixA DD OFFSET RowWork
MatrixB DD OFFSET MatrixWk
MatrixC DD OFFSET TempWork
; - - - Matrix elements are specified by row and column number.
IndexI DW 0
IndexJ DW 0
IndexK DW 0
; - - - Matrix elements are specified by one number, an offset
; from array start.
; C(I,J)=C(I,J)+(A(I,K)*B(K,J))
IndexIJ DW 0
IndexIK DW 0
IndexKJ DW 0
; - - - Matrix elements are specified by an address, one number,
; an offset from array start based on element size.
ADDR_IJ DD 0
ADDR_IK DD 0
ADDR_KJ DD 0
For instance, the IndexIJ, IndexIK, and IndexKJ came from the matrix
multiply routine. It uses something like;
C(I,J) = C(I,J) + ( A(I,K) * B(K,J) )
in a loop. Matrix C is made from the product of A multiplied by B.
The ColI, ColJ, and RowI were one based indices used in the display
code. The IndexI, IndexJ, and IndexK were one based indices intended
to be used in the calculation portions of the program. This was a
side effect of reusing some older code.
COMMENT !
28 August 2019
Implement a set of elementary matrix operations.
Type One: Interchange of (swap) the ith and jth columns denoted by
C(i,j).
Type Two: Multiplication of the ith column vector by the nonzero
constant c, denoted by cCi.
Type Three: Adding to the ith Col vector, k times the jth column
vector, denoted by Ci + kCj.
These can be done as an algorithm or by using a multiplcation by
an elementary matrix.
Reference: Basic Matrix Theory, Leonard E. Fuller, Dover edition
2017; Prentice-Hall edition 1962.
!
Note that there are the equivalent set of elementary row operations.
And column and row operations can be both be used.
The higher level routines then tend to look like the following code.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ColT1 PROC
; Type One:
; Interchange of (swap) the ith and jth columns denoted by C(i,j).
;
; Change identity | 1 0 0 | | 1 0 0 |
; matrix to a swap | 0 ii 0 | -> | 0 0 ij |
; columns matrix. | 0 0 jj | | 0 ji 0 |
;
; INPUT: ColI
; ColJ
; Matrix
MOV EBX, OFFSET ColumnWk
CALL MkIdent
CALL ZeroII
CALL ZeroJJ
CALL OneIJ
CALL OneJI
RET
ColT1 ENDP
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Note that in the above, the matrix is hard wired and not an input
despite the comment. Hey, work was in progress type of excuse?
Now for some low level routines to show how the matrix is actually
accessed by the program. First a routine to create the identity matrix.
| 1.0 0.0 0.0 |
| 0.0 1.0 0.0 |
| 0.0 0.0 1.0 |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MkIdent PROC
; While matrix notation is one based, X86 addressing is
; easier as zero based. Either think or be confused?
; Element is the number of rows and columns
; in the square matrix, one based.
;
; INPUT: EBX = OFFSET Matrix
MOV CX,0 ; Column counter
MOV EDI,10 ; Offset in matrix IdentWrk
MId_1:
MOV BP,0 ; Row counter
MId_2:
CMP CX,BP ; I = J ?
JNE MId_3
FLD1
;- FSTP IdentWrk[EDI]
FSTP TBYTE PTR [EBX+EDI]
JMP MId_4
MId_3:
FLDZ
;- FSTP IdentWrk[EDI]
FSTP TBYTE PTR [EBX+EDI]
MId_4:
ADD EDI,10 ; Size of number...
INC BP
CMP BP,Element ; End of row?
JB MId_2
MOV BP,0
INC CX
CMP CX,Element ; End of Matrix?
JB MId_1
RET
MkIdent ENDP
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The commented out lines with IdentWrk were when the identity matrix
was hard wired to a default matrix. Program growth required an arbi-
trary matrix to be filled in. So the input matrix address is passed
in EBX.
The next routine converts ColI and ColJ to IndexWrk. ColI and ColJ
are integer index numbers ( 1, 2, 3 ). IndexWrk is the byte address in
memory. An artifact of writing the program is that a matrix element
address is specified by ColI and ColJ instead of RowI and ColJ. Oh
well, sorry. IndexWrk is the linear address into the array as specified
by the row index and the column index. The array elements are ten bytes
apiece.
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MkIndexIJ PROC
; INPUT: ColI
; ColJ
MOV AX,[ColI]
DEC AX ; One to zero based.
MUL Three
MOV DX,[ColJ]
DEC DX ; One to zero based.
ADD AX,DX
INC AX ; Zero to one based.
MUL Ten ; Array element size.
MOV [IndxWrk],AX
RET
MkIndexIJ ENDP
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The program is attached. It was written by me, for my use, to
answer a question posed by some lectures and the reference book. Once
that was done, work mostly stopped. It basiclly shows what happens to
a matrix as it is worked to create the matrix inverse.
cheers,
Steve
Well, Steve, as the OP here I don't think your post is inappropriate.
I do think it's a bit too big of a chunk for someone just starting to use matrices in an assembly-language program to bite off. But I'll leave that for them to decide.
Rather than get into all the intricacies of matrix manipulation at the outset, I'm much more interested in just getting our n00b started on laying out and addressing a simple matrix.
First things first, y'know.
Here is a simple string array example :
include \masm32\include\masm32rt.inc
.data
string1 db 'Melon',0
string2 db 'Apple',0
string3 db 'Orange',0
string4 db 'Banana',0
strArray dd string1,string2
dd string3,string4
msg db 'Fruit %u = %s'
db 13,10,0
.code
start:
call main
invoke ExitProcess,0
main PROC uses esi ebx
xor ebx,ebx
mov esi,OFFSET strArray
@@:
inc ebx
invoke crt_printf,ADDR msg,\
ebx,DWORD PTR [esi]
add esi,4
cmp ebx,4
jne @b
ret
main ENDP
END start
Hi,
Well a bit long I will agree with. But I wanted a "real life"
example to show how that affects the programming involved in writing
a program that involves interacting with a user. The only real
description of matrices I gave was 'Well, numbers arranged in a
rectangle, enclosed in brackets is a matrix'. And how I laid things
out in memory to be used as an array. And some information on indexing.
Anyway after laying out the background, I forgot to give the punch line.
Synopsis:
One, when dealing with a user, use human oriented concepts to make
things easier to program. One based indexing as an example.
Two, when dealing with programming the CPU, use computer oriented
concepts, basiclly because you have no other choices with assembly
language. Zero based addressing for instance.
Three, you will need to translate between the two paradigms
mentioned above.
Example:
You have obtained a number you want to store in the first element of
the matrix. The first element has a row value of one and a column value
of one. You will convert those values to a byte offset to address the
correct array member. Simplified (fake) code example using stuff I
posted above.
MOV RowI,1 ; Human values, ColI in posted code.
MOV ColJ,1 ; These are the matrix index values.
CALL MkIndexIJ ; Make the byte offset to address the
; proper array member from the indicies.
MOV EDI,OFFSET MatrixWk ; Point to array holding the matrix.
ADD EDI,[IndxWrk] ; Add in byte offset to point to the proper
; array member.
MOV ESI,OFFSET FConst ; Point to wanted number.
FLD TBYTE PTR [ESI] ; Load number into FPU.
FSTP TBYTE PTR [EDI] ; Store number into the array/matrix.
And that was the missing punch line. Laughter ensues? Whatever.
Regards,
Steve
Quote from: FORTRANS on March 22, 2025, 12:16:06 AMOne, when dealing with a user, use human oriented concepts to make
things easier to program. One based indexing as an example.
Maybe when presenting array indices to the user.
But certainly not internally; zero-based indices are the norm and are much easier to handle programmatically. So you'd need to convert (add or subtract 1 to/from each index) for the user-interface values.
But I guess you said as much in your post ...
Might start thread in workshop for more advanced array coding?
Define "advanced error coding" :biggrin:
Hi,
Quote from: NoCforMe on March 22, 2025, 07:04:31 AMBut I guess you said as much in your post ...
Yes. Assuming we are talking on the same subject, I guess we must
agree to disagree.
I could post a snippet of code from this program that the majority
of our "regular" programmers would see as ugly or wrong. And could
explain why or how it can cause problems in some cases. I knew this
when I wrote it and could have "fixed" it then or now. But it was
easier to do it in the quick and dirty fashion and, knowing that it
works, and why it works, leave it as is. Saved two or three lines
of code that would need to be changed or added. And until I typed it
up here, saved a hand full of seconds.
Writing code should be done in a manner that works for you.
Following "the rules" is usually the best way of doing things. But
doing things differently is sometimes easier or more fun. Depending
on some definition of fun.
In this particular case, it made looking at intermediate results
and comparing them to the published methods, possible or easier for
me. Generating the indices to access a matrix was a bit tedious to
debug in some cases.
Cheers,
Steve N.
Hate to say it, Steve, but I think you're still kind of missing the point.
The point being that too often around here (on other forums as well), when someone asks a question about something, say how to set up an array in assembly language, some respondents not only explain the basics of array definition/declaration and simple addressing, but go way beyond it into much more complex subjects.
It's a simple matter of TMI; my plea is, please don't overwhelm the poor question-asker with information that's way beyond the scope of what they're asking about.
No rules, no violations of guidelines, just simple common sense and courtesy.