如何无修改寄存器/FLAGS、无栈操作检测x86代码的16/32位运行模式?
x86运行时模式检测:无栈、无状态修改的兼容方案
需求背景
预编译的x86代码需运行时检测当前处于16位模式(实模式/16位保护模式)还是32位模式(i386保护模式),要求满足:
- 不使用栈;
- 不修改通用寄存器、段寄存器、标志位;
- 兼容8086(仅支持16位模式)与386(支持两种模式)。
现有方案依赖栈操作(pushf/popf)不符合需求;曾尝试的lea esi, [dword esi+0]在16位模式下并非无操作,也不满足要求。
解决方案:利用指令编码长度差异的无状态检测
核心思路是利用同一指令在16位和32位模式下的编码长度差异,结合无操作指令(不修改任何状态)实现分支跳转,全程无栈操作、无状态修改。
实现代码(NASM)
bits 16 cpu 386 ; 模式检测核心逻辑:无栈、无寄存器/标志修改,兼容8086与386 strict mov ax, ax ; 16位模式下编码为2字节(89 C0),32位模式下强制生成16位操作数编码(66 89 C0,3字节) jmp short .in_16bit .in_32bit: bits 32 ; 32位模式执行代码,示例: int 32 jmp .end .in_16bit: bits 16 ; 16位模式执行代码,示例: int 16 .end: bits 16
原理说明
- 16位模式(含8086):处理器将
strict mov ax, ax解析为2字节的无操作指令,后续jmp short .in_16bit的偏移基于指令地址+2计算,直接跳转到16位分支执行代码,全程无状态修改。 - 32位模式:
strict mov ax, ax被强制生成为3字节的16位操作数无操作指令,后续jmp short .in_16bit的偏移基于指令地址+3计算,跳转目标自动指向32位分支,执行对应代码,同样无状态修改。
内容的提问来源于stack exchange,提问作者pts
相关产品推荐
相关产品推荐

