Example using Capstone in Python:
For production, use a library like (supports ARM, Thumb, Thumb-2, AArch64). 7. Advanced Considerations 7.1 Thumb-2 32-bit instructions Example: 0xF04F 0x4000 → MOV R0, #0 (32-bit Thumb-2 MOV). Decoding requires checking the first 16 bits: if bits 15-11 are 11101 or 11110 , it’s a 32-bit instruction. 7.2 PC-relative addressing LDR R0, [PC, #offset] → hex requires calculating the actual address from the offset. A converter may optionally resolve the target. 7.3 Endianness If hex input is from a memory dump (bytes: 00 05 A0 E3), the converter must reverse to little-endian word 0xE3A00500 ? Actually, ARM instruction words are stored little-endian: byte offset 0 = low byte of instruction. So the hex string E3 A0 00 05 in memory order becomes 0xE3A00005 as a word. 7.4 Unconditional vs conditional ARM allows conditional execution (e.g., MOVNE R0, #1 ). A full converter shows the condition suffix. 8. Tools That Implement Hex to ARM Conversion | Tool | Type | ARM support | |------|------|--------------| | Capstone | Library | ARM, Thumb, Thumb-2, AArch64 | | objdump (binutils) | CLI | arm-none-eabi-objdump -D -b binary -m arm | | Ghidra | GUI/CLI | Full ARM disassembly | | radare2 | CLI | r2 -a arm -b 32 hexdump.bin | | Online converters (e.g., armconverter.com) | Web | Basic ARM/Thumb |
A hex-to-ARM converter must first the mode. 3.1 ARM Mode (A32) Format A 32-bit ARM instruction has a general layout (varies by type): hex to arm converter
def hex_to_arm(hex_str): instr = int(hex_str, 16) cond = (instr >> 28) & 0xF if cond != 0xE: # 0xE = always return f"<conditional hex(instr)>" opcode = (instr >> 21) & 0xF rd = (instr >> 12) & 0xF rn = (instr >> 16) & 0xF
# Check if immediate (bit 25 = 1) if (instr >> 25) & 1: imm = instr & 0xFF shift = (instr >> 8) & 0xF if shift: imm = imm << (shift * 2) ops = 0: "AND", 1: "EOR", 2: "SUB", 3: "RSB", 4: "ADD", 8: "TST", 10: "CMP", 12: "ORR", 13: "MOV", 14: "BIC", 15: "MVN" return f"ops.get(opcode, '???') Rrd, #imm" else: # Register operand (simplified) rm = instr & 0xF ops = 0: "AND", 1: "EOR", 2: "SUB", 3: "RSB", 4: "ADD", 8: "TST", 10: "CMP", 12: "ORR", 13: "MOV" return f"ops.get(opcode, '???') Rrd, Rrn, Rrm" print(hex_to_arm("E3A00005")) # MOV R0, #5 Example using Capstone in Python: For production, use
instr = 0xE3A00005 cond = (instr >> 28) & 0xF opcode = (instr >> 21) & 0xF rn = (instr >> 16) & 0xF rd = (instr >> 12) & 0xF Use lookup tables or switch-case for opcode + additional bits:
Standard ARM assembly syntax (UAL - Unified Assembly Language). 5. Example Conversions ARM mode | Hex | Assembly | |------|-----------| | E1A00000 | MOV R0, R0 (NOP) | | E3A0102A | MOV R1, #42 | | E2833001 | ADD R3, R3, #1 | | E5902000 | LDR R2, [R0] | | EA000005 | B 0x20 (branch) | Thumb mode | Hex | Assembly | |------|-----------| | 2001 | MOVS R0, #1 | | 1C40 | ADDS R0, R0, #1 | | 6800 | LDR R0, [R0, #0] | 6. Building a Simple Converter (Python) Here’s a minimal ARM (A32) decoder for data processing instructions: Decoding requires checking the first 16 bits: if
if ((instr & 0xFC000000) == 0xE3A00000) // MOV immediate int rd = (instr >> 12) & 0xF; int imm = instr & 0xFF; printf("MOV R%d, #%d\n", rd, imm);
1. Introduction In the realm of low-level programming and embedded systems, the ARM architecture (Advanced RISC Machines) dominates—powering billions of devices from microcontrollers (Cortex-M) to smartphones (Cortex-A). At its core, an ARM processor executes machine code , a sequence of binary instructions. For human readability, this binary is often represented in hexadecimal (hex) .
| Set | Instruction width | Typical devices | |------|------------------|----------------| | ARM (A32) | 32-bit fixed | Classic ARM cores, Cortex-A | | Thumb (T16) | 16-bit | Cortex-M, lower memory footprint | | Thumb-2 (T32) | Mixed 16/32-bit | Modern Cortex-M3/M4/M7/M33 |