x86指令取指是否为原子?短跳转重写指令并发执行是否安全
Windows平台HotPatch并发安全性答疑
首先直接对应你的疑问给出结论:
- x86/x86_64平台不存在任意长度的原子指令取指,只有自然对齐的2/4/8字节内存访问是原子的,跨缓存行、跨页的指令取指必然是非原子的,热补丁的安全性确实依赖前置的对齐、指令约束,不是对任意代码都生效。
- 你看到的LLVM的HotPatch拦截实现,是专门针对Windows平台MSVC默认生成的热补丁兼容二进制设计的,已经满足了所有前置约束,不需要额外做原子写入也能保证并发场景下的安全:
- MSVC的
/hotpatch编译选项(x86_64平台默认生效)会强制函数入口的第一条指令必然是2字节对齐、长度恰好2字节的空操作类指令(比如32位下的mov edi, edi、64位下的nop word ptr [rax+rax]),根本不会出现你担心的带多前缀的长指令、跨对齐边界的情况,完全规避了非原子取指的问题。 - 写2字节短跳转的操作虽然分为两次单字节写入,但写入顺序固定为先写跳转opcode
0xEB,再写偏移量:全程的中间状态要么是原有的合法2字节空指令,要么是完整的合法短跳转指令,不会出现执行到非法指令的情况。
- MSVC的
- HotPatch的设计目标本身就包含并发执行场景下的安全性,但是这种安全性是建立在平台和编译约束之上的,不是通用方案:
- 如果短跳转的偏移范围不够,需要用长跳转,MSVC的
/functionpadmin链接选项(x86_64平台默认生效)会在函数入口前预留足够的padding空间,热补丁实现会先在前置padding区域写好完整的长跳转指令,再替换函数入口的2字节短跳转到前置padding的位置,全程没有非法中间状态。 - 超过2字节的长指令、带前缀的指令不会出现在兼容热补丁的二进制的函数入口位置,编译环节已经提前规避了这类情况,不需要额外处理。
- 如果短跳转的偏移范围不够,需要用长跳转,MSVC的
内容的提问来源于stack exchange,提问作者Alex Guteniev
相关产品推荐
相关产品推荐

