This was originally posted on Google+, which has now been shut down. It was helpfully converted to Markdown by Robert Jacobson after which I adjusted it for reposting here. I have dated it at its original posting date, but it was posted here on 2019-09-07.
This time we will automate stuff with the assembler.
Step 6: String length
In our Hello world-implementation, we used a tedious and error prone mechanism to measure the length of the string: counting by brain. Let's offload that to the computer.
NASM doesn't realize that hello_world represents a string for us. For NASM it is just a label, and in fact we could have written hello_world: with a colon, just like the main:-label. However, we still know that it is a string, and we can calculate its length by adding a label after it:
hello_world: db "Hello World!", 0x0a
hello_world_end:
We tack the colon onto our labels to get rid of a warning from NASM.
Now, we can use the Critical Expression hello_world_end - hello_world
to calculate the length of the string in the code:
mov rdx, hello_world_end - hello_world
We can also define constants with the keyword equ:
hello_world_size equ hello_world_end - hello_world
Let's stick this in the data section right under hello_world_end, and later on use this as the string length:
mov rdx, hello_world_size
Even though the constant is in the data section, it will not be stored in the assembled binary as data. It will instead be substituted by its value during assembly. Inspect this with otool -d and otool -tv as we did before.
Finally, we can get rid of hello_world_end by using the special symbol $, which in NASM evaluates to the address at the beginning of the line. This is all we need:
hello_world db "Hello World!", 0x0a
hello_world_size equ $ - hello_world
Your asm-file might now look like this:
section .data
hello_world db "Hello World!", 0x0a
hello_world_size equ $ - hello_world
section .text
global main
main:
mov rax, 0x02000004 ; SYS_write
mov rdi, 1 ; filedes = STDOUT_FILENO = 1
mov rsi, hello_world ; buf = The address of hello_world string
mov rdx, hello_world_size ; nbyte
syscall
mov rax, 0x02000001 ; SYS_exit
mov rdi, 0 ; Exit status
syscall
Step 7: Repetition
Let's print out a snake game board instead of the boring greeting. For this, we will need to repeat lots of stuff. Luckily, NASM has a pseudo-instruction for simple repetitions: TIMES
board:
times 80 db "X"
db 0x0a
board_size equ $ - board
Printing board instead of hello_world should now give you a nice line of X-es.
Let's have four walls:
board:
; North wall:
times 80 db "X"
db 0x0a
; One line of west and east walls:
db "X"
times 78 db " "
db "X", 0x0a
; Another line of west and east walls:
db "X"
times 78 db " "
db "X", 0x0a
; South wall:
times 80 db "X"
db 0x0a
board_size equ $ - board
Your source code might now look like part2.asm.
Step 8: Macros
This is getting ridiculous to read and write. We already know how to get rid of the repeated numerical constant; Add "width equ 80", and substitute the numerical literals appropriately.
However, we have an additional ace up our sleeve to help with this explosion of lines: Macros.
width equ 80
%macro full_line 0
times width db "X"
db 0x0a
%endmacro
%macro hollow_line 0
db "X"
times width-2 db " "
db "X", 0x0a
%endmacro
These are of course also hideous, but they make the data definition slightly less so:
board:
full_line
hollow_line
hollow_line
full_line
If you are anything like me, you are probably planning on applying TIMES
to the macros. That doesn't work, but luckily %rep
does:
board:
full_line
%rep 25
hollow_line
%endrep
full_line
Macros can have parameters, and the 0s above is us declaring that there will be zero parameters.
Your code should now be similar to part3.asm which outputs a lovely playful area just begging for a game of snake!
Exercise: Make something nice with macros. I'm pretty sure there must be an even less ugly way of defining this data :) It should be possible to make a macro that takes in width and height and spits out a box.
UPDATE: Solution by Knut at http://www.pastebin.com/XszHNdcx
Next lesson: Asmtut 4: Input (Will contain proper assembly! I promise!)