Assembly

wiki

Compilation

TODO: fill this section with instructions on how to compile assembly code

  • .s -> .o

  • .o -> .exe linking

  • windows

  • linux

Memory Layout of a Program

memory layout

Directives

.globl

The .globl directive is useful when working with multiple files, and we need parts of code to reference labels in other files. If you don't use .globl, during the linking process, it can't find the label and gives an error.

We could have a main.asm file like this:

.globl main
.data
.text
    main: 
        li $a0, 5
        jal fibonacci
        ...

And a second file math.asm with the fibonacci function:

.globl fibonacci
.data
.text
    fibonacci:
       mv $t0, $a0 
       ...

.ent

There is a .ent directive too, which is a debugger pseudo operation that marks the entry of main.

.globl main
.ent main
.text
    main:
        ...

Pseudo-Instructions

Many instructions provided by MIPS, like move, lw etc... are decomposed into multiple instructions when the code is assembled; for more details. For example:

lw

lw $s0, value is mapped to:

lui $1, 0x00001001
lw $16, 0x00000000($1)

In the second case, 0x10010000 is the address of value, to get this address, we need to lui 0x00001001 (load upper immediate, loads the immediate value in the upper 16bits of the $1 register, which is the $at register). Then we can load into $16, which is the $s0 register, whatever value is at the address 0 + $at (0x00000000($1))

move

move $t0, $s0 is mapped to addu $8, $0, $16, where addu is the "add unsigned" operation, and $8 is $t0, $0 is the $zero constant register and $16 the $s0 register.

beq

ble $s1, $t0, label is mapped to:

slt $1, $8, $17
beq $1, $0, 0x00000001

Now, slt (set less than) sets the value in rs to 1 if rt is less than rd (if you don't know what rs, rt and rd are, check R-Type Instructions)

Absolute Jump

MIPS instructions have a fixed 32 bit size... what happens when you need to jump to an address which is a 32 bit constant? Neither I-type or J-type support 32 bit constants. We need to use lui and ori.

Let's suppose we have to jump at the address 0000_0000_1111_1111_0000_1001_0000_0000, which corresponds to 0x00ff0900.

lui $t0, 0x000000ff
ori $t0, 0x00000900
jr $t0

What lui does is moving the lower 16 bits 0x00ff into the upper part of register $t0, that way we have 0x00ff0000 in $t0. Now, we use ori (which does a bitwise or, basically compares with an or for each bit in $t0 with the value 0x00000900 for the lower half of the byte) so we have the full address. Now we can just use jr to jump to the address in the register.