So, it’s official. If you want your assembly code to be at least as good as that produced by gcc, you should avoid using the “mul” instruction for multiplication by constants.

By the way, there are often several ways to achieve a multiplication by a series of shifts and adds. Here is my preferred way to multiply by 10. In this example, r4 holds the number to be multiplied and I want the result to be in r5.

Sometimes you will need to repeat something several times in your code. If it is a relatively small piece of code, you may be reluctant to turn it into a function since the branch and return commands may be almost as costly as the code you want to run. This is a good time to use a macro.

A macro is an assembler directive. You declare a macro at the start of the program. The assembler then looks through your code for occurences of the macro name and replaces them with the body of the macro. You can use parameters in a macro, so they are pretty flexible.

Here’s an example. One of my first programs was to calculate the gcd. It boils down to these lines:

gcd:
cmp r0, r1
subgt r0, r0, r1
sublt r1, r1, r0
bne gcd

Here’s a version of my gcd program in which I have made gcd into a macro.

As you can see, you declare a macro with a line that begins “.macro”. Following this is the name of the macro and any parameters used. The parameter names must be prefixed with a ‘\’ in the body of the macro. At the end of the macro definition we need “.endm”.

This particular example works fine and it will use whichever registers are passed to it to calculate the gcd. It doesn’t use any other registers, so there is no need to worry about other data getting “clobbered”.

Of course, you can write macros that do use named registers. Here’s a short program that uses a macro to print characters.

If you run this program it should print out the upper-case letters from A to Z. The macro uses printing, so that is going to clobber the registers r0, r1, r2 & r7. It might be wiser to use a function, but there are times when quick and dirty is the way to go and macros are very useful.

Here’s one more example. Here I’ve got a little modulus procedure that’s packaged as a macro.

As you can see this is another “safe” macro, like the gcd example. It works out the modulus of two numbers using only the registers that were passed to it. I am going to use this in my “Easter” algorithm to make the code a little cleaner.

When we looked at printing out numbers in a recent program, we had to make a conversion between a binary number stored in the computer and a series of ascii characters that could represent a denary number.

The same issue is faced when we want to get a number from the user and do something with it in an asm program. What follows is a simple solution to this problem. A string of characters is taken in from the keyboard and they are converted into a number that is stored in r0.

As you can tell, I am working my way towards having a few basic functions that I can use to create programs which can carry out mathematical operations as well as handling I/O.

The GNU debugger (gdb) is a very useful tool. Here I am going to show you one or two of its features.

You may need to install gdb (on my RPi, running Arch, the command was: “pacman -S gdb”). When you have done so, you can use it to look at what is happening as your program is running. This may help you to correct something that is going wrong. For now, though, we are going to look at a sample program that is working correctly.

If you want to use gdb, you need to invoke the assembler with some additional options. Adding the gdb functionality makes your executable larger, so you won’t want to do this unless you are actually planning a gdb session. The as command will look like this:

as -gstabs -o filename.o filename.s

Okay, here’s the sample program we are going to look at. It is very simple!

When gdb starts, we need to set a break-point. The execution of the program will stop there and we can step forwards one instruction at a time from that point. Here, I am setting the break-point at the _start label.

(gdb) break *_start
(gdb) run

After you have given the run command, gdb will execute the operations up to the break-point and await instructions. In this example, I typed “next” twice to cause the next two instructions to be executed. Then I typed “info registers” to see the contents of my registers.

As you can see, r1 holds the value 5. The stack pointer has an address in memory and the program counter shows where we are up to in the program.

The other register I am interested in is “cpsr”, this is the program status register which shows which flags have been set. At this point, its contents are not very interesting as we have not done any comparisons.

After one more instruction, the registers look like this:

You can see that the program counter shows we have moved 4 bytes forward (each instruction is 4 bytes). Also the program status register shows the result of comparing r1 with 4.

If we move on a couple of instructions, we get to this position.

Now r1 holds 4 and the “zero” flag on the cpsr has been set. This is because “cmp” actually does a subtraction and then sets the flags acordingly. Since 4 – 4 = 0, the zero flag is set.

If we move on once more, we come to this position.

We are now almost at the end of the program, r1 no longer equals 4 and so the last “cmp” instruction has caused the zero flag to be unset.

This will help you to remember to include the important sections of the program and the exit instructions.

Anything that starts with a full-stop is a directive to the assembler rather than an actual instruction. The final directive (“.end”) is optional, but I think it is useful. For instance, if the last line of your program has a comment on it, the assembler will complain.

Commenting your code is important. We can use ‘@’ to begin a comment in asm programs. I like to use the first line to record the name of the program.