GAS/x86 反汇编了一个裸 gs 寄存器作为指令,这是一个错误吗?

逆向工程 拆卸 x86 转储
2021-07-04 08:44:52

我遇到了一个奇怪的 x86-32 指令(操作码0x65),解码为objdumpas gs(不是%gs但是gs)。我是在对二进制 ( objdump -D)进行完整线性扫描时发现的,因此解码肯定是不正确的。但是,仍然objdump没有将其解码为(bad)指令,因此这意味着可以遇到它,我想知道它是什么意思。

这是此指令的示例:

080484fc <_IO_stdin_used>:
 80484fc:       01 00                   add    %eax,(%eax)
 80484fe:       02 00                   add    (%eax),%al
 8048500:       48                      dec    %eax
 8048501:       65                      gs     <======================= Here!!!
 8048502:       6c                      insb   (%dx),%es:(%edi)
 8048503:       6c                      insb   (%dx),%es:(%edi)
 8048504:       6f                      outsl  %ds:(%esi),(%dx)
 8048505:       20 57 6f                and    %dl,0x6f(%edi)
 8048508:       72 6c                   jb     8048576 <_IO_stdin_used+0x7a>
 804850a:       64 21 0a                and    %ecx,%fs:(%edx)
 804850d:       00 44 6f 64             add    %al,0x64(%edi,%ebp,2)
 8048511:       67 65 20 54 68          and    %dl,%gs:0x68(%si)
 8048516:       69                      .byte 0x69
 8048517:       73 21                   jae    804853a <_IO_stdin_used+0x3e>

请注意,由于%gs寄存器屏蔽了所有其他可能的命中,因此在 Web 上搜索此指令非常困难

那么,它是真正的“指令”还是由 产生的故障gas

1个回答

严格来说,这不是指令。它是段覆盖前缀(前缀被认为是指令的一部分)。

大多数存储器访问使用DS默认除涉及段选择ESPEBP寄存器(它们默认SS)和一些“字符串”的指令(movsscas等)。段覆盖前缀允许您使用另一个段选择器来访问您的数据。例如在 DOS 时代,CS覆盖通常用于访问存储在代码段中的数据(例如跳转表):

seg001:00EA shl bx, 1 ; SWITCH
seg001:00EC jmp cs:off_13158[bx] ; switch jump
...
seg001:0588 off_13158  dw offset loc_12DD7 ; DATA XREF: _main+E6r
seg001:0588            dw offset loc_12DE5 ; jump table for switch statement
seg001:0588            dw offset loc_12DE5
seg001:0588            dw offset loc_12DE5

80386 添加了两个额外的段寄存器(GSFS)和相应的前缀。

由于GS前缀实际上并不影响insb上面截取的代码中的以下指令 ( ),因此 GAS 选择不将其打印在单独的行上。

在以下一些说明中,您可以看到它如何影响反汇编:

64 21 0a       ->  and %ecx, %fs:(%edx)
^^                           ^^^
67 65 20 54 68 -> and %dl, %gs:0x68(%si)
   ^^                      ^^^

顺便说一句,67 是另一个前缀,这次是地址大小覆盖。这就是为什么该指令使用 16 位SI寄存器而不是完整的ESI.