英特尔指令集参考给我们增加了指令:
VEX.NDS.LIG.F2.0F.WIG 58 /r
VADDSD xmm1, xmm2, xmm3/m64
如我们所见,L位被忽略(可以为0或1)。
添加的xmm0,xmm0,xmm0的机器码:
0xC4, 0xE1, 0x7B, 0x58, 0xC0
C4 - indicates 3-byte VEX prefix
E1 - R = 1; X = 1; B = 1; m-mmmm = 1 (implied 0F escape)
7B - W = 0; vvvv = 1111 (xmm0); L = 0; pp = 11 (implied F2 prefix)
58 - opcode byte
C0 - mod-rm byte
让我们测试一下:
void exec(Byte* code, int size)
{
Byte* buf = (Byte*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(buf, code, size);
buf[size] = 0xC3;
((void (*)())buf)();
VirtualFree(buf, 4096, MEM_DECOMMIT);
}
void f()
{
Byte code[] = { 0xC4, 0xE1, 0x7B, 0x58, 0xC0 };
exec(code, sizeof(code));
}
很好,Visual Studio反汇编程序也能识别指令。
但是,当我将L位更改为1(0x7B替换为0x7F)时,反汇编程序无法识别指令,并且会生成无效指令异常。这是否意味着尽管有英特尔手册,L位也必须始终为0?
最佳答案
看起来LIG并不意味着L位被忽略。手册的那部分是错误的。实际上,它实际上是.LZ
或.128
的同义词,表示L必须为0。
您是对的,英特尔的insn ref手册(第3.1.1.2节(x86手册第2卷的指令摘要表(带VEX前缀的指令)中的“操作码”列)与观察到的行为相矛盾:
如果操作码列中存在VEX.LIG:VEX.L值为
忽略了。这通常适用于VEX编码的标量SIMD
浮点指令。
但是,它也与同一手册中的其他文档相矛盾。英特尔手册确实有偶尔的错误。 :(我想您可以在Intel论坛上报告错误。
据推测,英特尔改变了对忽略该位的想法,并决定保留标量操作码的L = 1编码,但忘记了更新文档以了解VEX.LIG在insn-encoding部分中的含义。
他们在正式发布之前(可能在完成硬件设计的每个细节之前)将对insn set参考手册的将来扩展更新发布。 (当前的未来扩展补充pdf描述了AVX512指令(可在KNL中找到)以及一些其他扩展,这些扩展尚未在官方手册中提供,也未在任何市售的硅AFAIK中提供。)(指向英特尔文档页面的链接,和大量其他内容,请参见x86标签Wiki)。
从Intel的insn参考手册中,图2-9 VEX位字段:
L:向量长度
标量或128位向量
256位向量
第2.3.6.2节解释了同一件事。
请注意,某些BMI1 / 2指令使用VEX编码,并且L = 0。看来他们用.Lz
表示了它:VEX.NDS.LZ.0F38.W0 F2 /r
是ANDN r32a, r32b, r/m32
。