Welcome to the introduction to ARM assembly and IArm
ARM is a RISC CPU architecture that is commonly used on embeded devices.
Assembly is a low level programming language. It is generally used for very performant code, very efficient code, or for direct access to the hardware.
IArm is an ARM assembly language interpreter. Normally, assembly is compiled from the source code to machine code. This machine code is then run on the CPU. IArm allows you to write code on your computer, and run it step by step, without the need for the actual hardware.
Each assembly line is broken up into three parts. The first part is the label. The label is used to reference whatever this particular line of code is. It can be used for loops, or for holding addresses of memory. The label is optional, so only use it when needed.
The second part is the instruction. This is the actual instruction that will be executed.
The last part is the instruction operands. These will be used by the instruction to perform the action.
[Label] Instruction [Operand1[, Operand2[, Operand3]]]
It is important to note that if no label is used, the instruction must be spaced or tabbed over. Any word that begins on a line with no spaces to the left will be interpreted as as a label.
The first instruction is the MOVS
instruction.
MOVS
stands for "Move, set" which will move the value of
operand 2 into the register in operand 1 and set the status register.
The MOVS
instruction must be used to load in immediate.
Comments can also be added, and start with ;
.
Anything after a ;
will be ignored.
To execute the code, select the cell and press Shift + Enter
; Put the value 5 into register 0
MOVS R0, #5
This will put the code into a program that can be executed. If there were any problems with the code, an error will be reported.
In order to read a register in IArm,
we need to use the %register
magic function.
This will print out the value of the register.
You can also use %reg
for short.
%reg R0
R0: 0
Why is the value 0?
We did not instruct IArm to run the code,
so it is simply spitting out the initial value which is 0.
To run the code, we specify the %run
magic,
which will run to the end of our current program.
the %run
magic also can take in an integer
to specify how many instructions to run.
%run
%reg R0
R0: 5
The ARM instruction set comes with a multitude of mathematical instructions to add, subtract, and multiply (no divide though).
; Add R0 and 1 and store it in R1
ADDS R1, R0, #1
; Subtract 10 from R1 and store it in R2
SUBS R2, R1, #7
; Multiply R0 by 5
MOVS R3, #5
MULS R3, R0, R3 ; Operand 1 and Operand 3 must be the same register
; Integer divide by 4 by bit shifting to the right by 2
LSRS R5, R3, #2
When looking at registers, we can specify multiple registers,
separated by spaces.
Ranges can also be used by specifying the start and end register,
separated by a hyphen (Rn-Rk
)
%run
%reg R0-R3 R5
R0: 5 R1: 6 R2: 4294967295 R3: 25 R5: 6
"Whoa, whats going on with R2?". We should have gotten -1, why is it in the millions?
It is -1, that is just the unsigned integer notation for it.
To turn on signed representations,
simply call the %signed
magic.
%signed
%reg R2
R2: -1
Values can also be represented in hexadecimal by using the %hex
magic.
%hex
%reg R2 R0 R3
R2: 0xffffffff R0: 0x5 R3: 0x19
To go back to the unsigned representation, use the %unsigned
magic.
%unsigned
%reg R2 R0 R3
R2: 4294967295 R0: 5 R3: 25
You can get help on any particular magic or instruction by using the %help
magic.
Calling it with no parameters will list all available magics,
while calling it with a magic or instructin will print out its help.
%help
%register %run %postpone_execution %help %generate_random %memory %signed %mem %hex %reg %unsigned
%help unsigned
unsigned All outputted values will be displayed with their unsigned representation Usage: Just call this magic `%unsigned`
%help ADDS
ADDS ADDS Ra, Rb, Rc ADDS Ra, Rb, #imm3 ADDS Ra, Ra, #imm8 Add the result of the last two operands and store the result in the first operand. Set the NZCV flags
Memory can be accessed with the LDR
and STR
.
; Clear R2
MOVS R2, #0
; Load an address into R0
MOVS R0, #4
MOVS R1, #12
STR R1, [R0, #0] ; Store 11 at byte 4
LDR R2, [R0, #0] ; Load the word at byte 4 and put it into R2
%run
%reg R1 R2
R1: 12 R2: 12
There is also a stack that can be accessed with the PUSH
and POP
instructions.
MOVS R0, #100
PUSH {R0} ; List of registers separated by commas
POP {R5}
%run
%reg R0 R5
R0: 100 R5: 100
In order to make programing easier, one can write subroutines. These are similar to functions. Instead of being called, they are branched to. They will then return to the next instruction after the branch.
To branch to a subroutine, use the BL
instruction.
This puts the next instructions address into the Link Register,
a register specifically for use with branching.
To return from an instruction, use the BX
instruction.
You can also PUSH
the link register into the stack,
and then POP
into the PC
register.
This allows for multi-subroutine calls.
B main ; Branch to the main code. This is to avoid executing the subroutine
; factorial
; Compute the factorial of the value in R0, storing the result in R1
; Uses R2, but saves state
factorial
PUSH {LR, R2} ; Save the return address and the value of R2
MOVS R1, #1 ; Init the result to 1 (0! and 1! = 1)
MOVS R2, #1 ; Init the coutner to 1
f_compare CMP R0, R2 ; R0 - R2, set flags
BEQ f_cleanup ; Are R0 and R2 equal?
ADDS R2, R2, #1 ; Add one to the counter
MULS R1, R2, R1 ; Multiply the current result with the coutner
B f_compare ; Check to see if we are done
f_cleanup POP {PC, R2} ; Restore R2, then jump to the address
main
MOVS R2, #0
MOVS R0, #5
BL factorial
%run
%reg R0-R2
R0: 5 R1: 120 R2: 0
%postpone_execution false
%reg R7
MOVS R7, #1
%reg R7
R7: 0 R7: 1
In a simulator, when a value is not initalized but is read from, normally zero is returned.
This is not the case in hardware, where random bits will be set unless explicitly set so.
This behaviour can be mimiced by setting the %generate_random
magic.
This is by default set to false.
Once read, this will be the value until set.
%reg R11
%generate_random true
%reg R11
%reg R11
R11: 0 R11: 1514712368 R11: 1514712368