7

I encountered a strange x86-32 instruction (opcode 0x65) decoded by objdump as gs (not %gs but gs). I found it while a full linear sweep of a binary (objdump -D), so the decoding was surely incorrect. But, still, objdump didn't decode it as a (bad) instruction, so it means that it can be encountered and I would like to know what does it means.

Here is an example of this instruction:

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>

Note that searching for this instruction on the Web is quite difficult because of the %gs register which mask all other possible hit.

So, is it a real "instruction" or is it glitch produced by gas ?

  • Hmm, it seems to be bug from the GNU binutils... The opcode 0x65 correspond in fact to a prefix corresponding to %gs:(mem_ref). But, here, the libopcodes parser seems to wrongly interpret it and forget to interpret what follow as a memory reference... (I may be wrong, but I will try to answer when I will know more about all this). – perror Aug 23 '13 at 15:17
  • 2
    According to Intel's manuals, the ins* instructions ignore segment override prefixes and always use %es. – DCoder Aug 23 '13 at 15:28
  • So, it means that this is because you have the opcodes 0x65 followed by an ins instruction that the decoder is wrong... I see, it is interesting. Thanks. – perror Aug 23 '13 at 15:36
  • 1
    A bit late, but: the decoder gets it "wrong" because you are disassembling a zero-terminated text string. You cannot make decisions on "good" or "bad" disassembly while feeding it with bad input. (Funny: this string is so well-known that I got it after ment'ly decoding the first three characters.) – usr2564301 Oct 20 '13 at 20:39
6

Strictly speaking it's not an instruction. It's the segment override prefix (prefixes are considered to be part of the instruction).

Most memory accesses use DS segment selector by default except those involving ESP or EBP register (they default to SS) and some "string" instructions (movs, scas etc). Segment override prefixes allow you to use another segment selector to access your data. E.g. in DOS times the CS override was commonly used to access data stored in the code segment (such as jump tables):

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

The 80386 added two extra segment registers (GS and FS) and the corresponding prefixes.

Since the GS prefix does not actually affect the following instruction (insb) in the code snipped above, GAS opted out for printing it on a separate line.

In some of the following instructions you can see how it affects the disassembly:

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

BTW, 67 is another prefix, this time the address size override. It is why the instruction uses the 16-bit SI register and not the full ESI.

  • This is pretty neat and clear (as ever, Igor!). But, would you consider this as an unwanted behavior (bug) of gas ? – perror Aug 23 '13 at 15:40
  • Well, I don't know. You could argue it both ways. It's not like GAS is hardened against nonsense/obfuscated code, you should be glad it did not crash at least :) – Igor Skochinsky Aug 23 '13 at 16:54
  • P.S. sometimes it does make sense to put prefix in a separate pseudo-instruction, see e.g. this snippet from some old libc. – Igor Skochinsky Aug 23 '13 at 17:11
  • If I understand well your example, the symbol is placed after the prefix of the instruction ??? It does mean that depending if we are coming from the block before or if we are jumping to it through the symbol, the semantics is not quite exactly the same (one is atomic and the other is not). I definitely hate x86, it gives me headaches ! :-) – perror Aug 23 '13 at 17:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.