ARMv7
Saturday, 28 June 2025 10:50 PM
R1 to R6 are general Purpose Registers
SP tells where next piece of memory is going to be available in Memory Stack
00000000 | 00000-address | 000000-> address +4 | 000000-> address +8 | 00000->address+16
lr registers are link registers
When you have function with return, it allows us to move back to function.
Pc are program counters -> All instructions are stored in memory and it moves piece by piece
with track from pc Register
CPSR register is special type, used to store information about our program.
If you subtract two number. 2s compliment -> end up with -ve number.
It could also be positive number. We need to know its sign
It sets flag if result was negative or positive, carry or overflow.
.global _start
_start:
MOV R0,#30. --? You can also write hex which is #0xA
MOV R7,#1
SWI 0
ARM is Bi-Endian -> LSB or MSB
LDR -> load Data from stack into register
.data list: stack
.global _start
_start:
LDR R0,=list
.data
list:
.word 4,5,-9,1,0,2,-3
LDR R1,[R0] // -> Indirect addressing
R1 value changes to whatever is stored in R0
OFFSET:
LDR R2,[R0,#4] //-> offset of 4 should point to R0 address + 4
In high level context it will be R0+1 location . Remember next location address is always with
difference of 4.
In high level context it will be R0+1 location . Remember next location address is always with
difference of 4.
Pre-increment:
LDR R2,[R0,#4]!
Increase R0 and then add the offset which will be 8?
Pass anything inside R0 to R2 then Increase R0
Post Increment:
LDR R2,[R0],#4
ARITHMETIC:
ADD:
.global _start
_start:
MOV R0,#5
MOV R1,#7
ADD R2,R0,R1 //R2 = R0 + R1
SUB:
.global _start
_start:
MOV R0,#5
MOV R1,#7
SUB R2,R0,R1 //R2 = R0 - R1
_start:
MOV R0,#5
MOV R1,#7
SUB R2,R0,R1 //R2 = R0 - R1
IF YOU SEE THE R2 HEX VALUE SEEMS TO BE LARGE NUMBER. BUT THIS IS OVERLAP. HOW DO
WE KNOW THE DIFFERENCE?
Using CPSR register for the above case:
Here NZCVI indicate flags. N for ex is negative.
SUBS R2,R0,R1 -> This is the operation -> use it when there is going to be negative.
Or you don't know what values are being subtracted.
Why because it can be an added step of loading value into CPSR register.
8 -> it is the indicator of Negative number. Flags in real environment will not be displayed.
Carry Example:
.global _start
_start:
MOV R0,#0xFFFFFFFFFF
MOV R1,#3
ADDS R2,R0,R1 //R2 = R0 + R1
Its far too big to be stored in one register. You can use this carry after some point using ADC:
.global _start
_start:
MOV R0,#0xFFFFFFFFFF
MOV R1,#3
ADC R2,R0,R1 //R2 = R0 + R1 + Carry(0 if it is not set, 1 if carry
is set)
Logical operators in ARM:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
AND R2,R0,R1
To Use Flags:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
ANDS R2,R0,R1
OR:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
ORR R2,R0,R1
To Use Flags:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
ANDS R2,R0,R1
OR:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
ORR R2,R0,R1
XOR:
.global _start
_start:
MOV R0,#0xFF
MOV R1,#22
EOR R2,R0,R1
r0 = 0xFF = 1111 1111
r1 = 0x16 = 0001 0110
-----------------------
XOR result = 1110 1001 = 0xE9
Negation:
.global _start
_start:
MOV R0,#0xFF
MVN R0,R0
.global _start
_start:
MOV R0,#0xFF
MVN R0,R0
AND R0,R0,#0x000000F
Clear Specific bits in the register.
R0 = 0xFFFFFF00 & 0x0000000F
= 0x00000000
Logical Shifts:
Left and Right.
What direction the bits are shifting.
1010 -> 10
Logical shift Left:
10100 -> 20 -> fast way to do multiplication by 2.
Logical Shift Right:
0101 -> 5 -> fast way to dividing by 2.
LoR/RoR (Rotation):
0000101 -> 1000010 (RoR) -> Used for things like Hashing/Crypto and so on.
RoL doesn't exist in ARM.
Alternate: Rotate Right 32-N times for L position
Shift Left:
.global _start
_start:
MOV R0,#10
LSL R0,#1
.global _start
_start:
MOV R0,#10
LSL R0,#1
Shift Right after Shift Left:
.global _start
_start:
MOV R0,#10
LSL R0,#1
LSR R0,#1
Mov and Shift at the same time:
.global _start
_start:
MOV R0,#10
MOV R1,R0
LSL R0,#1
LSR R1,#1
Alternatively:
.global _start
_start:
MOV R0,#10
MOV R1,R0,LSL #1
Conditional Statements:
.global _start
_start:
MOV R0,#1
MOV R1,#2
CMP R0,R1
BGT greater
greater:
MOV R2,#1
Won't work:
Somewhat fine but still the instruction will continue till greater label:
Somewhat fine but still the instruction will continue till greater label:
How to skip the greater label?
Other comparisons:
BLT
BLE
BGE
BEQ
BNE
Loops with Branches:
Empty memory spaces could be indicated by "aaaa…"
.global _start
_start:
LDR R0,=list
LDR R1,[R0]
ADD R2,R2,R1
.data:
list:
.word: 1,2,3,4,5,6,7,8,9,10
Bigger than two Hex values we have to be more creative with it. Its done with Constants.
.equ name, value (initial)
.global _start
.equ endlist, 0xaaaaaaaa
_start:
LDR R0,=list
LDR R3,=endlist
LDR R1,[R0]
ADD R2,R2,R1
loop:
LDR R1,[R0,#4]!
CMP R1,R3
BEQ exit
ADD R2,R2,R1
BAL loop
exit:
.data:
list:
.word: 1,2,3,4,5,6,7,8,9,10
Alternative to detecting end, \0
Why using : after keyword causes initialization error:
work/asmOmY3tO.s:18: Error: symbol `.data' is already defined
Compile failed.
Own example:
.global _start
.equ endlist, 0xaaaaaaaa
_start:
LDR R0,=list
LDR R3,=endlist
LDR R1,[R0]
ADD R2,R2,R1
loop:
LDR R1,[R0,#4]!
CMP R3,R1
BLE exit
SUB R2,R2,R1
Compile failed.
Own example:
.global _start
.equ endlist, 0xaaaaaaaa
_start:
LDR R0,=list
LDR R3,=endlist
LDR R1,[R0]
ADD R2,R2,R1
loop:
LDR R1,[R0,#4]!
CMP R3,R1
BLE exit
SUB R2,R2,R1
BAL loop
exit:
.data
list:
.word 10,9,8,7,6,5,4,3,2,1
Conditional Instruction Execution:
.global _start
_start:
MOV R0,#1
MOV R1,#4
CMP R0,R1
ADDLT R2,#1 //Put 1 in R2 is the value is less than
Negative Flag gets set in the CPSR register because of the comparison, that tells us the value is
less than:
Put 1 in R2 is the value is less than.
Move only if Greater than or equal to:
.global _start
_start:
MOV R0,#2
MOV R1,#4
CMP R0,R1
MOVGE R2,#1
Doesn't trigger as the Value of cpsr is not greater than 1
Triggers when greater:
Return:
Branch Linked using lr register
.global _start
_start:
MOV R0,#1
MOV R1,#3
BL add2 //Branch Linked -
// store at the location that follow this branch inside of LR register
MOV R3,#4 // What if we wanna continue
//executing the instruction after branching?
add2:
ADD R2,R0,R1
bx lr // branch back to lr
//executing the instruction after branching?
add2:
ADD R2,R0,R1
bx lr // branch back to lr
Utilizing Same resources in multiple areas like global and local with Stack
and Link Register:
.global _start
_start:
// We may need to resue the regieter that was used outside a
function,
// inside of the function as resource is less on Assy
MOV R0,#1
MOV R1,#3
PUSH {R0,R1} // Put these regs into stack register.
BL get_value
POP {R0,R1} // Pop them out once R0 and R1 local use has been
completed
B end
get_value:
//Resuse R0 and R1, by overwriting them inside.
MOV R0,#5
MOV R1,#7
ADD R2,R0,R1
BX lr // Link back to global R0 and R1
Stack pushed with address 12
In sp 0+8 there is 1 and next to it is 3 which are values of R0 and R1 initially.
At this step, the values of R0 and R1 have been overridden by get_value function:
Link back and popped stack items, R0 and R1 are back to their initial global value:
Link back and popped stack items, R0 and R1 are back to their initial global value:
Interacting with variety of Hardware using ARM processor:
Load address of the device address:
.equ SWITCH, 0xff20040
.global _start
_start:
LDR R0,=SWITCH
WITH LED display:
.equ SWITCH,0xff200040
.equ LED,0xff200020
.global _start
_start:
LDR R0,=SWITCH
LDR R1,[R0]
LDR R0,=LED
STR R1,[R0]
Command:
qemu-system-arm kernel-qemu-4.4.34-jessie \\
-cpu arm1176 -m 256 -M versatilepb stdio \\
-append "root=/dev/sda2 rootfstype=ext4 rw" -hda \\
-nic user,hostfwd=tcp::5022-:22 -no-reboot
Using GDB:
gdb helloworld
breakpoint
run
stepi
x/<decimal size><type of encoding (x,c,b,d)> $<register address>
Will show <decimal size> memory address values starting from the register.