assembly-arm — скилл для Claude Code: сборка под ARM и AArch64
Скилл, который помогает агенту читать и писать ассемблер AArch64 и ARM Thumb: регистры, соглашения вызова, инлайн-asm и NEON.
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a claude-codeЧто делает assembly-arm
Скилл разбирает вывод GCC и Clang под AArch64 и 32-битный ARM Thumb, объясняет регистры AAPCS64 и соглашение о вызовах, помогает писать инлайн-asm в C и C++ и отлаживать состояние регистров и стека на железе или в QEMU. Внутри — таблицы регистров, частых инструкций, типовой пролог и эпилог функции, примеры инлайн-asm с ограничениями "Q", "r" и "w", а также заготовки под NEON-интринсики.
Есть отдельные разделы про различия ABI Linux и Apple Darwin: где зарезервирован x18, как обстоят дела с red zone, почему на macOS arm64 страница 16 КБ, а не 4 КБ. Код, который рассчитывает на PAGE_SIZE == 4096, на Apple Silicon может промахнуться с выравниванием буферов или упасть на mmap — это повод проверить свои аллокации, если вы собираете под M-серию.
Для генерации листинга скилл предлагает кросс-компиляторы aarch64-linux-gnu-gcc -S и arm-linux-gnueabihf-gcc -S -mthumb, а также objdump -d -S и disassemble /s в GDB. Раздел про миграцию NEON на SVE2 в тексте обрывается, так что полного чек-листа по переносу там нет.
Какие задачи решает
- прочитать вывод
aarch64-linux-gnu-gcc -Sи понять, что делает компилятор - написать инлайн-asm для ARM с правильными ограничениями
- разобраться, какие регистры callee-saved в AAPCS64
- отладить состояние стека и регистров в QEMU
- перевести цикл на NEON-интринсики
Примеры запросов агенту
- объясни этот листинг AArch64, что тут происходит с x0–x7
- напиши инлайн-asm для load acquire на ARM
- почему на macOS arm64 mmap падает при выравнивании на 4096
Как установить assembly-arm
1Через Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a claude-code2Вручную: положить файлы
~/.claude/skills/assembly-arm/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/assembly-arm/
1Через Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a codex2Вручную: положить файлы
.agents/skills/assembly-arm/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a cursor2Вручную: положить файлы
.cursor/skills/assembly-arm/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install mohitmishra786/low-level-dev-skills assembly-arm2Вручную: положить файлы
.github/skills/assembly-arm/SKILL.md1Через Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a gemini-cli2Командой платформы
gemini skills install https://github.com/mohitmishra786/low-level-dev-skills --path skills/low-level-programming/assembly-armВручную: положить файлы
.devin/skills/assembly-arm/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о assembly-arm
Как установить assembly-arm в Claude?
Выполните npx skills add mohitmishra786/low-level-dev-skills --skill assembly-arm -a claude-code. Скилл окажется в ~/.claude/skills/assembly-arm/SKILL.md.
Что делает assembly-arm?
Помогает агенту читать и писать ассемблер AArch64 и ARM Thumb: регистры, соглашения вызова, инлайн-asm, NEON/SVE SIMD и отладка состояния регистров.
Чем ABI Linux и Apple Darwin отличаются?
На Linux есть red zone 128 байт ниже SP, на Darwin её нет. Регистр x18 зарезервирован на обеих платформах, а на Apple Silicon страница памяти 16 КБ вместо 4 КБ.
Исходный текст
SKILL.md · MIT
---
name: assembly-arm
description: AArch64 and ARM assembly skill for reading and writing ARM assembly code. Use when reading GCC/Clang output for AArch64 or ARM Thumb targets, writing inline asm in C/C++, understanding the ARM ABI (AAPCS64/AAPCS), or debugging register and stack state on ARM hardware or QEMU. Activates on queries about AArch64 assembly, ARM Thumb, NEON/SVE SIMD, ARM calling convention, inline asm for ARM, or reading ARM disassembly.
---
# 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
```bash
# 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 main
```
### 2. 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
```asm
// 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
ret
```
### 6. Inline assembly (GCC/Clang)
```c
// 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
```c
#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>`
- `q` suffix: 128-bit (quad) vector
- `_f32`: float32, `_s32`: int32, `_u8`: uint8, etc.
### 8. Darwin vs Linux AArch64 ABI differences
| Aspect | Linux (AAPCS64) | Apple Darwin (arm64) |
|--------|-----------------|----------------------|
| Stack alignment | 16 bytes at public interfaces | 16 bytes |
| Red zone | 128 bytes below SP | No red zone |
| `x18` register | Platform reserved (TLS) | Platform register (do not use) |
| Varargs | `x0–x7`, then stack | Same, but different objc_msgSend conventions |
| Name mangling | Itanium C++ ABI | Same + Apple blocks |
On macOS/iOS, avoid using `x18`; use `_DARWIN_C_LEVEL` headers for platform types.
### 9. AMX primer (Apple Silicon)
Apple Matrix coprocessor (AMX) is not exposed via public intrinsics. Access paths:
```c
// Practical: Accelerate/vecLib uses AMX internally
#include <Accelerate/Accelerate.h>
// cblas_sgemm, vDSP_* dispatch to AMX on M-series
// Low-level: community-documented opcodes — not portable, avoid in production
```
Prefer Metal Performance Shaders or Accelerate for matrix workloads on Apple Silicon (`skills/platform/apple-silicon`).
### 10. 16KB page size on Apple M-series
macOS on Apple Silicon uses 16KB pages (not 4KB):
```c
#include <unistd.h>
long page = sysconf(_SC_PAGESIZE); // 16384 on macOS arm64
// Align mmap and posix_memalign to page size
```
Code assuming `PAGE_SIZE == 4096` may misalign buffers or fail `mmap` on macOS.
### 11. NEON → SVE2 migration hints
```
Porting checklist
├── Replace 128-bit fixed loops with svcnt*() strides on SVE hardware
├── Use predicates (svwhilelt) for tails instead of scalar epilogues
├── Guard SVE code with #ifdef __ARM_FEATURE_SVE
└── Keep NEON path for Apple M1–M3 (no SVE); use SVE2 on Graviton/M4+
```
See `skills/platform/arm-sve` for SVE intrinsics and auto-vectorization flags.
For a register reference, see [references/reference.md](references/reference.md).
## Related skills
- Use `skills/low-level-programming/assembly-x86` for x86-64 assembly
- Use `skills/compilers/cross-gcc` for cross-compilation toolchain
- Use `skills/debuggers/gdb` for debugging ARM code with gdbserver
- Use `skills/platform/arm-sve` for SVE/SVE2 scalable vectors
- Use `skills/platform/apple-silicon` for M-series unified memory and AMX
© mohitmishra786 · MIT · mohitmishra786/low-level-dev-skills