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