The Art of
ASSEMBLY LANGUAGE PROGRAMMING

Chapter Five (Part 3)

Table of Content

Chapter Six 

CHAPTER FIVE:
VARIABLES AND DATA STRUCTURES (Part 4)
5.7 - Sample Programs
5.7.1 - Simple Variable Declarations
5.7.2 - Using Pointer Variables
5.7.3 - Single Dimension Array Access
5.7.4 - Multidimensional Array Access
5.7.5 - Simple Structure Access
5.7.6 - Arrays of Structures
5.7.7 - Structures and Arrays as Fields of Another Structure
5.7.8 - Pointers to Structures and Arrays of Structures
5.7 Sample Programs

The following short sample programs demonstrate many of the concepts appearing in this chapter.

5.7.1 Simple Variable Declarations

; Sample variable declarations
; This sample file demonstrates how to declare and access some simple
; variables in an assembly language program.
;
; Randall Hyde
;
;
; Note: global variable declarations should go in the "dseg" segment:

dseg            segment para public 'data'

; Some simple variable declarations:

character       byte    ?               ;"?" means uninitialized.
UnsignedIntVar  word    ?
DblUnsignedVar  dword   ?

;You can use the typedef statement to declare more meaningful type names:

integer         typedef sword
char            typedef byte
FarPtr          typedef dword

; Sample variable declarations using the above types:

J               integer ?
c1              char    ?
PtrVar          FarPtr  ?


; You can tell MASM & DOS to initialize a variable when DOS loads the
; program into memory by specifying the initial value in the operand
; field of the variable's declaration:

K               integer 4
c2              char    'A'
PtrVar2         FarPtr  L               ;Initializes PtrVar2 with the
; address of L.


; You can also set aside more than one byte
word
or double word of
; storage using these directives.  If you place several values in the
; operand field
separated by commas
the assembler will emit one byte

; word
or dword for each operand:

L               integer 0
1
2
3
c3              char    'A'
0dh
0ah
0
PtrTbl          FarPtr  J
K
L

; The BYTE directive lets you specify a string of characters byte enclosing
; the string in quotes or apostrophes.  The directive emits one byte of data
; for every character in the string (not including the quotes or apostrophes
; that delimit the string):

string          byte    "Hello world"
0dh
0ah
0


dseg            ends





; The following program demonstrates how to access each of the above
; variables.

cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.


; Some simple instructions that demonstrate how to access memory:

lea     bx
L           ;Point bx at first word in L.
mov     ax
[bx]        ;Fetch word at L.
add     ax
2[bx]       ;Add in word at L+2 (the "1").
add     ax
4[bx]       ;Add in word at L+4 (the "2").
add     ax
6[bx]       ;Add in word at L+6 (the "3").
mul     K               ;Compute (0+1+2+3)*123.
mov     J
ax           ;Save away result in J.

les     bx
PtrVar2     ;Loads es:di with address of L.
mov     di
K           ;Loads 4 into di
mov     ax
es:[bx][di] ;Fetch value of L+4.


; Examples of some byte accesses:

mov     c1
' '         ;Put a space into the c1 var.
mov     al
c2          ;c3 := c2
mov     c3
al

Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.2 Using Pointer Variables
; Using Pointer Variables in an Assembly Language Program
;
; This short sample program demonstrates the use of pointers in
; an assembly language program.
;
; Randall Hyde

dseg            segment para public 'data'


; Some variables we will access indirectly (using pointers):

J               word    0
0
0
0
K               word    1
2
3
4
L               word    5
6
7
8

; Near pointers are 16-bits wide and hold an offset into the current data
; segment (dseg in this program).  Far pointers are 32-bits wide and hold
; a complete segment:offset address.  The following type definitions let
; us easily create near and far pointers

nWrdPtr         typedef near ptr word
fWrdPtr         typedef far ptr word


; Now for the actual pointer variables:

Ptr1            nWrdPtr ?
Ptr2            nWrdPtr K               ;Initialize with K's address.
Ptr3            fWrdPtr L               ;Initialize with L's segmented adrs.

dseg            ends



cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.


; Initialize Ptr1 (a near pointer) with the address of the J variable.

lea     ax
J
mov     Ptr1
ax

; Add the four words in variables J
K
and L together using pointers to
; these variables:

mov     bx
Ptr1        ;Get near ptr to J's 1st word.
mov     si
Ptr2        ;Get near ptr to K's 1st word.
les     di
Ptr3        ;Get far ptr to L's 1st word.



mov     ax
ds:[si]     ;Get data at K+0.
add     ax
es:[di]     ;Add in data at L+0.
mov     ds:[bx]
ax     ;Store result to J+0.

add     bx
2           ;Move to J+2.
add     si
2           ;Move to K+2.
add     di
2           ;Move to L+2.



mov     ax
ds:[si]     ;Get data at K+2.
add     ax
es:[di]     ;Add in data at L+2.
mov     ds:[bx]
ax     ;Store result to J+2.

add     bx
2           ;Move to J+4.
add     si
2           ;Move to K+4.
add     di
2           ;Move to L+4.



mov     ax
ds:[si]     ;Get data at K+4.
add     ax
es:[di]     ;Add in data at L+4.
mov     ds:[bx]
ax     ;Store result to J+4.

add     bx
2           ;Move to J+6.
add     si
2           ;Move to K+6.
add     di
2           ;Move to L+6.



mov     ax
ds:[si]     ;Get data at K+6.
add     ax
es:[di]     ;Add in data at L+6.
mov     ds:[bx]
ax     ;Store result to J+6.



Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.3 Single Dimension Array Access
; Sample variable declarations
; This sample file demonstrates how to declare and access some single
; dimension array variables in an assembly language program.
;
; Randall Hyde


.386                            ;Need to use some 80386
option  segment:use16           ; addressing modes.

dseg            segment para public 'data'

J               word    ?
K               word    ?
L               word    ?
M               word    ?

JD              dword   0
KD              dword   1
LD              dword   2
MD              dword   3

; Some simple uninitialized array declarations:

ByteAry         byte    4 dup (?)
WordAry         word    4 dup (?)
DwordAry        dword   4 dup (?)
RealAry         real8   4 dup (?)


; Some arrays with initialized values:

BArray          byte    0
1
2
3
WArray          word    0
1
2
3
DWArray         dword   0
1
2
3
RArray          real8   0.0
1.0
2.0
3.0


; An array of pointers:

PtrArray        dword   ByteAry
WordAry
DwordAry
RealAry

dseg            ends

; The following program demonstrates how to access each of the above
; variables.

cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.


; Initialize the index variables.  Note that these variables provide
; logical indices into the arrays.  Don't forget that we've got to
; multiply these values by the element size when accessing elements of
; an array.

mov     J
0
mov     K
1
mov     L
2
mov     M
3

; The following code shows how to access elements of the arrays using
; simple 80x86 addressing modes:

mov     bx
J           ;AL := ByteAry[J]
mov     al
ByteAry[bx]

mov     bx
K           ;AX := WordAry[K]
add     bx
bx          ;Index*2 since this is a word array.
mov     ax
WordAry[bx]

mov     bx
L           ;EAX := DwordAry[L]
add     bx
bx          ;Index*4 since this is a double
add     bx
bx          ; word array.
mov     eax
DwordAry[bx]

mov     bx
M           ;BX := address(RealAry[M])
add     bx
bx          ;Index*8 since this is a quad
add     bx
bx          ; word array.
add     bx
bx
lea     bx
RealAry[bx] ;Base address + index*8.

; If you have an 80386 or later CPU
you can use the 386's scaled indexed
; addressing modes to simplify array access.

mov     ebx
JD
mov     al
ByteAry[ebx]

mov     ebx
KD
mov     ax
WordAry[ebx*2]

mov     ebx
LD
mov     eax
DwordAry[ebx*4]

mov     ebx
MD
lea     bx
RealAry[ebx*8]

Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.4 Multidimensional Array Access
; Multidimensional Array declaration and access
;
; Randall Hyde


.386                            ;Need these two statements to
option  segment:use16           ; use the 80386 register set.


dseg            segment para public 'data'


; Indices we will use for the arrays.

J               word    1
K               word    2
L               word    3

; Some two-dimensional arrays.
; Note how this code uses the "dup" operator to suggest the size
; of each dimension.

B2Ary           byte    3 dup (4 dup (?))
W2Ary           word    4 dup (3 dup (?))
D2Ary           dword   2 dup (6 dup (?))



; 2D arrays with initialization.
; Note the use of data layout to suggest the sizes of each array.

B2Ary2          byte    0
1
2
3
byte    4
5
6
7
byte    8
9
10
11

W2Ary2          word    0
1
2
word    3
4
5
word    6
7
8
word    9
10
11

D2Ary2          dword   0
1
2
3
4
5
dword   6
7
8
9
10
11

; A sample three dimensional array.

W3Ary           word    2 dup (3 dup (4 dup (?)))

dseg            ends


cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.

; AL := B2Ary2[j
k]

mov     bx
J           ;index := (j*4+k)
add     bx
bx          ;j*2
add     bx
bx          ;j*4
add     bx
K           ;j*4+k
mov     al
B2Ary2[bx]


; AX := W2Ary2[j
k]

mov     ax
J           ;index := (j*3 + k)*2
mov     bx
3
mul     bx              ;(j*3)-- This destroys DX!
add     ax
k           ;(j*3+k)
add     ax
ax          ;(j*3+k)*2
mov     bx
ax
mov     ax
W2Ary2[bx]


; EAX := D2Ary[i
j]

mov     ax
J           ;index := (j*6 + k)*4
mov     bx
6
mul     bx              ;DX:AX := j*6
ignore overflow in DX.
add     ax
k           ;j*6 + k
add     ax
ax          ;(j*6 + k)*2
add     ax
ax          ;(j*6 + k)*4
mov     bx
ax
mov     eax
D2Ary[bx]


; Sample access of a three dimensional array.
;
; AX := W3Ary[J
K
L]

mov     ax
J           ;index := ((j*3 + k)*4 + l)*2
mov     bx
3
mul     bx              ;j*3
add     ax
K           ;j*3 + k
add     ax
ax          ;(j*3 + k)*2
add     ax
ax          ;(j*3 + k)*4
add     ax
l           ;(j*3 + k)*4 + l
add     ax
ax          ;((j*3 + k)*4 + l)*2
mov     bx
ax
mov     ax
W3Ary[bx]


Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.5 Simple Structure Access
; Sample Structure Definitions and Accesses.
;
; Randall Hyde


dseg            segment para public 'data'


; The following structure holds the bit values for an 80x86 mod-reg-r/m byte.

mode            struct
modbits         byte    ?
reg             byte    ?
rm              byte    ?
mode            ends


Instr1Adrs      mode    {}                      ;All fields uninitialized.
Instr2Adrs      mode    {}


; Some structures with initialized fields.

axbx            mode    {11b
000b
000b}       ;"ax
ax" adrs mode.
axdisp          mode    {00b
000b
110b}       ;"ax
disp" adrs mode.
cxdispbxsi      mode    {01b
001b
000b}       ;"cx
disp8[bx][si]" mode.


; Near pointers to some structures:

sPtr1           word    axdisp
sPtr2           word    Instr2Adrs

dseg            ends


cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.


; To access fields of a structure variable directly
just use the "."
; operator like you would in Pascal or C:

mov     al
axbx.modbits
mov     Instr1Adrs.modbits
al

mov     al
axbx.reg
mov     Instr1Adrs.reg
al

mov     al
axbx.rm
mov     Instr1Adrs.rm
al


; When accessing elements of a structure indirectly (that is
using a
; pointer) you must specify the structure type name as the first
; "field" so MASM doesn't get confused:

mov     si
sPtr1
mov     di
sPtr2

mov     al
ds:[si].mode.modbits
mov     ds:[di].mode.modbits
al

mov     al
ds:[si].mode.reg
mov     ds:[di].mode.reg
al

mov     al
ds:[si].mode.rm
mov     ds:[di].mode.rm
al


Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.6 Arrays of Structures
; Arrays of Structures
;
; Randall Hyde


dseg            segment para public 'data'


; A structure that defines an (x
y) coordinate.
; Note that the Point data type requires four bytes.

Point           struct
X               word    ?
Y               word    ?
Point           ends



; An uninitialized point:

Pt1             Point   {}

; An initialized point:

Pt2             Point   {12
45}


; A one-dimensional array of uninitialized points:

PtAry1          Point   16 dup ({})             ;Note the "{}" inside the parens.


; A one-dimensional array of points
all initialized to the origin.

PtAry1i         Point   16 dup ({0
0})


; A two-dimensional array of points:

PtAry2          Point   4 dup (4 dup ({}))


; A three-dimensional array of points
all initialized to the origin.

PtAry3          Point   2 dup (3 dup (4 dup ({0
0})))



; A one-dimensional array of points
all initialized to different values:

iPtAry          Point   {0
0}
{1
2}
{3
4}
{5
6}


; Some indices for the arrays:

J               word    1
K               word    2
L               word    3

dseg            ends





; The following program demonstrates how to access each of the above
; variables.

cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.

; PtAry1[J] := iPtAry[J]

mov     bx
J           ;Index := J*4 since there are four
add     bx
bx          ; bytes per array element (each
add     bx
bx          ; element contains two words).

mov     ax
iPtAry[bx].X
mov     PtAry1[bx].X
ax

mov     ax
iPtAry[bx].Y
mov     PtAry1[bx].Y
ax

; CX := PtAry2[K
L].X;  DX := PtAry2[K
L].Y

mov     bx
K           ;Index := (K*4 + J)*4
add     bx
bx          ;K*2
add     bx
bx          ;K*4
add     bx
J           ;K*4 + J
add     bx
bx          ;(K*4 + J)*2
add     bx
bx          ;(K*4 + J)*4

mov     cx
PtAry2[bx].X
mov     dx
PtAry2[bx].Y

; PtAry3[j
k
l].X := 0

mov     ax
j           ;Index := ((j*3 +k)*4 + l)*4
mov     bx
3
mul     bx              ;j*3
add     ax
k           ;j*3 + k
add     ax
ax          ;(j*3 + k)*2
add     ax
ax          ;(j*3 + k)*4
add     ax
l           ;(j*3 + k)*4 + l
add     ax
ax          ;((j*3 + k)*4 + l)*2
add     ax
ax          ;((j*3 + k)*4 + l)*4
mov     bx
ax
mov     PtAry3[bx].X
0

Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp
cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.7 Structures and Arrays as Fields of Another Structure
; Structures Containing Structures as fields
; Structures Containing Arrays as fields
;
; Randall Hyde


dseg            segment para public 'data'

Point           struct
X               word    ?
Y               word    ?
Point           ends

; We can define a rectangle with only two points.
; The color field contains an eight-bit color value.
; Note: the size of a Rect is 9 bytes.

Rect            struct
UpperLeft               Point   {}
LowerRight              Point   {}
Color           byte    ?
Rect            ends

; Pentagons have five points
so use an array of points to
; define the pentagon.  Of course
we also need the color
; field.
; Note: the size of a pentagon is 21 bytes.

Pent            struct
Color           byte    ?
Pts             Point   5 dup ({})
Pent            ends


; Okay
here are some variable declarations:

Rect1           Rect    {}
Rect2           Rect    {{0
0}
{1
1}
1}

Pentagon1       Pent    {}
Pentagons       Pent    {}
{}
{}
{}

Index           word    2

dseg            ends


cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.

; Rect1.UpperLeft.X := Rect2.UpperLeft.X

mov     ax
Rect2.Upperleft.X
mov     Rect1.Upperleft.X
ax

; Pentagon1 := Pentagons[Index]

mov     ax
Index       ;Need Index*21
mov     bx
21
mul     bx
mov     bx
ax

; Copy the first point:

mov     ax
Pentagons[bx].Pts[0].X
mov     Pentagon1.Pts[0].X
ax

mov     ax
Pentagons[bx].Pts[0].Y
mov     Pentagon1.Pts[0].Y
ax

; Copy the second point:

mov     ax
Pentagons[bx].Pts[2].X
mov     Pentagon1.Pts[4].X
ax

mov     ax
Pentagons[bx].Pts[2].Y
mov     Pentagon1.Pts[4].Y
ax

; Copy the third point:

mov     ax
Pentagons[bx].Pts[4].X
mov     Pentagon1.Pts[8].X
ax

mov     ax
Pentagons[bx].Pts[4].Y
mov     Pentagon1.Pts[8].Y
ax

; Copy the fourth point:

mov     ax
Pentagons[bx].Pts[6].X
mov     Pentagon1.Pts[12].X
ax

mov     ax
Pentagons[bx].Pts[6].Y
mov     Pentagon1.Pts[12].Y
ax

; Copy the fifth point:

mov     ax
Pentagons[bx].Pts[8].X
mov     Pentagon1.Pts[16].X
ax

mov     ax
Pentagons[bx].Pts[8].Y
mov     Pentagon1.Pts[16].Y
ax

; Copy the Color:

mov     al
Pentagons[bx].Color
mov     Pentagon1.Color
al


Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp
cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main
5.7.8 Pointers to Structures and Arrays of Structures
; Pointers to structures
; Pointers to arrays of structures
;
; Randall Hyde


.386                            ;Need these two statements so
option  segment:use16           ; we can use 80386 registers

dseg            segment para public 'data'

; Sample structure.
; Note: size is seven bytes.

Sample          struct
b               byte    ?
w               word    ?
d               dword   ?
Sample          ends


; Some variable declarations:

OneSample       Sample  {}
SampleAry       Sample  16 dup ({})

; Pointers to the above

OnePtr          word    OneSample               ;A near pointer.
AryPtr          dword   SampleAry


; Index into the array:

Index           word    8

dseg            ends





; The following program demonstrates how to access each of the above
; variables.

cseg            segment para public 'code'
assume  cs:cseg
ds:dseg

Main            proc
mov     ax
dseg        ;These statements are provided by
mov     ds
ax          ; shell.asm to initialize the
mov     es
ax          ; segment register.

; AryPtr^[Index] := OnePtr^


mov     si
OnePtr      ;Get pointer to OneSample
les     bx
AryPtr      ;Get pointer to array of samples
mov     ax
Index       ;Need index*7
mov     di
7
mul     di
mov     di
ax

mov     al
ds:[si].Sample.b
mov     es:[bx][di].Sample.b
al

mov     ax
ds:[si].Sample.w
mov     es:[bx][di].Sample.w
ax

mov     eax
ds:[si].Sample.d
mov     es:[bx][di].Sample.d
eax


Quit:           mov     ah
4ch         ;Magic number for DOS
int     21h             ; to tell this program to quit.
Main            endp

cseg            ends

sseg            segment para stack 'stack'
stk             byte    1024 dup ("stack   ")
sseg            ends

zzzzzzseg       segment para public 'zzzzzz'
LastBytes       byte    16 dup (?)
zzzzzzseg       ends
end     Main

Chapter Five (Part 3)

Table of Content

Chapter Six 

Chapter Five: Variables and Data Structures (Part 4)
26 SEP 1996