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

问题描述 投票:2回答:1

我想通过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)的二元运算。

大。现在,如果我采取第二组包含0x640x650x660x6701100100011001010110011001100111),我发现了另一个共同部分:011001XX

然后,111111000xFC)的二进制运算可以找到该字节是否在第二组中。

问题出现在剩余的指令前缀(0xF00xF20xF3):没有共同的部分。 111111000xFC)的操作将让字节0xF1

如果字节不是0xF1,一种解决方案是检查。

因此,C中可能的实现将是:

if ((byte & 0xE7) == 0x26) {
    /* This `byte` is a ES, SS, CS or DS segment override prefix */
}
if ((byte & 0xFC) == 0x64) {
    /* This `byte` is a FS, GS, Operand-size or address-size override prefix */
}
if ((byte & 0xFC) == 0xF0) {
    if (byte != 0xF1) {
        /* This `byte` is a LOCK, REPN(E/Z) or REP(_/E/Z) prefix */
    }
}

来自英特尔,除了最后一组可以只检入一个操作外,我会这样做。

然后,最后一个问题是:如果字节是0xF0,0xF2或0xF3,我可以检入一个操作吗?

optimization x86 intel disassembly micro-optimization
1个回答
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条目将导致跳转到设置“看到rep前缀”标志的代码),并且跳转到的一些代码将切换到另一个表(例如,初始表中的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]
© www.soinside.com 2019 - 2024. All rights reserved.