我遇到了一个奇怪的x86-32指令(操作码0x65),被objdump解码为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产生的故障?

评论

嗯,这似乎是来自GNU binutils的错误...操作码0x65实际上对应于与%gs:(mem_ref)对应的前缀。但是,在这里,libopcodes解析器似乎错误地解释了它,却忘记了将后续内容解释为内存引用……(我可能是错的,但是当我对所有这些都了解更多时,我会尝试回答)。 >
根据Intel的手册,ins *指令忽略段覆盖前缀,并始终使用%es。

所以,这意味着这是因为您有0x65的操作码,后接一条ins指令,表明解码器是错误的...我知道,这很有趣。谢谢。

有点晚了,但是:解码器将其“错误”了,因为您正在反汇编以零结尾的文本字符串。当输入错误的输入时,您不能对“好”或“坏”的拆卸做出决定。 (有趣:这个字符串非常有名,以至于我在对前三个字符进行了解码之后就知道了。)

#1 楼

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

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

GS)以及相应的前缀。

由于FS前缀实际上不会影响上面代码中的以下指令(GS),因此GAS选择了将其打印在单独的一行上。 >
在以下某些说明中,您会看到它如何影响反汇编:

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


BTW,67是另一个前缀,这一次地址大小优先。这就是为什么指令使用16位insb寄存器而不使用完整的SI的原因。

评论


这非常简洁明了(一如既往,Igor!)。但是,您是否认为这是有害的气体行为(错误)?

–恐怖
13年8月23日在15:40

好吧,我不知道。您可以双向争论。并不是说GAS可以针对废话/混淆代码进行强化,但您应该很高兴它至少没有崩溃:)

–伊戈尔·斯科钦斯基♦
13年8月23日在16:54

附言有时将前缀放在单独的伪指令中确实很有意义,例如来自某些旧libc的这段代码。

–伊戈尔·斯科钦斯基♦
13年8月23日在17:11

如果我很好地理解了您的示例,则将符号放置在指令的前缀之后?这确实意味着,取决于我们是从块前来还是通过符号跳转到块,其语义并不完全相同(一个是原子的,另一个不是原子的)。我绝对讨厌x86,这让我头疼! :-)

–恐怖
13年8月23日在17:23