Chapter 5.7-5.8 Notes

Document last modified: 

Overview

The importance of algorithm abstraction and modularity is such that virtually all high-level languages realize these notions, generally as procedures and functions with parameters. Translation from Pascal or C++ algorithms to Assembly can be made once a few basic rules for passing parameters are established. Though there are numerous methods to pass data to a procedure, the simplest and the one discussed here is the use of global variables and register parameters to interface the calling and the called functions. The more general and useful method of passing parameters via the stack will also be discussed later as this method is most often used by high level languages.

Macros are another method of implementing modularity and abstraction in Assembler (and C, spreadsheets, and many languages). Though both are abstraction techniques, macros are very different from a function in use.

Macros

Macros allow a programmer to define pseudo operations, typically operations that are generally desirable, are not implemented as part of the processor instruction, and can be implemented as a sequence of regular assembler instructions. Each use of a macro generates new program instructions, the macro 

use has the effect of automating the writing of the program.

Consider a typical scenario where one needs to do a number of different divisions of the Ax register by 10. The following lists the typical evolution of macro development and usage. The final result is the expansion of the macro in which the generated assembler code becomes part of the program. In the following example the macrouse simply inserts the three instructions of the macro definition.
Typical evolution of a Macro
Instruction
Needed
Real
Operations
Macro
Definition
Use in
Program
Macro
Expansion
Div  10



Mov  Dx, 0
Mov  Bx, 10  
Div  Bx

_Div10  Macro
        Mov    Dx, 0
        Mov    Bx, 10    
        Div    Bx
endm
Call  GetDec$
_Div10
Call  PutDec$   

  
Call  GetDec$
  Mov   Dx, 0
  Mov   Bx, 10
  Div   Bx
Call  PutDec$

Parameters - Macro parameters support code reuse, allowing one macro definition to generate or implement multiple, similar algorithms. In the following, the _DIV macro has a single parameter N. When the macro is used in the program, the actual parameter used, 34, is substituted for the formal parameter, N, defined in the macro prototype during the macro expansion. Now the same macro definition when expanded, produces code to divide by any unsigned integer parameter.
Macro Parameters
Instruction
Needed
Real
Operations
Macro
Definition
Use in
Program
Macro
Expansion
Div  N



Mov  Dx, 0
Mov  Bx, N  
Div  Bx

_Div    Macro  N
        Mov    Dx, 0
        Mov    Bx, &N    
        Div    Bx
endm
Call  GetDec$
_Div  34
Call  PutDec$   

  
Call  GetDec$
  Mov   Dx, 0
  Mov   Bx, 34
  Div   Bx
Call  PutDec$

Labels - Labels must be unique. When used in macros, multiple expansions of a macro can produce multiple definitions of the same label. To see the problem consider the macro below to produce the absolute value of a signed integer variable. For one use of the _Abs macro, the if:, then:, and endif: label definitions are unique, two or more uses of the _Abs macro leads to multiple definitions of the if:, then:, endif: labels.
Local Symbols - The solution to the label problem is to generate unique symbol(s) each time the macro is used. The solution is to implement a counter that is incremented each time a symbol defined to be local is encountered during macro expansion. The following illustrates the use of local symbols to produce unique symbols in place of if, then, and endif. The first table is correct but produces labels that bear little connection to the original structure. The second produces more readable code.
Macro Label Solution
Instruction
Needed
Real
Operations
Macro
Definition
Use in
Program
Macro
Expansion
Abs   X







if: Cmp X, 0 
    Jl  then
    Jmp endif
then:
    Neg X
endif:


_Abs  Macro   X
  local if, then, endif
  if: Cmp &X, 0 
      Jl  then
      Jmp endif
  then:
      Neg &X
  endif:
endm
Call  GetDec$
_Abs  Z
Call  PutDec$   

  



       Call  GetDec$
$0001: Cmp   Z, 0 
       Jl    $0002
       Jmp   $0003
$0002:
       Neg   Z
$0003:
       Call  PutDec$
Macro Label Solution
Instruction
Needed
Real
Operations
Macro
Definition
Use in
Program
Macro
Expansion
Abs   X






if: Cmp X, 0 
    Jl  then
    Jmp endif
then:
    Neg X
endif:

_Abs  Macro   X
  local label
  if&label: Cmp &X, 0 
      Jl  then
      Jmp endif
  then&label:
      Neg &X
  endif&label:
endm
Call  GetDec$
_Abs  Z
Call  PutDec$   

  


         Call GetDec$
if$0001: Cmp  Z, 0 
         Jl   then$0001
         Jmp  endif$0001
then$0001:
         Neg  Z
endif$0001:
         Call PutDec$
Conditional Assembly - Means that some sections of the program may be optional, either included or not in the final program, dependent upon the specified conditions. A reasonable use of conditional assembly would be to combine two versions of a program, one that prints debugging information during test executions for the developer, another version for production operation that displays only results of interest for the average user. A program fragment that assembles the instructions to print the Ax register only if Debug is true is given below. Note that true is any non-zero value so that Debug equ 1 makes Debug true or non-zero.
 
Generate code to display Ax when Debug is non-zero.
Generate no code when Debug is zero.
Debug  equ  1         ; Debug is true
      :
      :
     Mul   Bx
     If    Debug    ; Assemble when Debug is true
       Push    Bx   
       Mov     Bh, 0
       Call    PutDec$
       Pop     Bx
     Endif
     Sub   Cx, 12
Debug  equ  0         ; Debug is false
      :
      :
     Mul   Bx
     If    Debug    ; Assemble when Debug is true



     Endif
     Sub   Cx, 12

Macro Messages

Errors can be signaled to the console during assembly using:

Testing for Blank Macro Parameters/Exit Expansion - It is possible to perform some simple tests for correctness of macro parameters, the simplest is to verify that all parameters are defined. Consider a macro _Max that returns the maximum of two unsigned integers in the Ax register. If either of the two values are missing the macro should display an error message to the screen but not expand to produce any program instructions.

Testing for Blank Parameters
Instruction
Needed
Real
Operations
Macro
Definition
Use in
Program
Macro
Expansion
Max   X, Y 
    Mov Ax, X
if: Cmp Ax, Y  
    Ja  then
    Jmp else
then:
    Mov Ax, X
    Jmp endif
else:
    Mov Ax, Y
endif:
_Max    Macro  X, Y  
        local L
ifB    <&Y> 
        %outm Error 
        exitm
endif
        Mov Ax, &X
  if&L: Cmp Ax, &Y 
        Ja  then&L
        Jmp else&L
  then&L:
        Mov Ax, &X
        Jmp endif&L
  else&L:
        Mov Ax, &Y
  endif&L:
endm
Call  GetDec$
_Max  Z, 5
Call  PutDec$  
_Max  Z   








  



       Call  GetDec$
       _Max    Z, 5
       Mov Ax, Z
if$01: Cmp Ax, 5    
       Ja  then$01
       Jmp else$01
then&01:
       Mov Ax, Z
       Jmp endif$01
else$01:
       Mov Ax, 5
endif$01:
       Call  PutDec$

       _Max  Z
No expansion due to
missing parameter.

Examples
 
Euclid's Greatest Common Divisor Macro
Modulus operator
Result parameter must be a variable or register other
than Ax, Bx, or Dx
Interchange operator 
All parameters must be variables 
or registers other than Ax, Bx
GCD operator
All parameters must be variables or
registers other than Ax, Bx, Dx
_Mod   Macro   N, Divisor, Result
       PushA   
       Mov     Ax, &N
       Mov     Bx, &Divisor
       Mov     Dx, 0
       Div     Bx
       Mov     &Result, Dx
       PopA
endm


_Swap Macro  A, B
      PushA  
      Mov    Ax, &A
      Mov    Bx, &B
      Mov    &A, Bx
      Mov    &B, Ax
      PopA
endm
             


_Gcd Macro  X, Y
       local  L
  while&L:
       cmp    &Y, 0
       Jne    do&L
       Jmp    endwhile&L
   do&L:
       _Mod   &X, &Y, &X
       _Swap  &X, &Y
       Jmp    while&L
  endwhile&L:
endm

 
Expansion of _GCD, _MOD, and _SWAP
  _GCD A, B

   while$0001:
       cmp    B, 0
       Jne    do$0001
       Jmp    endwhile$0001 
   do$0001:
   ; _Mod   A, B, A
         PushA   
         Mov     Ax, A
         Mov     Bx, B
         Mov     Dx, 0
         Div     Bx
         Mov     A, Dx
         PopA
   ; _Swap  A, B
         PushA  
         Mov    Ax, A
         Mov    Bx, B
         Mov    A, Bx
         Mov    B, Ax
         PopA
       Jmp    while$0001
  endwhile$0001:

_OR - Performs a logical OR operation on the results of two relations. The Carry flag is set equal 1 if the result is true and the Carry flag is reset equal 0 if the result is false. For example:

        Mov  N, 12                     ;; N = 12;
Do:                                    ;; Do
        Dec   N                        ;;        N = N - 1;
While:  _OR  N, Jl, 0, N, Jg, 10       ;; While (N < 0) || (N > 10)
        Jc    Do                              
EndDo:
would set the Carry flag equal 1 when 0 <= N <= 10. To set Carry flag equal 1 use STC instruction, reset Carry flag equal 0 use CLC instruction. The following macro will test that there are six actual parameters provided to the macro, if any parameters are missing the macro will exit without generating any code.
Definition and Expansion of _OR macro
Definition
_OR     Macro        Opr1, Condition1, Opr2, Opr3, Condition2, Opr4
        Local        L
     IfB             <&Opr4>    
        %Outm        "Missing operand in OR"
        exitm
     Endif

     if&L:
        Cmp          &Opr1, &Opr2
        &Condition1  then&L
     or&L:
        Cmp          &Opr3, &Opr4
        &Condition2  then&L
        Jmp          else&L
     then&L:
        Stc
        Jmp          endif&L
     else&L:
        Clc
     endif&L:
Endm
Expansion
_OR     N, Jl, 0, N, Jg, 10

    if$0001:
        Cmp          N, 0
        Jl           then$0001
     or$0001:
        Cmp          N, 10
        Jg           then$0001
        Jmp          else$0001
     then$0001:
        Stc
        Jmp          endif$0001
     else$0001:
        Clc
     endif$0001:


Program Organization - Macro definitions must be placed at the beginning of a program prior to any other executeable statements.
 
.386
.model flat, stdcall
 include v:\common\user\c335\masm32\include\kernel32.inc
 include v:\common\user\c335\masm32\include\masm32.inc
 includelib v:\common\user\c335\masm32\lib\kernel32.lib
 includelib v:\common\user\c335\masm32\lib\masm32.lib
       PutDec  proto
       GetDec  proto
_Abs  Macro   X
        local if, then, endif
    if: Cmp &X, 0 
        Jl  then
        Jmp endif
    then:
        Neg &X
    endif:
endm
.code
main    Proc    Near        ; void main()  {

        Call    Getdec      ;       cin >> eAx ;         
       _Abs    eAx            
        Call    Putdec      ;       cout << eAx ;   

        Push    0            
        Call    ExitProcess    
main    Endp
        End     main

Document last modified: