一个仅头文件的 C++20 库,用于编译时 x86/x86-64 指令编码。
本项目采用双重许可:Boost Software License 1.0 和 MIT License。您可以选择其中任一许可。
#include "static_asm.hpp"
using namespace static_asm::x86::registers;
using namespace static_asm::x86::instructions;
// 在编译时构建机器码
constexpr auto code = core::assemble(
mov(rax, 0x12345678), // mov rax, imm32
add(rax, rcx), // add rax, rcx
xor_(r8, r8), // xor r8, r8
call(rax), // call rax
ret() // ret
);
// code 是 std::array<uint8_t, N> - 完全 constexpr!
// 寄存器到寄存器
add(rax, rbx); // 48 01 D8
sub(ecx, edx); // 29 D1
and_(r8, r9); // 4D 21 C8
or_(rsi, rdi); // 48 09 FE
xor_(eax, eax); // 31 C0 (清零寄存器的常用惯用法)
cmp(rax, rcx); // 48 39 C8
// 寄存器与立即数
add(rax, 0x10); // 48 83 C0 10 (符号扩展的 imm8)
add(rax, 0x10000); // 48 05 00 00 01 00 (imm32)
sub(ecx, 100); // 83 E9 64
and_(rdx, 0xFF); // 48 83 E2 FF
// 带内存操作数
add(eax, dword_ptr(rbx)); // 03 03
add(rax, qword_ptr(rcx + 0x10)); // 48 03 41 10
sub(dword_ptr(rsp + 0x20), eax); // 29 44 24 20
// 寄存器到寄存器
mov(rax, rbx); // 48 89 D8
mov(eax, ecx); // 89 C8
mov(r8, r9); // 4D 89 C8
// 立即数到寄存器
mov(rax, 0x12345678); // 48 C7 C0 78 56 34 12
mov(eax, 0xDEADBEEF); // B8 EF BE AD DE
// 内存操作
mov(rax, qword_ptr(rbx)); // 48 8B 03
mov(eax, dword_ptr(rcx + 0x10)); // 8B 41 10
mov(qword_ptr(rsp + 0x8), rax); // 48 89 44 24 08
mov(dword_ptr(rbp - 0x20), 0x100); // C7 45 E0 00 01 00 00
// 零扩展/符号扩展
movzx(eax, bl); // 0F B6 C3 (字节零扩展到双字)
movzx(rax, bx); // 48 0F B7 C3 (字零扩展到四字)
movsx(eax, cl); // 0F BE C1 (字节符号扩展到双字)
movsx(rax, dx); // 48 0F BF C2 (字符号扩展到四字)
movsxd(rax, ecx); // 48 63 C1 (双字符号扩展到四字)
// 加载有效地址
lea(rax, qword_ptr(rbx + rcx * s4)); // 48 8D 04 8B
lea(rax, qword_ptr(rbx + rcx * s8 + 0x10)); // 48 8D 44 CB 10
// 交换
xchg(rax, rbx); // 48 87 D8
// [base + index*scale]
mov(eax, dword_ptr(rbx + rcx * s1)); // 8B 04 0B
mov(eax, dword_ptr(rbx + rcx * s2)); // 8B 04 4B
mov(eax, dword_ptr(rbx + rcx * s4)); // 8B 04 8B
mov(eax, dword_ptr(rbx + rcx * s8)); // 8B 04 CB
// [base + index*scale + displacement]
mov(rax, qword_ptr(rbx + rcx * s4 + 0x10)); // 48 8B 44 8B 10
mov(rax, qword_ptr(r12 + r13 * s8 + 0x1000)); // 4B 8B 84 EC 00 10 00 00
// 存储到 SIB 地址
mov(dword_ptr(rax + rdx * s4), ecx); // 89 0C 90
mov(qword_ptr(rbx + rsi * s8 + 0x20), rax); // 48 89 44 F3 20
// 带 SIB 的 LEA(适用于地址计算)
lea(rax, qword_ptr(rbx + rcx * s4)); // 48 8D 04 8B
lea(rax, qword_ptr(rdi + rsi * s8 + 0x100)); // 48 8D 84 F7 00 01 00 00
// 移位 1 位
shl(eax, 1); // D1 E0
shr(rax, 1); // 48 D1 E8
sar(ecx, 1); // D1 F9
// 按立即数移位
shl(eax, 4); // C1 E0 04
shr(rax, 8); // 48 C1 E8 08
sar(rdx, 16); // 48 C1 FA 10
// 按 CL 寄存器移位
shl(eax, cl); // D3 E0
shr(rax, cl); // 48 D3 E8
// 循环移位
rol(eax, 1); // D1 C0
ror(rax, 8); // 48 C1 C8 08
rcl(ecx, cl); // D3 D1
rcr(rdx, 1); // 48 D1 DA
// 单操作数(结果在 rdx:rax 中)
mul(rbx); // 48 F7 E3 (无符号:rdx:rax = rax * rbx)
imul(rcx); // 48 F7 E9 (有符号:rdx:rax = rax * rcx)
div(rbx); // 48 F7 F3 (无符号:rax = rdx:rax / rbx,rdx 为余数)
idiv(rcx); // 48 F7 F9 (有符号除法)
// 双操作数 IMUL(dest = dest * src)
imul(rax, rbx); // 48 0F AF C3
imul(ecx, edx); // 0F AF CA
// 三操作数 IMUL(dest = src * imm)
imul(rax, rbx, 10); // 48 6B C3 0A
imul(ecx, edx, 1000); // 69 CA E8 03 00 00
// 无条件跳转
jmp(0x10); // EB 10 (短跳转,8 位偏移)
jmp(0x1000); // E9 00 10 00 00 (近跳转,32 位偏移)
jmp(rax); // FF E0 (间接跳转)
jmp(here); // EB FE (jmp $,无限循环)
// 条件跳转(8 位偏移)
jz(0x10); // 74 10
jnz(0x20); // 75 20
jb(0x08); // 72 08 (低于/进位)
jae(0x08); // 73 08 (高于或等于/无进位)
jl(0x10); // 7C 10 (小于,有符号)
jge(0x10); // 7D 10 (大于或等于,有符号)
// 条件跳转(32 位偏移,用于较长分支)
jz_near(0x10000); // 0F 84 00 00 01 00
jnz_near(0x20000); // 0F 85 00 00 02 00
// 调用和返回
call(rax); // FF D0 (间接调用)
call(0x100); // E8 00 01 00 00 (相对调用)
ret(); // C3
ret(0x10); // C2 10 00 (返回并弹出 16 字节)
// 条件为真时传送(无分支惩罚!)
cmovz(rax, rbx); // 48 0F 44 C3 (零标志设置时传送)
cmovnz(eax, ecx); // 0F 45 C1 (零标志未设置时传送)
cmovl(rax, rdx); // 48 0F 4C C2 (小于时传送,有符号)
cmovge(ecx, esi); // 0F 4D CE (大于或等于时传送,有符号)
cmovb(rax, rbx); // 48 0F 42 C3 (低于时传送,无符号)
cmovae(edx, edi); // 0F 43 D7 (高于或等于时传送,无符号)
// 带内存源操作数
cmovz(rax, qword_ptr(rbx)); // 48 0F 44 03
cmovnz(eax, dword_ptr(rcx + 0x10)); // 0F 45 41 10
// 位测试
bt(eax, 5); // 0F BA E0 05
bt(rax, rbx); // 48 0F A3 D8
// 位测试并置位/复位/取反
bts(eax, 10); // 0F BA E8 0A (测试并置位)
btr(rax, rcx); // 48 0F B3 C8 (测试并复位)
btc(edx, 3); // 0F BA FA 03 (测试并取反)
// 位扫描
bsf(eax, ecx); // 0F BC C1 (正向扫描第一个 1)
bsr(rax, rbx); // 48 0F BD C3 (反向扫描第一个 1)
// 人口计数和前/后导零
popcnt(eax, ecx); // F3 0F B8 C1
lzcnt(rax, rbx); // F3 48 0F BD C3
tzcnt(eax, edx); // F3 0F BC C2
// 字节交换
bswap(eax); // 0F C8 (反转字节顺序)
bswap(rax); // 48 0F C8
// 基本字符串操作(操作 [rsi] 和/或 [rdi])
movsb(); // A4 (将字节从 [rsi] 移动到 [rdi])
movsw(); // 66 A5
movsd(); // A5
movsq(); // 48 A5
cmpsb(); // A6 (比较 [rsi] 与 [rdi])
stosb(); // AA (将 al 存储到 [rdi])
lodsb(); // AC (将 [rsi] 加载到 al)
scasb(); // AE (比较 al 与 [rdi])
// 带 REP 前缀(重复 rcx 次)
rep_movsb(); // F3 A4 (memcpy)
rep_movsq(); // F3 48 A5 (快速 memcpy,一次 8 字节)
rep_stosb(); // F3 AA (memset)
rep_stosq(); // F3 48 AB
// 带 REPE/REPNE(相等/不相等时重复)
repe_cmpsb(); // F3 A6 (比较字符串直到不匹配)
repne_scasb(); // F2 AE (在字符串中扫描字节)
push(rax); // 50
push(rbx); // 53
push(r8); // 41 50
push(0x10); // 6A 10 (压入 imm8)
push(0x1000); // 68 00 10 00 00 (压入 imm32)
pop(rax); // 58
pop(rbx); // 5B
pop(r15); // 41 5F
// 系统调用
syscall_(); // 0F 05 (64 位 syscall)
sysenter(); // 0F 34
sysexit(); // 0F 35
// 中断
int3(); // CC (断点)
int_(0x80); // CD 80 (Linux 32 位 syscall)
int_(0x21); // CD 21 (DOS 中断)
// CPU 信息
cpuid(); // 0F A2
rdtsc(); // 0F 31
rdtscp(); // 0F 01 F9
// 特权指令
cli(); // FA (清除中断标志)
sti(); // FB (设置中断标志)
hlt(); // F4 (停机)
// 中断返回
iret(); // CF (16 位)
iretd(); // CF (32 位)
iretq(); // 48 CF (64 位)
使用 core::assemble() 拼接指令字节数组: