mcpField
A
assembly-x86

assembly-x86

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

关于 assembly-x86

assembly-x86 是一项引导 Agent 学习 x86-64 汇编的技能,内容从解读编译器输出延伸到 ABI、内联汇编和 SIMD intrinsic。

主要功能

  1. 01阅读编译器生成的汇编
  2. 02理解寄存器与 System V ABI
  3. 03比较 AT&T 和 Intel 语法
  4. 04编写 GCC 扩展内联汇编
  5. 05使用 SSE 和 AVX intrinsic
  6. 06识别常见指令模式

适用场景

  1. 01检查 C 程序的 GCC 输出
  2. 02理解函数参数与返回值
  3. 03在 C 中编写内联汇编
  4. 04对成批数值使用 SIMD 操作

安装

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

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

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

附带文件references/reference.md

详细介绍

x86-64 汇编

用途

指导 Agent 学习 x86-64 汇编:阅读编译器输出、理解 ABI、编写内联汇编以及掌握常见模式。

触发语句

  • “如何阅读 GCC 生成的汇编?”
  • “x86-64 有哪些寄存器?”
  • “Linux/macOS 上的调用约定是什么?”
  • “如何在 C 中编写内联汇编?”
  • “如何使用 SSE/AVX 内建函数?”
  • “这段汇编用了 %rsp / %rbp——是什么意思?”

工作流

1. 生成并阅读汇编
# AT&T syntax (GCC default)
gcc -S -O2 -fverbose-asm foo.c -o foo.s

# Intel syntax
gcc -S -masm=intel -O2 foo.c -o foo.s

# From GDB
(gdb) disassemble /s main    # with source
(gdb) x/20i $rip

# From objdump
objdump -d -M intel -S prog  # Intel + source (needs -g)
2. x86-64 寄存器
64 位32 位16 位高 8 位低 8 位用途
%rax%eax%ax%ah%al返回值 / 累加器
%rbx%ebx%bx%bh%bl被调用者保存
%rcx%ecx%cx%ch%cl第 4 个参数 / 计数
%rdx%edx%dx%dh%dl第 3 个参数 / 第 2 个返回值
%rsi%esi%si—%sil第 2 个参数
%rdi%edi%di—%dil第 1 个参数
%rbp%ebp%bp—%bpl帧指针(被调用者保存)
%rsp%esp%sp—%spl栈指针
%r8–%r11%r8d–%r11d%r8w–%r11w—%r8b–%r11b第 5–8 个参数 / 调用者保存
%r12–%r15%r12d–%r15d%r12w–%r15w—%r12b–%r15b被调用者保存
%rip指令指针
%rflags%eflags状态标志
%xmm0–%xmm7浮点/SIMD 参数和返回值
%xmm8–%xmm15调用者保存的 SIMD 寄存器
%ymm0–%ymm15AVX 256 位
%zmm0–%zmm31AVX-512 512 位
3. System V AMD64 ABI(Linux、macOS、FreeBSD)

整数/指针参数寄存器(按顺序): %rdi, %rsi, %rdx, %rcx, %r8, %r9

浮点参数寄存器: %xmm0–%xmm7

返回值:

  • 整数:%rax(低位),%rdx(若为 128 位,则存放高位)
  • 浮点数:%xmm0(低位),%xmm1(高位)

调用者保存(临时): %rax, %rcx, %rdx, %rsi, %rdi, %r8–%r11, %xmm0–%xmm15

被调用者保存(必须保留): %rbx, %rbp, %r12–%r15

栈: 调用 call 前按 16 字节对齐;call 会压入 8 字节,因此在函数序言执行后,函数入口处的栈按 16 字节对齐。

红区: 叶函数可以使用 %rsp 以下的 128 字节,而无需调整 %rsp。内核/信号处理程序中不可用。

4. 常见指令模式
模式含义
mov %rdi, %rax将 rdi 复制到 rax
mov (%rdi), %rax从 rdi 中的地址加载 8 字节
mov %rax, 8(%rdi)将 rax 存储到 rdi+8
lea 8(%rdi), %rax将有效地址 rdi+8 加载到 rax(不访问内存)
push %rbx压入 rbx;rsp -= 8
pop %rbx弹出到 rbx;rsp += 8
call foo压入返回地址;跳转到 foo
ret弹出返回地址;跳转到该地址
xor %eax, %eax将 rax 清零(编码比 mov $0, %rax 更短)
test %rax, %rax若 rax == 0,则设置 ZF(比 cmp $0, %rax 更高效)
cmp $5, %rdi根据 rdi - 5 设置标志
jl label若有符号数小于,则跳转
5. AT&T 与 Intel 语法
特征AT&TIntel
操作数顺序源,目标目标,源
寄存器前缀%raxrax
立即数前缀$4242
内存操作数8(%rdi)[rdi+8]
大小后缀movl、movq—(自动推断)

GCC 默认输出 AT&T 语法。使用 -masm=intel 可指定 Intel 语法。

6. 内联汇编(GCC 扩展 asm)
// Basic: increment a register
int x = 5;
__asm__ volatile (
    "incl %0"
    : "=r"(x)   // outputs: =r means write-only register
    : "0"(x)    // inputs: 0 means same as output 0
    : // clobbers: none
);

// CPUID example
uint32_t eax, ebx, ecx, edx;
__asm__ volatile (
    "cpuid"
    : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
    : "a"(1)    // input: leaf 1
);

// Atomic increment
static inline int atomic_inc(volatile int *p) {
    int ret;
    __asm__ volatile (
        "lock; xaddl %0, %1"
        : "=r"(ret), "+m"(*p)
        : "0"(1)
        : "memory"
    );
    return ret + 1;
}

约束代码:

  • "r" — 任意通用寄存器
  • "m" — 内存操作数
  • "i" — 整数立即数
  • "a"、"b"、"c"、"d" — 指定寄存器(%rax、%rbx、%rcx、%rdx)
  • "=" 前缀 — 输出(只写)
  • "+" 前缀 — 读写
  • "memory" clobber — 告知编译器内存可能被修改(屏障)
7. SSE/AVX 内置函数(优先于内联汇编)
#include <immintrin.h>   // includes all x86 SIMD headers

// Add 8 floats at once with AVX
__m256 a = _mm256_loadu_ps(arr_a);   // load 8 floats (unaligned)
__m256 b = _mm256_loadu_ps(arr_b);
__m256 c = _mm256_add_ps(a, b);
_mm256_storeu_ps(result, c);

在编译时检查 CPU 支持:-mavx2 或 -march=native。 在运行时检查:__builtin_cpu_supports("avx2")。

有关完整的寄存器和指令参考,请参阅 references/reference.md。

相关技能

  • 使用 skills/low-level-programming/assembly-arm 处理 AArch64/ARM 汇编
  • 使用 skills/compilers/gcc 了解 -S -masm=intel 标志的详细信息
  • 使用 skills/debuggers/gdb 单步调试汇编(si、ni、x/i)

评论

支持 Markdown