assembly - x86指令前缀解码

标签 assembly x86 x86-64 disassembly

我目前正在为 x86_x64 CISC 开发反汇编程序。 我有两个关于前缀指令解码的问题:

  1. 对于以下流:

    \x9b\x9b\xd9\x30
    

    GCCobjdump 输出

    fstenv [eax]
    

    所以他们首先读取所有前缀 (不超过15个)然后继续检查指令是否正确 使用最后一个前缀读取 \x9b\xd9 使其成为 fstenv 说明。

    Capstone 另一方面输出

    wait
    wait
    fnstenv dword ptr [eax] 
    

    现在,显然是错误的 它放置了 2 个 wait 指令,而不仅仅是 1 个。但是它应该放置 wait 指令,或者 GCCobjdump 位于右侧 此处用于消耗 fstenv 的所有额外 \x9b 前缀 指令?

  2. 对于以下流:

    \xf2\x66\x0f\x12\x00
    

    GCCobjdump 输出

    data16 movddup xmm0,QWORD PTR [eax]
    

    所以他们正在安排 以特定顺序添加前缀,因此 \x66\xf2 之前被解释 因此,他们仍然使用最后一个前缀 \xf2 来 确定指令movddup。那么他们来这里是为了 使用前缀的这种排列逻辑还是错误的?

    Capstone 另一方面输出

    movlpd xmm0,qword ptr [eax]

    所以他们没有以任何顺序排列前缀,他们只是 取最后一个前缀读取\x66来确定指令 在这种情况下, movlpd 看起来比 GCCobjdump 正在做。

CPU实际上如何解释这些流?

最佳答案

可以相对容易地测试您的 CPU 如何实际解释这些流。

<小时/>

第一个直播可以使用我的工具nanoBench 。您可以使用命令

sudo ./nanoBench.sh -asm_init“mov RAX,R14”-asm“.byte 0x9b,0x9b,0xd9,0x30”

此命令首先将 RAX 设置为有效的内存地址,然后多次运行您的流。在我的 Core i7-8700K 上,我得到以下输出(对于固定功能性能计数器):

Instructions retired: 3.00
Core cycles: 73.00
Reference cycles: 62.70

我们可以看到 CPU 执行了三个指令,因此 Capstone 似乎是正确的。

<小时/>

您可以使用nanoBench的 Debug模式分析第二个流:

sudo ./nanoBench.sh -unroll 1 -asm "mov RAX, R14; mov qword ptr [RAX], 1234; .byte 0xf2, 0x66, 0x0f, 0x12, 0x00"-debug .

这将在 gdb 内 - 首先执行 asm 代码,然后生成断点陷阱。我们现在可以查看 XMM0 寄存器的当前值:

(gdb) p $xmm0.v2_int64
$1 = {1234, 1234}

因此,XMM0 的高四字和低四字现在与地址 RAX 处的内存具有相同的值,这表明 CPU 执行了 movddup 指令。

<小时/>

您还可以在不使用 nanoBench 的情况下分析第二个流。为此,您可以将以下汇编代码保存在文件 asm.s 中。

.intel_syntax noprefix

.global _start
_start:
    mov RAX, RSP
    mov qword ptr [RAX], 1234   
    .byte 0xf2, 0x66, 0x0f, 0x12, 0x00
    int 0x03 /* breakpoint trap */

然后,您可以使用构建它

as asm.s -o asm.o
ld -s asm.o -o asm

现在您可以使用 gdb ./asm 来分析它:

(gdb) r
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000000000400088 in ?? ()
(gdb) p $xmm0.v2_int64
$2 = {1234, 1234}

关于assembly - x86指令前缀解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54886083/

相关文章:

c++ - 为什么两次比较 char 变量比一次比较 short 变量更快

linux - 在 64 位 Linux 上从 32 位模式切换到 64 位(长模式)

assembly - x86在x86-x64中不同或已完全删除的32位操作码

assembly - 旧CPU如何执行新的ENDBR64和ENDBR32指令?

pointers - 应该在64位x86中对指针比较进行签名还是不签名?

assembly - rel8 立即数操作数的 x86-64 Intel 语法?

assembly - ARMv8 异常向量和处理

linux - 如何切换gdb字节输出分组

assembly - 如何使用 64 位调用门

linux-kernel - 通过 NUMA 环回优化套接字数据传输