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
产生的故障?#1 楼
严格来说,这不是指令。这是段覆盖前缀(前缀被视为指令的一部分)。默认情况下,大多数内存访问使用
DS
段选择器,但涉及ESP
或EBP
寄存器(它们默认为SS
)的段选择器和一些“字符串”指令(movs
,scas
等)。段覆盖前缀允许您使用另一个段选择器来访问数据。例如。在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
评论
嗯,这似乎是来自GNU binutils的错误...操作码0x65实际上对应于与%gs:(mem_ref)对应的前缀。但是,在这里,libopcodes解析器似乎错误地解释了它,却忘记了将后续内容解释为内存引用……(我可能是错的,但是当我对所有这些都了解更多时,我会尝试回答)。 >根据Intel的手册,ins *指令忽略段覆盖前缀,并始终使用%es。
所以,这意味着这是因为您有0x65的操作码,后接一条ins指令,表明解码器是错误的...我知道,这很有趣。谢谢。
有点晚了,但是:解码器将其“错误”了,因为您正在反汇编以零结尾的文本字符串。当输入错误的输入时,您不能对“好”或“坏”的拆卸做出决定。 (有趣:这个字符串非常有名,以至于我在对前三个字符进行了解码之后就知道了。)