SuperAPI AI 工具集

assembly-x86

编程与开发

查看项目

更新于 10-15 15:31

技能介绍

用途

本技能引导代理处理 x86-64 汇编:阅读编译器输出、理解 ABI、编写内联汇编,以及掌握常见汇编模式。

适用触发场景包括:如何阅读 GCC 生成的汇编?x86-64 有哪些寄存器?Linux/macOS 上的调用约定是什么?如何在 C 中编写内联汇编?如何使用 SSE/AVX 内联函数?汇编中的 %rsp、%rbp 是什么意思?

生成与阅读汇编

  • AT&T 语法(GCC 默认):gcc -S -O2 -fverbose-asm foo.c -o foo.s
  • Intel 语法:gcc -S -masm=intel -O2 foo.c -o foo.s
  • 从 GDB 查看:(gdb) disassemble /s main(带源码)、(gdb) x/20i $rip
  • 从 objdump 查看:objdump -d -M intel -S prog(Intel 语法加源码,需要 -g)

x86-64 寄存器

资料给出寄存器在各宽度下的名称与用途:

  • %rax / %eax / %ax / %ah / %al:返回值/累加器
  • %rbx / %ebx / %bx / %bh / %bl:被调用者保存
  • %rcx / %ecx / %cx / %ch / %cl:第 4 个参数/计数
  • %rdx / %edx / %dx / %dh / %dl:第 3 个参数/第二个返回值
  • %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(及对应 32/16/8 位形式):被调用者保存
  • %rip:指令指针
  • %rflags / %eflags:状态标志
  • %xmm0–%xmm7:浮点/SIMD 参数与返回值
  • %xmm8–%xmm15:调用者保存的 SIMD
  • %ymm0–%ymm15:AVX 256 位
  • %zmm0–%zmm31:AVX-512 512 位

System V AMD64 ABI(Linux、macOS、FreeBSD)

  • 整数/指针参数寄存器(按顺序):%rdi, %rsi, %rdx, %rcx, %r8, %r9
  • 浮点参数寄存器:%xmm0–%xmm7
  • 返回值:整数用 %rax(低位)、%rdx(128 位时的高位);浮点用 %xmm0(低位)、%xmm1(高位)
  • 调用者保存(scratch):%rax, %rcx, %rdx, %rsi, %rdi, %r8–%r11, %xmm0–%xmm15
  • 被调用者保存(必须保留):%rbx, %rbp, %r12–%r15
  • 栈:调用前 16 字节对齐;call 压入 8 字节,因此函数入口在序言后 16 字节对齐
  • 红区:叶子函数可不调整 %rsp 而使用 %rsp 以下 128 字节;内核/信号处理器中不可用

常见指令模式

资料列出以下模式及其含义:

  • 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:有符号小于时跳转

AT&T 与 Intel 语法

资料给出对照:

  • 操作数顺序:AT&T 为 source, dest;Intel 为 dest, source
  • 寄存器前缀:AT&T 为 %rax;Intel 为 rax
  • 立即数前缀:AT&T 为 $42;Intel 为 42
  • 内存操作数:AT&T 为 8(%rdi);Intel 为 [rdi+8]
  • 大小后缀:AT&T 为 movl、movq;Intel 无(推断得出)

GCC 默认输出 AT&T;使用 -masm=intel 切换为 Intel 语法。

内联汇编(GCC 扩展 asm)

资料给出三个示例:

基本寄存器递增:

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 示例:

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

原子递增:

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:告知编译器内存可能被修改(屏障)

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)

限制

资料未说明是否需要特定平台、工具版本或额外依赖,也未提供收费、价格或效果相关信息。