Introduction
This is a memo from my ARM assembly studies. It explains how to convert between ARM assembly and machine code, and how the instruction encoding works. Please note that some details may be incorrect.
Machine Language
ARM uses 32-bit instructions. Instructions are classified into data processing instructions, memory instructions, branch instructions, and other instructions.
Basic form
*Top: bit positions. Bottom row: contents.
| 31:28 | 27:26 | 25:20 | 19:0 |
|---|---|---|---|
| cond | op | funct | - |
Field descriptions
- cond: Condition code cond=1110: Always execute
- op: Operation code Check this first to determine the instruction type.
- op=00: data processing instruction
- op=01: memory instruction
- op=10: branch instruction
- funct: function The format changes depending on whether the instruction is for data processing, memory access, or branching.
- -: The format changes depending on the instruction.
Data Processing Instructions
Instructions executed when op=00
Basic form
*Top: bit positions. Bottom row: contents.
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:0 |
|---|---|---|---|---|---|---|---|
| cond | op | I | cmd | S | Rn | Rd | Src2 |
Field descriptions
- I: Selects an immediate value or a register. This changes the format of Src2.
- I=1:immediate value
- I=0: register or shifted register
- cmd: data processing instructions This determines the data processing operation.
- S: Update condition flags
- S=1: Update
- S=0: Do not update
- Rd: Register 1
- Rn: Register 2
- Src2: Source 2
cmd values
| cmd | format | description | behavior |
|---|---|---|---|
| 0000 | AND Rd,Rn,Src2 | Bitwise AND | Rd ← Rn & Src2 |
| 0001 | EOR Rd,Rn,Src2 | Bitwise XOR | Rd ← Rn ^ Src2 |
| 0010 | SUB Rd,Rn,Src2 | Subtraction | Rd ← Rn - Src2 |
| 0011 | RSB Rd,Rn,Src2 | Reverse subtraction | Rd ← Src2 - Rn |
| 0100 | ADD Rd,Rn,Src2 | Addition | Rd ← Rn + Src2 |
| 0101 | ADC Rd,Rn,Src2 | Carry addition | Rd ← Rn + Src2 + C |
| 0110 | SBC Rd,Rn,Src2 | Subtraction with carry | Rd ← Rn - Src2 - C |
| 0111 | RSC Rd,Rn,Src2 | Reverse subtraction with carry | Rd ← Src2 - Rn - C |
| 1000 | TST Rn,Src2 | Test | Set flag based on Rn & Src2 |
| 1001 | TEQ Rn,Src2 | Test for equality | Set flag based on Rn^Src2 |
| 1010 | CMP Rn,Src2 | Compare | Set flag based on Rn -Src2 |
| 1011 | CMN Rn,Src2 | Negative comparison | Set flag based on Rn + Src2 |
| 1100 | ORR Rd,Rn,Src2 | Bitwise OR | Rd ← Rn | Src2 |
| 1101 | Shift | See table below | |
| 1110 | BIC Rd,Rn,Src2 | Clear each bit | Rd ← Rn & ~Src2 |
| 1111 | MVN Rd,Src2 | Bitwise negation | Rd ← ~Src2 |
- Format example In this case, R1=Rd, R2=Rn, #12=Src2.
ADD R1,R2,#12
Shift details
When I=1, the instruction is a move instruction. When I=0, it is a shift or rotate instruction.
When I=0, the instruction is determined from sh.
*Exception 1: If I=0, sh=00, and shmat5=00000, it becomes a move instruction (MOV).
*Exception 2: If I=0, sh=11, and shmat5=00000, it becomes an extended rotate-right instruction (RRX).
Shift breakdown when I=1
| Format | Description | Behavior |
|---|---|---|
| MOV Rd,Src2 | Move | Rd ← Src2 |
Shift details when I=0
| sh | Format | Description | Behavior |
|---|---|---|---|
| 00 | LSL Rd,Rm,Rs/shmat5 | Logical left shift | Rd ← Rm << Src2 |
| 01 | LSR Rd,Rm,Rs/shmat5 | Logical right shift | Rd ← Rm >> Src2 |
| 10 | ASR Rd,Rm,Rs/shmat5 | Arithmetic right shift | Rd ← Rm >> Src2 |
| 11 | ROR Rd,Rm,Rs/shmat5 | Right rotation | Rd ← Rn ror Src2 |
Instructions for which condition flags are updated
Instructions with S=1:
- ADDS
- SUBS
- ASRS,LSLS,LSRS,RORS
- ANDS,ORRS,EORS,BICS
- MOVS,MVNS
- MULS, SMULLS, UMULLS
- CMP,CMN
- TEQ,TST
Contents of Src2
This is broadly divided into data processing instructions such as ADD and SUB, and shift instructions.
For data processing instructions
There are two patterns.
I=1: When handling immediate values
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:8 | 7:0 |
|---|---|
| rot | imm8 |
- rot: Number of rotations
- imm8: 8-bit value
When handling immediate values, you can basically only encode 8-bit values directly. However, by using the barrel shifter, you can represent values up to 32 bits with some restrictions.
- Calculation method
Rotate the
imm8value right byrot x 2. Example: imm8=1111 1111 rot=1110 rot=1110 is 14 in decimal. Therefore, rotate right by 14 x 2 = 28 bits. Before 32-bit rotation 0000 0000 0000 0000 0000 0000 1111 1111 After 32-bit rotation 0000 0000 0000 0000 0000 1111 1111 0000
The value after rotation is 4080 in decimal. This value cannot be represented as a plain 8-bit value, but it can be encoded by using the barrel shifter. If the value can be expressed within 8 bits, specify rot=0000.
Example: ADD R0,R1,#42
| cond | op | I | cmd | S | Rn | Rd | rot | imm8 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 0100 | 0 | 0001 | 0000 | 0000 | 0010 1010 |
cmd=ADD, Rd=R0, Rn=R1, rot/imm8=#42. Dividing this machine code into 4-bit groups gives:
1110 0010 1000 0001 0000 0000 0010 1010
Converting it to hexadecimal gives:
0xE281002A
I=0: When handling registers
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5: 5-bit shift amount *Shmat5=00000 when using data processing instructions and registers.
- sh: Shift command *When handling data processing instructions and registers, sh=00.
- 0: 0 is stored
- Rm: Register This corresponds to the third register.
Example: SUB R8,R9,R10
| cond | op | I | cmd | S | Rn | Rd | shmat5 | sh | 0 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 0010 | 0 | 0110 | 0101 | 00000 | 00 | 0 | 1010 |
cmd=SUB, Rd=R9, Rn=R8, Rm=R10. Dividing this machine code into 4-bit groups gives:
1110 0000 0100 0110 0101 0000 0000 1010
Converting it to hexadecimal gives:
0xE049800A
For shift commands
There are three patterns.
I=1: For move instructions
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:8 | 7:0 |
|---|---|
| rot | imm8 |
- rot: Number of rotations
- imm8: 8-bit value
As mentioned above, if I=1 in a shift command, it becomes a move instruction (MOV). Example: MOV R0,#7
| cond | op | I | cmd | S | Rn | Rd | rot | imm8 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 1101 | 0 | 0000 | 0000 | 0000 | 0000 0111 |
cmd=shift command, Rd=R0, rot/imm8=#7. Dividing this machine code into 4-bit groups gives:
1110 0011 1010 0000 0000 0000 0000 0111
Converting it to hexadecimal gives:
0xE3A00007
I=0: When the shift amount is an immediate value
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5: 5-bit shift amount *The immediate value is included here.
- sh: Shift command
- 0: 0 is stored
- Rm: Register *For shift instructions, Rn is not used and the second register is Rm.
Example: LSL R0,R9,#7
| cond | op | I | cmd | S | Rn | Rd | shmat5 | sh | 0 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0000 | 00111 | 00 | 0 | 1001 |
cmd=shift command, Rd=R0, Rm=R9, shmat5=#7, sh=LSL. Dividing this machine code into 4-bit groups gives:
1110 0001 1010 0000 0000 0011 1000 1001
Converting it to hexadecimal gives:
0xE1A00309
I=0: When the shift amount is a register
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:8 | 7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|
| Rs | 0 | sh | 1 | Rm |
- Rs: Register This corresponds to the third register.
- 0: 0 is stored
- sh: Shift instruction
- 1: 1 is stored
- Rm: Register This corresponds to the second register.
Example: ASR R5,R1,R12
| cond | op | I | cmd | S | Rn | Rd | Rs | 0 | sh | 1 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0101 | 1100 | 0 | 10 | 1 | 0001 |
cmd=shift command, Rd=R5, Rm=R1, Rs=R12, sh=ASR. Dividing this machine code into 4-bit groups gives:
1110 0001 1010 0000 0101 1100 0101 0001
Converting it to hexadecimal gives:
0xE1A05C51
Memory Instructions
Instructions executed when op=01
Basic form
*Top: bit positions. Bottom row: contents.
| 31:28 | 27:26 | 25 | 24 | 23 | 22 | 21 | 20 | 19:16 | 15:12 | 11:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| cond | op | I | P | U | B | W | L | Rn | Rd | Src2 |
Field descriptions
- I: Selects an immediate value or a register. This changes the format of Src2.
- I=0:Immediate offset
- I=1: Register offset
- U: Addition or subtraction
- U=1: Add offset
- U=0: Subtract offset
- P W: Index mode Determine using the P and W values.
- L B: Memory instruction Determine using the L and B values.
- Rd: Register 1
- Rn: Register 2
- Src2: Source 2
P W: Index mode values
| P W | Index mode | Example | How to tell |
|---|---|---|---|
| 0 0 | Post-index | LDR R0,[R1],R2 | The parentheses are in the middle. |
| 0 1 | Not supported | - | |
| 1 0 | Offset | LDR R0,[R1,R2] | The two closing brackets are at the end. |
| 1 1 | Pre-index | LDR R0,[R1,R2]! | Exclamation mark |
L B: Memory instruction values
| L B | Command |
|---|---|
| 0 0 | STR |
| 0 1 | STRB |
| 1 0 | LDR |
| 1 1 | LDRB |
Contents of Src2
I=0: When handling immediate values
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:0 |
|---|
| imm12 |
- imm12: Stores a 12-bit value This handles immediate values.
Example: STR R11,[R5],#-26
| cond | op | I | P | U | B | W | L | Rn | Rd | imm12 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 01 | 0 | 0 | 0 | 0 | 0 | 0 | 0101 | 1011 | 0000 0001 1010 |
U=subtraction, P W=post index, L B=STR, imm12=#26 Dividing this machine code into 4-bit groups gives:
1110 0100 0000 0101 1011 0000 0001 1010
Converting it to hexadecimal gives:
0xE405B01A
I=1: When handling registers
Src2 is encoded as follows.
*Top: bit positions. Bottom row: contents.
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5: 5-bit shift amount
- sh: Shift instruction
- 0: 0 is stored
- Rm: Register
Example: omitted
Branch Instructions
Instructions executed when op=10
Basic form
*Top: bit positions. Bottom row: contents.
| 31:28 | 27:26 | 25 | 24 | 23:0 |
|---|---|---|---|---|
| cond | op | 1 | L | imm24 |
- 1: 1 is stored
- L: Branch instruction
- imm24: Stores a 24-bit value This stores the branch destination address.
L: Branch instruction values
| L | Command |
|---|---|
| 0 | B |
| 1 | BL |
Branch destination address calculation
- Find the branch instruction.
- Use the instruction two positions after the branch instruction as the reference.
- Calculate how far the branch destination address is from the reference.
- Store that address value in imm24. If the value is negative, express it using two’s complement.
Example:
1 TEST LDRB R5,[R0,R3] ← Branch destination address
2 STRB R5,[R1,R3]
3 ADD R3,R3,#1
4 MOV PC,LR
5 BL TEST ← Branch instruction
6 LDR R3,[R1],#4
7 SUB R4,R3,#9 ← Reference
In this case, the branch destination address is “-6” from the reference. In other words, it is expressed in machine code as follows:
| cond | op | 1 | L | imm24 |
|---|---|---|---|---|
| 1110 | 10 | 1 | 1 | 1111 1111 1111 1111 1111 1010 |
Dividing this machine code into 4-bit groups gives:
1110 1011 1111 1111 1111 1111 1111 1010
Converting it to hexadecimal gives:
0xEBFFFFFA