
Assembly Arm
- 384 installs
- 155 repo stars
- Updated June 27, 2026
- mohitmishra786/low-level-dev-skills
assembly-arm is a Claude Code agent skill that teaches AArch64 and ARM Thumb assembly reading, writing, and debugging with AAPCS64 calling conventions for developers working on embedded, mobile, or Rust/C inline asm.
About
assembly-arm is a low-level-dev-skills agent skill for AArch64 and ARM Thumb assembly from the mohitmishra786 toolchain suite. The skill documents AAPCS64 register roles across x0–x7 argument slots, v0–v7 SIMD args, callee-saved x19–x28, and 16-byte stack alignment rules. Developers reach for assembly-arm when reading GCC or Clang -S output, writing inline asm in C/C++/Rust, debugging register and stack state on ARM hardware or QEMU, or applying NEON and SVE SIMD patterns in performance-critical paths.
- AArch32/AArch64 ABI rules
- Register and stack conventions
- Inline asm patterns
- Debugging disassembly
- FFI boundary safety
Assembly Arm by the numbers
- 384 all-time installs (skills.sh)
- +25 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #31 of 121 Rust skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill assembly-armAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 384 |
|---|---|
| repo stars | ★ 155 |
| Last updated | June 27, 2026 |
| Repository | mohitmishra786/low-level-dev-skills ↗ |
How do you read AArch64 assembly calling conventions?
Write and debug ARM assembly for embedded, mobile, or performance-critical paths needing register-level control, ABI compliance, and inline asm in Rust/C projects.
Who is it for?
Systems and embedded developers debugging ARM64 firmware, mobile native code, or Rust/C inline assembly on AArch64 targets.
Skip if: Web frontend developers or teams building standard REST APIs without register-level ARM assembly or cross-compilation needs.
When should I use this skill?
A user asks about AArch64 registers, AAPCS64 calling convention, ARM Thumb inline asm, or reading ARM disassembly from GCC or GDB.
What you get
Correct AArch64 or ARM Thumb assembly with AAPCS64-compliant register usage, inline asm blocks, and GDB/objdump disassembly traces.
- AAPCS64-compliant inline asm blocks
- Annotated disassembly with register role mapping
By the numbers
- Documents 8 integer argument registers (x0–x7) and 8 SIMD argument registers (v0–v7)
- Requires 16-byte stack alignment at every bl or blr instruction
Files
ARM / AArch64 Assembly
Purpose
Guide agents through AArch64 (64-bit) and ARM (32-bit Thumb) assembly: registers, calling conventions, inline asm, and NEON/SVE SIMD patterns.
Triggers
- "How do I read ARM64 assembly output?"
- "What are the AArch64 registers and calling convention?"
- "How do I write inline asm for ARM?"
- "What is the difference between AArch64 and ARM Thumb?"
- "How do I use NEON intrinsics?"
Workflow
1. Generate ARM assembly
# AArch64 (native or cross-compile)
aarch64-linux-gnu-gcc -S -O2 foo.c -o foo.s
# 32-bit ARM Thumb
arm-linux-gnueabihf-gcc -S -O2 -mthumb foo.c -o foo.s
# From objdump
aarch64-linux-gnu-objdump -d -S prog
# From GDB on target
(gdb) disassemble /s main2. AArch64 registers (AAPCS64)
| Register | Alias | Role |
|---|---|---|
x0–x7 | — | Arguments 1–8 and return values |
x8 | xr | Indirect result location (struct return) |
x9–x15 | — | Caller-saved temporaries |
x16–x17 | ip0, ip1 | Intra-procedure-call temporaries (used by linker) |
x18 | pr | Platform register (reserved on some OS) |
x19–x28 | — | Callee-saved |
x29 | fp | Frame pointer (callee-saved) |
x30 | lr | Link register (return address) |
sp | — | Stack pointer (must be 16-byte aligned at call) |
pc | — | Program counter (not directly accessible) |
xzr | wzr | Zero register (reads as 0, writes discarded) |
v0–v7 | q0–q7 | FP/SIMD args and return |
v8–v15 | — | Callee-saved SIMD (lower 64 bits only) |
v16–v31 | — | Caller-saved temporaries |
Width variants: x0 (64-bit), w0 (32-bit, zero-extends to 64), h0 (16), b0 (8).
3. AAPCS64 calling convention
Integer/pointer args: x0–x7 Float/SIMD args: v0–v7 Return: x0 (int), x0+x1 (128-bit), v0 (float/SIMD) Callee-saved: x19–x28, x29 (fp), x30 (lr), v8–v15 (lower 64 bits) Caller-saved: everything else
Stack must be 16-byte aligned at any bl or blr instruction.
4. Common AArch64 instructions
| Instruction | Effect |
|---|---|
mov x0, x1 | Copy register |
mov x0, #42 | Load immediate |
movz x0, #0x1234, lsl #16 | Move zero-extended with shift |
movk x0, #0xabcd | Move with keep (partial update) |
ldr x0, [x1] | Load 64-bit from address in x1 |
ldr x0, [x1, #8] | Load from x1+8 |
str x0, [x1, #8] | Store x0 to x1+8 |
ldp x0, x1, [sp, #16] | Load pair (two regs at once) |
stp x29, x30, [sp, #-16]! | Store pair, pre-decrement sp |
add x0, x1, x2 | x0 = x1 + x2 |
add x0, x1, #8 | x0 = x1 + 8 |
sub x0, x1, x2 | x0 = x1 - x2 |
mul x0, x1, x2 | x0 = x1 * x2 |
sdiv x0, x1, x2 | Signed divide |
udiv x0, x1, x2 | Unsigned divide |
cmp x0, x1 | Set flags for x0 - x1 |
cbz x0, label | Branch if x0 == 0 |
cbnz x0, label | Branch if x0 != 0 |
bl func | Branch with link (call) |
blr x0 | Branch with link to address in x0 |
ret | Return (branch to x30) |
ret x0 | Return to address in x0 |
adrp x0, symbol | PC-relative page address |
add x0, x0, :lo12:symbol | Low 12 bits of symbol offset |
5. Typical function prologue/epilogue
// Non-leaf function
stp x29, x30, [sp, #-32]! // save fp, lr; allocate 32 bytes
mov x29, sp // set frame pointer
stp x19, x20, [sp, #16] // save callee-saved registers
// ... body ...
ldp x19, x20, [sp, #16] // restore
ldp x29, x30, [sp], #32 // restore fp, lr; deallocate
ret
// Leaf function (no calls, no callee-saved regs needed)
// Can use red zone (no rsp adjustment) — but AArch64 has no red zone
sub sp, sp, #16 // allocate locals
// ... body ...
add sp, sp, #16
ret6. Inline assembly (GCC/Clang)
// Barrier
__asm__ volatile ("dmb ish" ::: "memory");
// Load acquire
static inline int load_acquire(volatile int *p) {
int val;
__asm__ volatile ("ldar %w0, %1" : "=r"(val) : "Q"(*p));
return val;
}
// Store release
static inline void store_release(volatile int *p, int val) {
__asm__ volatile ("stlr %w1, %0" : "=Q"(*p) : "r"(val));
}
// Read system counter
static inline uint64_t read_cntvct(void) {
uint64_t val;
__asm__ volatile ("mrs %0, cntvct_el0" : "=r"(val));
return val;
}AArch64-specific constraints:
"Q"— memory operand suitable for exclusive/acquire/release instructions"r"— any general-purpose register"w"— any FP/SIMD register
7. NEON SIMD intrinsics
#include <arm_neon.h>
// Add 4 floats at once
float32x4_t a = vld1q_f32(arr_a); // load 4 floats
float32x4_t b = vld1q_f32(arr_b);
float32x4_t c = vaddq_f32(a, b);
vst1q_f32(result, c);
// Horizontal sum
float32x4_t sum = vpaddq_f32(c, c);
sum = vpaddq_f32(sum, sum);
float total = vgetq_lane_f32(sum, 0);Naming convention: v<op><q>_<type>
qsuffix: 128-bit (quad) vector_f32: float32,_s32: int32,_u8: uint8, etc.
For a register reference, see references/reference.md.
Related skills
- Use
skills/low-level-programming/assembly-x86for x86-64 assembly - Use
skills/compilers/cross-gccfor cross-compilation toolchain - Use
skills/debuggers/gdbfor debugging ARM code with gdbserver
AArch64 / ARM Assembly Reference
Source: <https://developer.arm.com/documentation/ddi0487/latest> (ARM Architecture Reference Manual) Source: <https://developer.arm.com/documentation/ihi0055/latest> (AAPCS64)
Table of Contents
1. Condition codes 2. Key instructions by category 3. Memory ordering 4. NEON data types 5. Thumb-2 notes
---
Condition codes
| Code | Meaning | Flags |
|---|---|---|
EQ | Equal | Z=1 |
NE | Not equal | Z=0 |
CS/HS | Carry set / Unsigned ≥ | C=1 |
CC/LO | Carry clear / Unsigned < | C=0 |
MI | Minus (negative) | N=1 |
PL | Plus (non-negative) | N=0 |
VS | Overflow | V=1 |
VC | No overflow | V=0 |
HI | Unsigned > | C=1, Z=0 |
LS | Unsigned ≤ | C=0 or Z=1 |
GE | Signed ≥ | N=V |
LT | Signed < | N≠V |
GT | Signed > | Z=0, N=V |
LE | Signed ≤ | Z=1 or N≠V |
AL | Always (default) | — |
Conditional branches: b.eq, b.ne, b.lt, b.ge, b.hi, b.ls, etc.
---
Key instructions by category
Loads and stores
ldr x0, [x1] ; load 64-bit
ldr w0, [x1] ; load 32-bit, zero-extend
ldrb w0, [x1] ; load 8-bit, zero-extend
ldrsb w0, [x1] ; load 8-bit, sign-extend
ldrh w0, [x1] ; load 16-bit, zero-extend
str x0, [x1] ; store 64-bit
strb w0, [x1] ; store byte
; Pre-index: update base before access
ldr x0, [x1, #8]! ; x0 = [x1+8]; x1 += 8
; Post-index: update base after access
ldr x0, [x1], #8 ; x0 = [x1]; x1 += 8
; Pair operations
ldp x0, x1, [x2] ; load pair
stp x0, x1, [x2, #-16]! ; store pair, pre-decrement
; Exclusive access (for atomics)
ldxr x0, [x1] ; load exclusive
stxr w2, x0, [x1] ; store exclusive; w2=0 on success
; Acquire/release (for lock-free)
ldar x0, [x1] ; load-acquire
stlr x0, [x1] ; store-releaseArithmetic and logic
add x0, x1, x2 ; x0 = x1 + x2
add x0, x1, x2, lsl #2 ; x0 = x1 + (x2 << 2)
adds x0, x1, x2 ; add, set flags
adc x0, x1, x2 ; add with carry
sub x0, x1, x2
subs x0, x1, x2 ; sub, set flags
sbc x0, x1, x2 ; sub with carry
mul x0, x1, x2
madd x0, x1, x2, x3 ; x0 = x1*x2 + x3
msub x0, x1, x2, x3 ; x0 = x3 - x1*x2
and x0, x1, x2
orr x0, x1, x2
eor x0, x1, x2 ; XOR
bic x0, x1, x2 ; x0 = x1 & ~x2
lsl x0, x1, #3 ; logical shift left 3
lsr x0, x1, #3 ; logical shift right 3
asr x0, x1, #3 ; arithmetic shift right 3
ror x0, x1, #3 ; rotate right
clz x0, x1 ; count leading zeros
rbit x0, x1 ; reverse bits
rev x0, x1 ; reverse bytes (endian swap 64-bit)Branches and system
b label ; unconditional branch
bl label ; branch and link (call)
blr x0 ; branch and link to register (indirect call)
br x0 ; branch to register (indirect jump)
ret ; return (branch to x30)
cbz x0, label ; branch if x0 == 0
cbnz x0, label ; branch if x0 != 0
tbz x0, #3, label ; branch if bit 3 of x0 == 0
tbnz x0, #3, label ; branch if bit 3 != 0
nop ; no operation
wfe ; wait for event
wfi ; wait for interrupt
isb ; instruction sync barrier
dsb sy ; data sync barrier
dmb ish ; data memory barrier (inner shareable)
mrs x0, cntvct_el0 ; read virtual timer count
mrs x0, nzcv ; read flags register
msr nzcv, x0 ; write flags register---
Memory ordering
| Instruction | Ordering |
|---|---|
ldar | Load-Acquire (reads after this are ordered after) |
stlr | Store-Release (writes before this are ordered before) |
ldaxr | Load-Acquire Exclusive |
stlxr | Store-Release Exclusive |
dmb ish | Data Memory Barrier (inner shareable domain) |
dmb ishld | DMB for loads only |
dmb ishst | DMB for stores only |
dsb ish | Data Synchronization Barrier |
isb | Instruction Synchronization Barrier |
---
NEON data types
| C type | Lanes | Element |
|---|---|---|
uint8x8_t | 8 | uint8 |
uint8x16_t | 16 | uint8 |
int16x4_t | 4 | int16 |
int16x8_t | 8 | int16 |
int32x2_t | 2 | int32 |
int32x4_t | 4 | int32 |
int64x1_t | 1 | int64 |
int64x2_t | 2 | int64 |
float32x2_t | 2 | float |
float32x4_t | 4 | float |
float64x2_t | 2 | double |
Common intrinsic categories (prefix v):
- Load:
vld1q_f32,vld2q_u8(interleaved) - Store:
vst1q_f32 - Arithmetic:
vaddq_f32,vsubq_s32,vmulq_f32 - Comparison:
vcgeq_f32,vceqq_u8 - Shift:
vshlq_n_u32,vshrq_n_s16 - Reorder:
vuzpq_u8,vzipq_u8,vtrn1q_u32 - Horizontal:
vpaddq_s32,vaddvq_f32
---
Thumb-2 notes
32-bit ARM with Thumb-2 ISA (Cortex-M, Cortex-A in Thumb state):
- Most 32-bit ARM instructions available as Thumb-2 (32-bit encoding)
- Compact 16-bit encodings for common ops
it(If-Then) block for conditional execution without branches- No condition codes on most instructions by default; use
ssuffix to update flags blrange: ±16 MB; useblxfor ARM↔Thumb interworking
Related skills
How it compares
Pick assembly-arm over assembly-x86 when targeting AArch64 embedded firmware, iOS/Android native code, or ARM cross-compilation toolchains.
FAQ
What ARM architectures does assembly-arm cover?
assembly-arm covers AArch64 (64-bit) and ARM Thumb (32-bit) assembly. The skill documents AAPCS64 for AArch64 and AAPCS for 32-bit ARM, including register width variants x0, w0, h0, and b0.
How does assembly-arm generate ARM assembly output?
assembly-arm guides agents to run aarch64-linux-gnu-gcc -S -O2 for AArch64 or arm-linux-gnueabihf-gcc -S -mthumb for 32-bit targets. Disassembly uses aarch64-linux-gnu-objdump -d -S or GDB disassemble /s main.