Say hello to x86_64 Assembly [part 5]
http://0xax.blogspot.sg/2014/11/say-hello-to-x8664-assembly-part-5.html
It is a fifth part of Say hello to x86_64 Assembly and here we will look at macros. It will not be blog post about x86_64, mainly it will be about nasm assembler and it's preprocessor. If you're interesting in it read next.
Macros
NASM supports two form of macro:
- single-line
- multiline
All single-line macro must start from %define directive. It form is following:
| %define macro_name(parameter) value |
Nasm macro behaves and looks very similar as in C. For example, we can create following single-line macro:
| %define argc rsp + 8 | |
| %define cliArg1 rsp + 24 |
and than use it in code:
| ;; | |
| ;; argc will be expanded to rsp + 8 | |
| ;; | |
| mov rax, [argc] | |
| cmp rax, 3 | |
| jne .mustBe3args |
Multiline macro starts with %macro nasm directive and end with %endmacro. It general form is following:
| %macro number_of_parameters | |
| instruction | |
| instruction | |
| instruction | |
| %endmacro |
For example:
| %macro bootstrap 1 | |
| push ebp | |
| mov ebp,esp | |
| %endmacro |
And we can use it:
| _start: | |
| bootstrap |
For example let's look at PRINT macro:
| %macro PRINT 1 | |
| pusha | |
| pushf | |
| jmp %%astr | |
| %%str db %1, 0 | |
| %%strln equ $-%%str | |
| %%astr: _syscall_write %%str, %%strln | |
| popf | |
| popa | |
| %endmacro | |
| %macro _syscall_write 2 | |
| mov rax, 1 | |
| mov rdi, 1 | |
| mov rsi, %%str | |
| mov rdx, %%strln | |
| syscall | |
| %endmacro |
Let's try to go through it macro and understand how it works: At first line we defined PRINT macro with one parameter. Than we push all general registers (with pusha instruction) and flag register with (with pushf instruction). After this we jump to %%astr label. Pay attention that all labels which defined in macro must start with %%. Now we move to__syscall_write macro with 2 parameter. Let's look on __syscall_write implementation. You can remember that we use writesystem call in all previous posts for printing string to stdout. It looks like this:
| ;; write syscall number | |
| mov rax, 1 | |
| ;; file descriptor, standard output | |
| mov rdi, 1 | |
| ;; message address | |
| mov rsi, msg | |
| ;; length of message | |
| mov rdx, 14 | |
| ;; call write syscall | |
| syscall |
In our __syscall_write macro we define first two instruction for putting 1 to rax (write system call number) and rdi (stdout file descriptor). Than we put %%str to rsi register (pointer to string), where %%str is local label to which is get first parameter of PRINT macro (pay attention that macro parameter access by $parameter_number) and end with 0 (every string must end with zero). And %%strlen which calculates string length. After this we call system call with syscall instruction and that's all.
Now we can use it:
| label: PRINT "Hello World!" |
Useful standard macros
NASM supports following standard macros:
STRUC
We can use STRUC and ENDSTRUC for data structure defintion. For example:
| struc person | |
| name: resb 10 | |
| age: resb 1 | |
| endstruc |
And now we can make instance of our structure:
| section .data | |
| p: istruc person | |
| at name db "name" | |
| at age db 25 | |
| iend | |
| section .text | |
| _start: | |
| mov rax, [p + person.name] |
%include
We can include other assembly files and jump to there labels or call functions with %include directive.
Conclusion
It was a fifth part of series 'say hello to x64 assembly', if you will have a questions/suggestions write me a comment or ping me at twitter for discussing. In next part we will talk about difference between Intel syntax and AT&T and look at gas assembly. If you're interesting in some additional themes about assembly and x86_64 programming write me a comment and I will try to write blog post about it in near time.
All another parts you can find - here.
All source code you can find as every time - here.
English is not my first language, so you'll find mistakes in blog post please write me in comments or drop me email .
浙公网安备 33010602011771号