英特尔为指令添加前缀,检查优化问题

时间:2019-04-19 15:27:43

标签: optimization x86 intel disassembly micro-optimization

我想了解更多有关x86_64二进制文件中ptrace功能的信息,以反汇编指令。 目的是检查字节是否为指令前缀之一。

我在Intel® 64 and IA-32 Architectures Software Developer’s Manual(第2卷,第2章)中找到了一些信息。

2.1.1 INSTRUCTION PREFIXES部分显示以下前缀:

  • [{0x26] ES段覆盖
  • [{0x36] SS段覆盖前缀
  • [{0x2E] CS段覆盖前缀未采用分支
  • [{0x3E] DS段覆盖前缀已采取分支
  • [{0x64] FS段覆盖前缀
  • [{0x65] GS段覆盖前缀
  • [{0x66]操作数大小的覆盖前缀
  • [{0x67]地址大小覆盖前缀
  • [{0xF0] LOCK前缀
  • [{0xF2] REPNE / REPNZ前缀 BND前缀
  • [{0xF3] REP或REPE / REPZ前缀

视觉上,this chart以黄色显示前缀。

如果我想知道字节是否为前缀,我将尝试提高效率,并检查是否可以执行二进制操作。

如果我将0x260x360x2E0x3E分组。以2为底的这些数字(00100110001101100010111000111110)显示了一个公共部分:001XX110

如果我的字节在该组中,则会发现111001110xE7)的二进制运算。

太好了。现在,如果我第二个组包含0x640x650x660x670110010001100101,{{1} },01100110),我发现了另一个常见部分:01100111

然后,如果该字节在第二组中,则可以找到011001XX11111100)的和二进制运算。

剩余的指令前缀(0xFC0xF00xF2)出现问题:没有共同的部分。 0xF311111100)的与运算将使字节0xFC

一种解决方案是检查字节是否不是0xF1

因此,在C中可能的实现方式是:

0xF1

我来自英特尔,除了最后一组只能签入一个操作。

然后,最后一个问题是:我可以检查一个字节是0xF0、0xF2还是0xF3吗?

1 个答案:

答案 0 :(得分:2)

  

然后,最后一个问题是:我可以检查一个字节是0xF0、0xF2还是0xF3吗?

与一条指令最接近的是:

                     ;ecx = the byte
    bt [table],ecx   ;Is the byte F0, F2 or F3?
    jc .isF0F2orF3   ; yes

但是,有时前缀不被视为前缀(例如pause指令,其编码类似于rep nop,以兼容旧CPU)。

还要注意,对于高速反汇编程序,最快的方法可能是“跳转表驱动”,其中一个寄存器指向与解码器状态相对应的表,而另一个寄存器包含指令的下一个字节,例如:

                          ;ebx = address of table corresponding to the decoder's current state
    movzx eax,byte [esi]  ;eax = next byte of the instruction
    inc esi               ;esi = address of byte after the next byte of this instruction
    jmp [ebx+eax*4]       ;Go to the code that figures out what to do

在这种情况下,跳转到的某些代码段将设置一些标志而不更改当前表(例如,初始表中0xF3的条目将导致跳转到设置“看到前缀前缀”标志的代码) ),而跳转到的某些代码段将切换到另一个表(例如,初始表中0x0F的条目将导致跳转到更改EBX的代码,以指向用于所有用户的完全不同的表以0x0F, ...开头的指令);然后跳转到其中的一些代码将显示一条指令(并重置解码器的状态)。

例如;对于pause,代码可能是:

table0entryF3:
    or dword [prefixes],REP
    movzx eax,byte [esi]                ;eax = next byte of the instruction
    inc esi                             ;esi = address of byte after the next byte
    jmp [ebx+eax*4]

table0entry90:
    mov edx,instructionNameString_NOP
    test dword [prefixes],REP           ;Was it a PAUSE or NOP?
    je doneInstruction_noOperands       ; NOP, current name is right
    and dword [prefixes],~REP           ; PAUSE, pretend the REP prefix wasn't there
    mov edx,instructionNameString_PAUSE ;        and use the right name
    jmp doneInstruction_noOperands

doneInstruction_noOperands:
    call displayPrefixes
    call displayInstructionName
    mov dword [prefixes],0              ;Reset prefixes
    mov ebx,table0                      ;Switch current table back to the initial table
    movzx eax,byte [esi]                ;eax = first byte of next instruction
    inc esi                             ;esi = address of byte after the next byte
    jmp [ebx+eax*4]