How to Convert ARM Assembly and Machine Code

16 min read

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:2827:2625:2019:0
condopfunct-

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:2827:262524:212019:1615:1211:0
condopIcmdSRnRdSrc2

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

cmdformatdescriptionbehavior
0000AND Rd,Rn,Src2Bitwise ANDRd ← Rn & Src2
0001EOR Rd,Rn,Src2Bitwise XORRd ← Rn ^ Src2
0010SUB Rd,Rn,Src2SubtractionRd ← Rn - Src2
0011RSB Rd,Rn,Src2Reverse subtractionRd ← Src2 - Rn
0100ADD Rd,Rn,Src2AdditionRd ← Rn + Src2
0101ADC Rd,Rn,Src2Carry additionRd ← Rn + Src2 + C
0110SBC Rd,Rn,Src2Subtraction with carryRd ← Rn - Src2 - C
0111RSC Rd,Rn,Src2Reverse subtraction with carryRd ← Src2 - Rn - C
1000TST Rn,Src2TestSet flag based on Rn & Src2
1001TEQ Rn,Src2Test for equalitySet flag based on Rn^Src2
1010CMP Rn,Src2CompareSet flag based on Rn -Src2
1011CMN Rn,Src2Negative comparisonSet flag based on Rn + Src2
1100ORR Rd,Rn,Src2Bitwise ORRd ← Rn | Src2
1101ShiftSee table below
1110BIC Rd,Rn,Src2Clear each bitRd ← Rn & ~Src2
1111MVN Rd,Src2Bitwise negationRd ← ~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

FormatDescriptionBehavior
MOV Rd,Src2MoveRd ← Src2

Shift details when I=0

shFormatDescriptionBehavior
00LSL Rd,Rm,Rs/shmat5Logical left shiftRd ← Rm << Src2
01LSR Rd,Rm,Rs/shmat5Logical right shiftRd ← Rm >> Src2
10ASR Rd,Rm,Rs/shmat5Arithmetic right shiftRd ← Rm >> Src2
11ROR Rd,Rm,Rs/shmat5Right rotationRd ← 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:87:0
rotimm8
  • 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 imm8 value right by rot 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

condopIcmdSRnRdrotimm8
1110001010000001000000000010 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:76:543:0
shmat5sh0Rm
  • 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

condopIcmdSRnRdshmat5sh0Rm
11100000010001100101000000001010

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:87:0
rotimm8
  • 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

condopIcmdSRnRdrotimm8
1110001110100000000000000000 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:76:543:0
shmat5sh0Rm
  • 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

condopIcmdSRnRdshmat5sh0Rm
11100001101000000000001110001001

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:876:543:0
Rs0sh1Rm
  • 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

condopIcmdSRnRdRs0sh1Rm
11100001101000000101110001010001

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:2827:2625242322212019:1615:1211:0
condopIPUBWLRnRdSrc2

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 WIndex modeExampleHow to tell
0 0Post-indexLDR R0,[R1],R2The parentheses are in the middle.
0 1Not supported-
1 0OffsetLDR R0,[R1,R2]The two closing brackets are at the end.
1 1Pre-indexLDR R0,[R1,R2]!Exclamation mark

L B: Memory instruction values

L BCommand
0 0STR
0 1STRB
1 0LDR
1 1LDRB

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

condopIPUBWLRnRdimm12
111001000000010110110000 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:76:543:0
shmat5sh0Rm
  • 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:2827:26252423:0
condop1Limm24
  • 1: 1 is stored
  • L: Branch instruction
  • imm24: Stores a 24-bit value This stores the branch destination address.

L: Branch instruction values

LCommand
0B
1BL

Branch destination address calculation

  1. Find the branch instruction.
  2. Use the instruction two positions after the branch instruction as the reference.
  3. Calculate how far the branch destination address is from the reference.
  4. 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:

condop1Limm24
111010111111 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

References