mcpField
A
assembly-arm

assembly-arm

github.com/mohitmishra786开发269667 次安装18 周前更新
代码仓库

关于 assembly-arm

面向 Agent 的 ARM 与 AArch64 汇编参考技能,涵盖寄存器、调用约定、内联汇编和 SIMD 用法。也介绍 Apple Silicon 上的相关注意事项及 NEON 到 SVE2 的迁移。

主要功能

  1. 01AArch64 与 ARM Thumb 汇编基础
  2. 02寄存器和调用约定参考
  3. 03GCC/Clang 内联汇编指导
  4. 04NEON SIMD 内建函数示例
  5. 05Apple Silicon 与 ABI 注意事项
  6. 06NEON 到 SVE2 迁移提示

适用场景

  1. 01阅读 ARM64 汇编输出
  2. 02编写 ARM 内联汇编
  3. 03为 NEON 代码规划 SVE2 迁移

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill assembly-arm

安装后在 Claude Code 中输入/assembly-arm确认已加载。

附带文件references/reference.md

详细介绍

ARM / AArch64 汇编

用途

指导 Agent 学习 AArch64(64 位)和 ARM(32 位 Thumb)汇编:寄存器、调用约定、内联汇编,以及 NEON/SVE SIMD 模式。

触发场景

  • “如何阅读 ARM64 汇编输出?”
  • “AArch64 有哪些寄存器?调用约定是什么?”
  • “如何为 ARM 编写内联汇编?”
  • “AArch64 和 ARM Thumb 有什么区别?”
  • “如何使用 NEON 内建函数?”

工作流

1. 生成 ARM 汇编
# 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 寄存器(AAPCS64)
寄存器别名用途
x0–x7—参数 1–8 和返回值
x8xr间接结果位置(结构体返回值)
x9–x15—调用者保存的临时寄存器
x16–x17ip0、ip1过程调用内部临时寄存器(由链接器使用)
x18pr平台寄存器(某些 OS 上保留)
x19–x28—被调用者保存
x29fp帧指针(被调用者保存)
x30lr链接寄存器(返回地址)
sp—栈指针(调用时必须按 16 字节对齐)
pc—程序计数器(不可直接访问)
xzrwzr零寄存器(读取为 0,写入会被丢弃)
v0–v7q0–q7浮点/SIMD 参数和返回值
v8–v15—被调用者保存的 SIMD 寄存器(仅低 64 位)
v16–v31—调用者保存的临时寄存器

宽度变体:x0(64 位)、w0(32 位,零扩展至 64 位)、h0(16 位)、b0(8 位)。

3. AAPCS64 调用约定

整数/指针参数: x0–x7 浮点/SIMD 参数: v0–v7 返回值: x0(整数)、x0+x1(128 位)、v0(浮点/SIMD) 被调用者保存: x19–x28、x29(fp)、x30(lr)、v8–v15(低 64 位) 调用者保存: 其他所有寄存器

执行任何 bl 或 blr 指令时,栈都必须按 16 字节对齐。

4. 常见 AArch64 指令
指令效果
mov x0, x1复制寄存器
mov x0, #42加载立即数
movz x0, #0x1234, lsl #16移动并进行零扩展及移位
movk x0, #0xabcd移动并保留其他位(部分更新)
ldr x0, [x1]从 x1 中的地址加载 64 位数据
ldr x0, [x1, #8]从 x1+8 加载数据
str x0, [x1, #8]将 x0 存储到 x1+8
ldp x0, x1, [sp, #16]加载一对寄存器(一次加载两个寄存器)
stp x29, x30, [sp, #-16]!存储一对寄存器,并预先递减 sp
add x0, x1, x2x0 = x1 + x2
add x0, x1, #8x0 = x1 + 8
sub x0, x1, x2x0 = x1 - x2
mul x0, x1, x2x0 = x1 * x2
sdiv x0, x1, x2有符号除法
udiv x0, x1, x2无符号除法
cmp x0, x1为 x0 - x1 设置标志位
cbz x0, label如果 x0 == 0,则分支
cbnz x0, label如果 x0 != 0,则分支
bl func带链接的分支(调用)
blr x0带链接地跳转到 x0 中的地址
ret返回(跳转到 x30)
ret x0返回到 x0 中的地址
adrp x0, symbolPC 相对页地址
add x0, x0, :lo12:symbol获取 symbol 偏移的低 12 位
5. 典型函数序言/尾声
// 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. 内联汇编(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 专用约束:

  • "Q" — 适用于独占/获取/释放指令的内存操作数
  • "r" — 任意通用寄存器
  • "w" — 任意浮点/SIMD 寄存器
7. NEON SIMD 内建函数
#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);

命名约定:v<op><q>_<type>

  • q 后缀:128 位(四元)向量
  • _f32:float32,_s32:int32,_u8:uint8 等
8. Darwin 与 Linux AArch64 ABI 的差异
方面Linux(AAPCS64)Apple Darwin(arm64)
栈对齐公共接口处为 16 字节16 字节
红区SP 下方 128 字节无红区
x18 寄存器平台保留(TLS)平台寄存器(请勿使用)
可变参数x0–x7,然后是栈相同,但 objc_msgSend 约定不同
名称修饰Itanium C++ ABI相同 + Apple blocks

在 macOS/iOS 上,避免使用 x18;平台类型请使用 _DARWIN_C_LEVEL 头文件。

9. AMX 入门(Apple Silicon)

Apple 矩阵协处理器(AMX)无法通过公开的内建函数访问。访问方式:

// 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

在 Apple Silicon 上处理矩阵工作负载时,优先使用 Metal Performance Shaders 或 Accelerate(skills/platform/apple-silicon)。

10. Apple M 系列上的 16KB 页面大小

Apple Silicon 上的 macOS 使用 16KB 页面(而非 4KB):

#include <unistd.h>
long page = sysconf(_SC_PAGESIZE);  // 16384 on macOS arm64
// Align mmap and posix_memalign to page size

假设 PAGE_SIZE == 4096 的代码可能会导致缓冲区未对齐,或在 macOS 上调用 mmap 失败。

11. NEON → SVE2 迁移提示
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+

有关 SVE 内建函数和自动向量化标志,请参阅 skills/platform/arm-sve。

有关寄存器参考,请参阅 references/reference.md。

相关技能

  • 使用 skills/low-level-programming/assembly-x86 处理 x86-64 汇编
  • 使用 skills/compilers/cross-gcc 使用交叉编译工具链
  • 使用 skills/debuggers/gdb 通过 gdbserver 调试 ARM 代码
  • 使用 skills/platform/arm-sve 使用 SVE/SVE2 可伸缩向量
  • 使用 skills/platform/apple-silicon 了解 M 系列统一内存和 AMX

评论

支持 Markdown