Asmtut 3: Redundancies

by
2012-10-19

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!)

, 2012