寻求X86_64(amd64)无效二进制指令序列的高效查找方案及解码语法
如何系统推导AMD64未使用的指令序列并添加自定义指令到gem5
核心需求
我想要在X86_64(amd64)架构中添加自定义指令,生成包含这些指令的二进制文件后在gem5模拟器运行。目前仅能获取单字节未使用操作码列表,需要AMD64完整的解码语法,以此系统推导更长的无效二进制指令序列,替代当前的暴力测试方法。
现有暴力测试方案
当前通过C程序嵌入汇编字节序列,编译后用objdump标记的(bad)字段判断无效指令:
测试代码
int main() { asm volatile(".byte 0x06" ::: "memory"); asm volatile(".byte 0x07" ::: "memory"); asm volatile(".byte 0x0E" ::: "memory"); asm volatile(".byte 0x16" ::: "memory"); asm volatile(".byte 0x17" ::: "memory"); asm volatile(".byte 0x1E" ::: "memory"); asm volatile(".byte 0x1F" ::: "memory"); asm volatile(".byte 0x27" ::: "memory"); asm volatile(".byte 0x2F" ::: "memory"); asm volatile(".byte 0x37" ::: "memory"); asm volatile(".byte 0x3F" ::: "memory"); asm volatile(".byte 0x60" ::: "memory"); asm volatile(".byte 0x61" ::: "memory"); asm volatile(".byte 0x62" ::: "memory"); asm volatile(".byte 0x82" ::: "memory"); asm volatile(".byte 0x9A" ::: "memory"); asm volatile(".byte 0xC4" ::: "memory"); asm volatile(".byte 0xC5" ::: "memory"); asm volatile(".byte 0xD4" ::: "memory"); asm volatile(".byte 0xD5" ::: "memory"); asm volatile(".byte 0xD6" ::: "memory"); asm volatile(".byte 0xEA" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x00" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x01" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x02" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x03" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x04" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x05" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x06" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x07" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x08" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x09" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0A" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0B" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0C" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0D" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0E" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x0F" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x10" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x11" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x13" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x17" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x18" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x19" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1A" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1B" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1C" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1D" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1E" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x1F" ::: "memory"); asm volatile(".byte 0xC5, 0x00, 0x01" ::: "memory"); return 0; }
测试命令
gcc main.c && objdump -D -j .text a.out
示例输出(关键片段)
0000000000001119 <main>: 1119: 55 push %rbp 111a: 48 89 e5 mov %rsp,%rbp 111d: 06 (bad) 111e: 07 (bad) 111f: 0e (bad) 1120: 16 (bad) 1121: 17 (bad) 1122: 1e (bad) 1123: 1f (bad) 1124: 27 (bad) 1125: 2f (bad) 1126: 37 (bad) 1127: 3f (bad) 1128: 60 (bad) 1129: 61 (bad) 112a: 62 82 (bad) 112c: 9a (bad) 112d: c4 (bad) 112e: c5 d4 d5 (bad) 1131: d6 (bad) 1132: ea (bad) 1133: c5 00 00 (bad) 1136: c5 00 01 (bad) 1139: c5 00 02 (bad) 113c: c5 00 03 (bad) 113f: c5 00 04 (bad) 1142: c5 00 05 (bad) 1145: c5 00 06 (bad) 1148: c5 00 07 (bad) 114b: c5 00 08 (bad) 114e: c5 00 09 (bad) 1151: c5 00 0a (bad) 1154: c5 00 0b (bad) 1157: c5 00 0c (bad) 115a: c5 00 0d (bad) 115d: c5 00 0e (bad) 1160: c5 00 0f (bad) 1163: c5 00 10 (bad) 1166: c5 00 11 (bad) 1169: c5 00 13 (bad) 116c: c5 00 17 (bad) 116f: c5 00 18 (bad) 1172: c5 00 19 (bad) 1175: c5 00 1a (bad) 1178: c5 00 1b (bad) 117b: c5 00 1c (bad) 117e: c5 00 1d (bad) 1181: c5 00 1e (bad) 1184: c5 00 1f (bad) 1187: c5 00 01 (bad) 118a: b8 00 00 00 00 mov $0x0,%eax 118f: 5d pop %rbp 1190: c3 ret
解决方案
1. 获取AMD64解码语法资源
- 官方架构手册:Intel和AMD的官方软件开发者手册第2卷(指令集参考)是最权威来源,详细定义了指令编码结构:前缀(REX/VEX/EVEX等)、主操作码(1-3字节)、ModRM/SIB字节、立即数的组合规则,以及每类指令的操作码映射范围。
- 开源解码器实现:参考gem5自身的X86解码器代码(
src/arch/x86/isa/decoder目录),或者udis86、capstone等开源项目的解码逻辑,这些代码直接实现了AMD64的解码规则,能清晰看到未定义的操作码组合。 - 结构化编码文档:第三方整理的按前缀分类的操作码空间文档,可快速定位未被占用的编码区间。
2. 系统推导无效指令序列的方法
- 编码结构排除法:
- 明确AMD64指令的基本结构:可选前缀 + 1-3字节主操作码 + 可选ModRM/SIB字节 + 可选偏移量/立即数。
- 按前缀类型(无前缀、0F双字节操作码、VEX前缀等),对照官方手册排除已定义的操作码范围,剩余区间即为潜在无效序列。比如VEX前缀的C5开头指令,后续操作码字节若不在官方定义列表中,就属于无效指令(如你测试的
C5 00 xx系列)。
- 自动化解码器验证:
- 用
capstone库编写脚本,批量测试指令序列的解码结果,返回“无效指令”的序列即可作为自定义指令编码,效率远高于手动暴力测试。 - 在gem5中添加临时调试逻辑,让模拟器输出无法解码的指令序列,结合自定义需求筛选合适的编码。
- 用
- 优先选择连续未占用区间:
- 优先挑选连续未被使用的操作码块,而非零散字节,方便后续扩展自定义指令,也避免和现有指令冲突。比如某些VEX前缀下的操作码子空间完全未被使用,是最优选择。
内容的提问来源于stack exchange,提问作者Setu
相关产品推荐
相关产品推荐

