UMBC CMSC 211

UMBC | CSEE


Addressing

The author points out that this chapter is the most crucial in the book. Specifically, he points out: "Its importance can't be overestimated, and its careful study will be repaid many times over.
If you are familiar with C pointers and pointer arithmetic, you will notice many things here that look familiar. In fact, C/C++ pointers were designed to mimic assembly language in order to make them efficient to implement. In other words, if you don't really understand pointers in C, after you see how they really work, you will probably be able to understand them, finally.

Memory Address versus Memory Contents

In high-level languages, such as C, the identifier refers to the contents of a memory location. Thus, when you write:
A = 3;	/* assigns the value of three to the memory location you
			named A */
x = A;      /* the memory location x gets the value used at location A
			or three */
p = &A;     /* P now holds the address of the memory location you 
			named A */
Unless you use & symbol, you are referring to the contents. The contents of that location change during the execution of your program, but the address will be the same throughout.

As you remember, we can write something like this:

A DB 24
B DW 1234
Now when we want to get the contents and address we do:
  mov bx, B ; moves the contents of B to bx
  mov bx, OFFSET B ; moves the address of B to bx
Or the keyword OFFSET is the equivalent of C's & .

Address Arithmetic

In C, we have something like:
char	name[10];
This reserves ten bytes of memory and the first one is called name[0]. In assembly language we can do it a number of ways:
A DB 0Ah, 1Ah, 2Ah, 3Ah, 6 dup (?)
Or
A DB 0Ah
  DB 1Ah
  DB 2Ah
  DB 3Ah
  DB 6 dup (?)
Now the location A holds 0Ah, etc. Notice that the other locations do not have a name (they are anonymous), but we can get to them with address arithmetic A + 3 refers to the byte containing 3Ah. This means that A + 3 points to the byte [ A + 3 ]. This gives us two forms:
  mov al, A ; moves the contents of A to al
  mov al, [ A + 3 ] ; moves the address of A plus 3 to al (which holds 3Ah!)
Additionally, if p is a pointer variable in C, we can say that [p] is the equivalent of *p.

Notice that the following are not the same thing!!!!!

  mov al, A + 3 ; moves 3Ah into al
  mov al, [ A ] + 3; ; moves 0Ah plus 3 (0Dh) into al
A + 3 in assembly language is the exact opposite of what it is in C! I recommend that you used the notation [ a + 3 ].

If you to get the address of pointed to by [ a + 3 ], you would use:

  mov ax, OFFSET [A + 3] ; moves address of where the
; byte 3Ah is into ax
Suppose we have the following definitions of arrays:
AA DB 0Ah, 1Ah, 2Ah, 3Ah, 4Ah, 5Ah, 6Ah, 7Ah
BB DB 0Bh, 1Bh, 2Bh, 3Bh
CC DB 0Ch, 1Ch, 2Ch, 3Ch, 4Ch, 5Ch
In memory we would have:

Label AA:                                        BB:             CC:            
Contents 0A 1A 2A 3A 4A 5A 6A 7A 0B 1B 2B 3B 0C 1C 2C 3C 4C 5C  
Offset AA   
BB-8
CC-12
AA+1 
BB-7
CC-11
AA+2 
BB-6
CC-10
AA+3 
BB-5
CC-9 
AA+4 
BB-4
CC-8 
AA+5 
BB-3
CC-7 
AA+6 
BB-2
CC-6 
AA+7 
BB-1
CC-5 
AA+8 
BB  
CC-4 
AA+9 
BB+1
CC-3 
AA+10
BB+2
CC-2 
AA+11
BB+3
CC-1 
AA+12
BB+4
CC   
AA+13
BB+5
CC+1 
AA+14
BB+6
CC+2 
AA+15
BB+7
CC+3 
AA+16
BB+8
CC+4 
AA+17
BB+9
CC+5 

It is important to notice that the offset can be a positive or negative number and that there is nothing preventing this. Array-bound checking is only accomplished in high-level languages with the addition of additional code that you normally don't see! This is why in C, if you exceed the boundary of an array, you don't get an error message unless you attempt to use memory that is not available.

Whenever you use OFFSET, you are referring to a word! For mov instructions, you must have a sixteen bit register as the destination!

Looking at a word array, we can have:

INCLUDE       PCMAC.INC                
              .MODEL      SMALL
              .STACK      100h
              .DATA
;
A             DW          000Ah, 001Ah, 002Ah, 003Ah, 004Ah
;
              .CODE                    
template      PROC
;
              mov         ax, @data
              mov         ds, ax
;
              mov         ax, OFFSET A
              mov         bx, [ A + 3]       ;Danger!!!!
;
              _Exit
template      ENDP                     
              END         template                      
  
However, there is one item to point out! In C, if the program called for the item (p + 3), the compiler will generate code to address the word 003A, which is [ A + 6].
In assembly language, if [ A + 3 ] is used, the result is very different!

When we run this, we get:

Memory: Data Segment

1A3B:0000  0A 00 1A 00 2A 00 3A 00 4A 00 4E 42 4E  
1A3B:000D  42 30 38 20 02 00 00 00 00 00 00 01 00
  

Memory: Code Segment

1A3A:0000 B83B1A         MOV       AX,1A3B     ;Really mov ax, @data
1A3A:0003 8ED8           MOV       DS,AX  
1A3A:0005 B80000         MOV       AX,0000  
1A3A:0008 8B1E0300       MOV       BX,WORD PTR [0003]  
1A3A:000C B44C           MOV       AH,4C  
1A3A:000E CD21           INT       21  
  

Registers

 AX = 0000
 BX = 2A00
 CX = 0000
 DX = 0000
 SP = 0100
 BP = 0000
 SI = 0000
 DI = 0000
 DS = 1A3B
 ES = 1A2A
 SS = 1A3C
 CS = 1A3A
 IP = 000C
 FL = 3202

NV UP EI PL
NZ NA PO NC
  
As you can see from the memory, what was put into BX:
1A3B:0000 0A 00 1A 00 2A 00 3A 00 4A 00 4E 42 4E
There are two items here that need to be highlighted:
  1. The expression [ A + 3 ] became: WORD PTR [ 0003 ]
    That is WORD PTR [ OFFSET A + 3]
  2. The data is being store as 0300, not 0003!
    Data and addresses are stored as little-endian
Always remember that when addressing an array element, what you are counting is the number of bytes from the beginning of the array.

Rules for Address Expressions

An address and a number are two different types of objects. An address represents a physical location in member. A number is simply a bit pattern that has no inherent data type! We don't know if it represents years, days, minutes, seconds, oranges, airplanes, characters or whatever.

The most important difference is when a program is loaded into a different location in memory, the addresses change but the numbers do not!

Legal Address Arithmetic

Symbols (identifiers) are addresses if the label memory locations. Normally, that is when they are in front of something like DB or DW in the data segment or when followed by a colon in the code segment. Additionally, symbols can be EQUated to addresses are addresses. (However, symbols EQUated to constant numbers are just simply ordinary numbers.)

If A and B are addresses and n a ordinary number, then we can legally do:

Every address has a particular data type (word or byte) and every address express retains the data type of the base address.

Some examples are:

A + 14 address
B - A number
CW - AW number
AW + ( B - A ) address
Remember B - A is a number that
puts this into the form of A + n
One thing to point out is that when using macros and address expressions, you want to put the angle brackets around the expression, otherwise it will be interpreted as multiple parameters:
_PutStr < BlankEnd - n > There is also a special assembler symbol, the dollar sign. NOTE: This is not '$', the quotes make it a character. The assembler symbol represents the next location that code will be assembled into.

Here is an example:


        .model  small
        .stack  100h
        .data
msg     DB      'This is a test', 10, 13, '$'
msglen  DW      $ - msg
msg1    DB      'Its length is $'

        .code
        EXTRN   PutDec : NEAR
main    PROC
        include pcmac.inc
        _Begin

        _PutStr msg
        _putStr msg1
        mov     ax, msglen
        call    PutDec
        _PutCh  10, 13


        _exit
main    ENDP
        END     main

This says that the length is 17, which is longer than the string that appears on the string. Why???? Because in memory, the 10, 13, and '$' each occupy one byte and is included in the length.

Byte Swapping

When we write code that will store a word, such as:
AWord DW 1234h
produces memory that looks like this:
  34h 12h  
When moving data from memory (or the opposite direction), the data is put into the correct format.

Words in assembly language source code files and words in registers have bytes in their normal order. Words in memory have their bytes swapped!

Moving a word to or from memory automatically swaps bytes.

Once a label for a variable is defined with a size, it keeps that size of word or byte that it was give, unless you cast or coerce or override it:

Aword DW  1234h
      ...
      mov al, BYTE PTR AWord           ; al now has 34h
  


UMBC | CSEE