This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| en:multiasm:papc:chapter_6_13 [2024/09/27 20:40] – created pczekalski | en:multiasm:papc:chapter_6_13 [2025/11/17 08:54] (current) – [Predefined macro functions] ktokarz | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== | + | ====== |
| + | Macros are elements of language that enable the replacement of one text with another. In assembler language, macros can be implemented differently in different assemblers understood as programming software. In this chapter, we'll present the MASM implementation. Although in other assemblers (NASM, NASM) the syntax can differ, the idea remains the same. There are a few types of macros in MASM: | ||
| + | * Text macros, | ||
| + | * Macro procedures, | ||
| + | * Repeat blocks, | ||
| + | * Macro functions, | ||
| + | * Predefined macro functions, | ||
| + | * String directives. | ||
| + | We'll go through all of them in the following sections. | ||
| + | |||
| + | ===== Text macros ===== | ||
| + | Text macros are a simple replacement of one text with another. They are defined with the directive **TEXTEQU**, | ||
| + | |||
| + | <code asm> | ||
| + | name TEXTEQU < | ||
| + | name TEXTEQU macroId | textmacro | ||
| + | name TEXTEQU %constExpr | ||
| + | </ | ||
| + | |||
| + | Using text macros, it is possible to name some constants like PI, shorten other directives, and even create your own instruction names. | ||
| + | |||
| + | <code asm> | ||
| + | pi | ||
| + | WPT TEXTEQU <WORD PTR> ; Sequence of keywords | ||
| + | copy | ||
| + | </ | ||
| + | |||
| + | Previously defined text macro can be redefined later in the program. | ||
| + | <code asm> | ||
| + | message TEXTEQU <Hello World!> ; Define message with the text "Hello World!" | ||
| + | message TEXTEQU <Good Bye!> | ||
| + | </ | ||
| + | |||
| + | The explanation of percent operator is shown in the following code. | ||
| + | <code asm> | ||
| + | sum TEXTEQU < | ||
| + | sum TEXTEQU %(3+9) | ||
| + | </ | ||
| + | ===== Macro procedures ===== | ||
| + | Macro procedure is a definition of a fragment of code that can be used later in the resulting program. In some assemblers, they are named multi-line macros. The use of the name of a macro procedure later in the source program causes the so-called expansion of the macro. It is worth noting that for every usage of the macro, the assembler will place in the resulting program all elements specified in the statements inside the macro. These include: | ||
| + | * instructions, | ||
| + | * directives, | ||
| + | * pseudoinstructions. | ||
| + | |||
| + | The simplest definition of a macro procedure contains the name, **MACRO** keyword, a list of statements inside the macro and **ENDM** at the end | ||
| + | <code asm> | ||
| + | name MACRO | ||
| + | statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | Please note that no macro name is repeated before the ENDM directive. | ||
| + | </ | ||
| + | |||
| + | Macro procedure can have parameters. They are treated as macros themselves, so the use of the parameter name inside the macro results in the replacement of it with the actual value. | ||
| + | <code asm> | ||
| + | name MACRO parameterlist | ||
| + | statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | An example of a simple macro which makes a copy of data from the source to the destination can be seen in the following code. | ||
| + | <code asm> | ||
| + | copy MACRO arg1, arg2 | ||
| + | mov RAX, arg1 | ||
| + | mov arg2, RAX | ||
| + | | ||
| + | </ | ||
| + | Note that the arguments of the macro must fit the instructions used inside it. They can be previously defined variables, the first argument can be a constant, or you can even pass the names of other registers. | ||
| + | |||
| + | <code asm> | ||
| + | ; Three following lines with " | ||
| + | |||
| + | copy 65, x_coeff | ||
| + | copy x_coeff, RBX | ||
| + | copy RBX, RCX | ||
| + | |||
| + | ; Will be expanded as | ||
| + | |||
| + | mov RAX, 65 | ||
| + | mov x_coeff, RAX | ||
| + | mov RAX, x_coeff | ||
| + | mov RBX, RAX | ||
| + | mov RAX, RBX | ||
| + | mov RCX, RAX | ||
| + | </ | ||
| + | |||
| + | If the actual parameter is empty, it may result in an error in the expanded line, because empty parameters are assumed as empty texts. | ||
| + | <code asm> | ||
| + | ; Use of " | ||
| + | copy RBX | ||
| + | |||
| + | ; Will result in | ||
| + | mov RAX, RBX | ||
| + | mov , RAX ; this line is invalid and will cause an error | ||
| + | </ | ||
| + | |||
| + | The solution to avoid such a situation is to assign the default parameter value or mark the parameter as required. In the first case, the default value will be assigned to the missing parameter. | ||
| + | <code asm> | ||
| + | ; The " | ||
| + | copy MACRO arg1:=0, arg2:=RCX | ||
| + | mov RAX, arg1 | ||
| + | mov arg2, RAX | ||
| + | | ||
| + | |||
| + | ; Use of " | ||
| + | copy | ||
| + | |||
| + | ; Will result in | ||
| + | mov RAX, 0 | ||
| + | mov RCX, RAX | ||
| + | </ | ||
| + | |||
| + | In the second case, the error will be signalled, but at the line with a macro use, not inside the macro, which makes it easier to localise the error. | ||
| + | <code asm> | ||
| + | ; The " | ||
| + | copy MACRO arg1:REQ, arg2:REQ | ||
| + | mov RAX, arg1 | ||
| + | mov arg2, RAX | ||
| + | | ||
| + | |||
| + | ; Use of " | ||
| + | copy RBX ; this line will cause an error | ||
| + | </ | ||
| + | |||
| + | If a label needs to be defined inside the macro, it must be declared as local to avoid ambiguity. In general, any symbol can be declared as local. In such a case, it will only be visible inside the macro. The **LOCAL** directive can be used for this purpose. It must appear in the line next to the **MACRO** statement. | ||
| + | |||
| + | <code asm> | ||
| + | copy MACRO arg1, arg2 | ||
| + | LOCAL jump_over, jump_end | ||
| + | |||
| + | cmp RAX, arg1 ; test if RAX = arg1 | ||
| + | je jump_over | ||
| + | mov RAX, arg1 | ||
| + | |||
| + | jump_over: | ||
| + | cmp RAX, arg2 ; test if RAX = arg2 | ||
| + | je jump_end | ||
| + | mov arg2, RAX | ||
| + | |||
| + | jump_end: | ||
| + | | ||
| + | </ | ||
| + | ===== Repeat blocks ===== | ||
| + | Repeat blocks are macros automatically repeated. The number of repetitions depends on the condition, or is determined by the constant value, or the list of argument values. | ||
| + | The **REPEAT** block is expanded the number of times specified in the constant expression. | ||
| + | <code asm> | ||
| + | REPEAT constexpr | ||
| + | Statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | The **WHILE** block is expanded as long as the condition is true. The condition can be any expression that evaluates to zero (false) or nonzero (true). | ||
| + | |||
| + | <code asm> | ||
| + | WHILE expression | ||
| + | Statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | The **FOR** block is expanded for each argument in a list. The parameter is a placeholder that represents the name of each argument | ||
| + | The argument list must contain comma-separated arguments and must be enclosed in angle brackets. | ||
| + | |||
| + | <code asm> | ||
| + | FOR parameter, < | ||
| + | Statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | The **FORC** is similar to **FOR** but takes a string of text rather than a list of arguments. The text must be enclosed in angle brackets. Statements inside the block are assembled once for each character from the string. | ||
| + | <code asm> | ||
| + | FORC parameter, < | ||
| + | Statements | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | Now, let's examine four repeat blocks that result in the same data definitions. All of them define five bytes with initialising values from 1 to 5. | ||
| + | <code asm> | ||
| + | i = 1 | ||
| + | REPEAT 5 | ||
| + | DB i | ||
| + | i = i + 1 | ||
| + | ENDM | ||
| + | |||
| + | i = 1 | ||
| + | WHILE i < 6 | ||
| + | DB i | ||
| + | i = i + 1 | ||
| + | ENDM | ||
| + | |||
| + | FOR i,< | ||
| + | DB i | ||
| + | ENDM | ||
| + | |||
| + | FORC i,< | ||
| + | DB i | ||
| + | ENDM | ||
| + | </ | ||
| + | |||
| + | ===== Macro functions ===== | ||
| + | |||
| + | A macro function is a macro which returns a value. As all macros are tex processing feature macro functions always return text. Returning the value is possible with the use of the **EXITM** directive. Argument of the **EXITM** must be text or the result of another macro function. Numeric values must be converted to text form with the expansion operator %. | ||
| + | |||
| + | ===== Predefined macro functions ===== | ||
| + | Masm offers a set of predefined macro functions, usually used to process texts. There are two versions of them. First is the macro function, which returns the resulting text. Second is the directive, which returns the same text and additionally creates a new symbol. The macro function **@SubStr** returns part of a source string. The **SUBSTR** directive assigns part of a source string to a new symbol. The macro function **@InStr** searches for one string within another and returns its position. The **INSTR** creates a new symbol containing the position of one string in another. The macro function **@SizeStr** determines the string size. The **SIZESTR** creates a new item and assigns to it the size of a string. The macro function **@CatStr** concatenates one or more strings to a single string and returns a concatenated string. The **CATSTR** directive concatenates one or more strings to a newly defined string. The following code demonstrates the equivalent use of both versions. | ||
| + | <code asm> | ||
| + | name SUBSTR string, start [, length ] | ||
| + | name INSTR [[start]], string, substring | ||
| + | name SIZESTR string | ||
| + | name CATSTR string [[, string ]] | ||
| + | |||
| + | name TEXTEQU @SubStr (string, start [, length ]) | ||
| + | name TEXTEQU @InStr ([[start]], string, substring) | ||
| + | name TEXTEQU @SizeStr (string) | ||
| + | name TEXTEQU @CatStr (string [[, string ]]) | ||
| + | </ | ||