An Introduction to MACROS Macro -- An alternative to a procedure for achieving modularity in assembly language programming. Macro: A name that stands for a block of text Defined once by giving the name and the text Then the name can be used as many times as we wish Each reference to the macro name causes text it stands for to be inserted at the place the name is used The assembler does this text insertion It's called "expanding" the macro Intel 80X86 (MASM) Macro syntax: name MACRO [list of arguments] ;arguments are optional placeholders statement_1 statement_2 ;these form the body of the macro (the text it stands for) ... statement_n ENDM Example: putchar, a macro to output a character to the screen putchar macro ;here no argument -- programmer must load character into DL before invoking macro mov AH,2 ;DOS single character output service int 21h endm Using the putchar macro (This code will output an A and a 0 to the screen) ... mov DL,'A' putchar ... ... mov DL,30h ;ASCII code for a '0' putchar ... ... This code would be expanded (.LST file) as follows (The assembler generates the 1's to show that these are macro statements): mov DL,'A' putchar 1 mov AH,2 ;DOS single character output service 1 int 21h ... ... mov CL,30h ;ASCII code for a '0' putchar 1 mov AH,2 ;DOS single character output service 1 int 21h ... ... Note that when the macro is expanded by the assembler, the text it stands for is blindly inserted. Using macro arguments: Macro arguments are symbols to be replaced by values when macro is expanded They are just placeholders separated by commas Values given when macro is invoked will replace the arguments in the same order Example -- putchar with a single argument: putchar macro char ;char is the argument mov AH,2 mov DL,char int 21h endm Using the new putchar macro: ... putchar 'A' ;note the value of the argument here is 'A' 1 mov AH,2 1 mov DL,'A' ;an exact text replacement of char by 'A' 1 int 21h ... ... mov AL,30h putchar AL ;here the value of the argument is AL 1 mov AH,2 1 mov DL,AL ;exact text replacemt of char by AL 1 int 21h ... ... Careful with macros containing labels -- Example -- Macro to determine absolute value: abs macro x cmp x,0 jge done neg x ;reverse sign if negative done: endm Let's use this macro in the following code (source and expansion): ... mov AX,-5 abs AX ;x will be replaced by AX 1 cmp AX,0 1 jge done 1 neg AX 1 done: ... ... mov BL,2 abs BL ;x will be replaced by BL 1 cmp BL,0 1 jge done 1 neg BL 1 done: ;*** this is an error -- done is a duplicate label!! ... If our macro is to be invoked more than once and has labels, we need to have the assembler generate label names. Do this with the 'local' declaration. This causes the assembler to generate a new label name each time the macro is invoked. Same example using local: abs macro x local done ;this is the label name -- could have several separated by commas cmp x,0 jge done neg x ;reverse sign if negative done: endm Using this new abs macro (soure and expansion): ... mov AX,-5 abs AX ;x will be replaced by AX 1 cmp AX,0 1 jge ??0000 ;label name done replaced with ??0000 generated by assembler 1 neg AX 1 ??0000: ... ... mov BL,2 abs BL ;x will be replaced by BL 1 cmp BL,0 1 jge ??0001 ;note new label name ??0001 generated by assembler 1 neg BL 1 ??0001: ;*** No duplicate labels, no error!! ... Nested Macros -- can have any level of nesting, but inner macros must be defined first Example: DisplayStr (Displays a string of characters and uses the putchar macro) putchar macro char ;char is the argument mov AH,2 mov DL,char int 21h endm DisplayStr macro str, lng ;arguments are offset and length of string to be displayed local top mov SI,0 ;index of next character in string mov CX,lng top: putchar str[SI] ;output current character inc SI ;point to next character loop top ;repeat endm See example program (source and lst files) to see how these macros are used and expanded (http://www.cs.binghamton.edu/~reckert/220/macros.htm) Using macros to generate new instructions: putcharif -- a macro to display a character if a certain condition is true: Examples of how it would be used: putcharif BL, E, 0, 'Z' ; Read this as: displaycharif BL is Equal to 0, character 'Z' This would display a Z if BL contains a 0 The macro definition: putcharif macro op1, cond, op2, char ;op1, op2 are operands to be compared, cond is the ... local doit, done ;condition to be tested, char is the character to be displayed cmp op1, op2 j&cond doit ;& is the concatination operator -- append value of cond to j jmp done doit: putchar char done: endm Example use of the putcharif macro: putcharif SI, L, BX, 'W' ; display a W if SI < BX 1 cmp SI, BX 1 jL ??0000 ; note L concatenated to j and ??0000 label generated by assembler 1 jmp ??0001 1 ??0000 putchar 'W' 2 mov AH,2 ; note level 2 nesting of macros generated by assembler 2 mov DL,'W' 2 int 21h 1 ??0001: Macros to emulate a for loop in assembly language: for i = first_i to last_i ;pseudo-code for a high level language for loop ... ... ;body of loop ... next i We'll use one macro (formac) to emulate the 'for' statement and another (endfor) to emulate the 'next' statement. Flow chart (The logic for the macros is enclosed in thick rectangles): Note from the flow chart that these macros are not independent. The formac macro must have a label (start_L) that will be jumped to from the endfor macro. and the endfor macro must have a label (end_L) that will be branched to conditionally from the formac macro. One way of doing this is to include the two labels as arguments in each of the two macros. Here they are: formac macro i, first_i, last_i, start_L, end_L mov i, first_1 start_L cmp i, last_i ja end_L inc i endm endfor macro start_L, end_L jmp start_L end_L: endm Let us now use these macros to display 3 A's to the screen: formac SI, 1, 3, ps, pf mov AH,2 mov DL,'A' ;output an A int 21h endfor ps, pf The assembler will expand these macros and generate code as follows: formac SI, 1, 3, ps, pf 1 mov SI, 1 1 ps: cmp SI, 3 1 ja pf 1 inc SI mov AH,2 mov DL,'A' ;output an A int 21h endfor ps, pf 1 jmp ps 1 pf: If you trace execution of the resulting code you will see that the body of the loop does indeed repeat itself three times. Macros could be used to implement many new and powerful instructions in a low-level language like assembly language. As an example see the WHILE/WEND macros that emulate a high level language while loop (http://www.cs.binghamton.edu/~reckert/220/whilemac.htm) Macros versus Procedures: Advantage of macros: Faster than procedures -- the code is actually inserted in the program; there is no need to call the code so the overhead of using the stack for the return address is avoided. In other words, the pushes and pops of the stack that are required to store and retrieve the return address each time the procedure is invoked are eliminated. Disadvantage of macros: Longer programs -- Each invocation of the macro causes the code to be inserted in the program. So if your code invokes the macro many times, the size of the program could become very large because of all the inserted macro code.