(2014/04/11 2:00), Oleg Nesterov wrote:
> On 04/10, Oleg Nesterov wrote:
>>
>> On 04/10, Masami Hiramatsu wrote:
>>>
>>> (2014/04/10 22:41), Denys Vlasenko wrote:
>>>> There is this monstrosity, "16-bit override for branches" in 64-mode:
>>>>
>>>> 66 e8 nn nn       callw   <offset16>
>>>>
>>>> Nobody sane uses it because it truncates instruction pointer.
>>>
>>> No problem, insn.c can handle that too. :)
>>
>> Does it?
>>
>>      "callw 1f; 1:\n"
>>      "rep; nop\n"
>>
>> objdump:
>>
>>      66 e8 00 00             callw  485 <_init-0x3ffed3>
>>      f3 90                   pause
>>
>>
>> if we probe this "callw", we copy MAX_INSN_BYTES into auprobe->insn,
>> and after insn_get_length() (insn_complete() == T)
>>
>>      // this is correct
>>      OPCODE1() == e8
>>
>>      // this all looks wrong
>>      insn->length == 6
>>      insn->immediate.value == -1863122944
>>      insn->immediate.nbytes == 4
>>
>> so it seems that lib/insn.c treats the next "pause" insn as the high
>> 16 bits of address.
> 
> Or perhaps lib/insn.c is fine but objdump is wrong? And everything
> should work correctly? Although in this case I do not understand what
> this "callw" actually does.

Yeah, I think objdump is wrong. see below.

> 
>       int main(void)
>       {
>               asm (
>                       "nop\n"
> 
>                       "callw 1f; 1:\n"
>                       ".byte 0\n"
>                       ".byte 0\n"
>               );
> 
>               return 0;
>       }
> 
> this runs just fine. With or without gdb. And gdb shows that ->ip is
> incremented by 6 after "callw".
> 
>       int main(void)
>       {
>               asm (
>                       "nop\n"
> 
>                       "callw 1f; 1:\n"
>                       ".byte 10\n"
>                       ".byte 20\n"
>               );
> 
>               return 0;
>       }
> 
> objdump:
> 
>       000000000040047c <main>:
>         40047c:       55                      push   %rbp
>         40047d:       48 89 e5                mov    %rsp,%rbp
>         400480:       90                      nop
>         400481:       66 e8 00 00             callw  485 <_init-0x3ffed3>
>         400485:       0a 14 b8                or     (%rax,%rdi,4),%dl
>         400488:       00 00                   add    %al,(%rax)
>         40048a:       00 00                   add    %al,(%rax)
>         40048c:       c9                      leaveq
>         40048d:       c3                      retq
> 
> run:
> 
>       $ ./t
>       Segmentation fault (core dumped)
> 
>       $ gdb ./t core.*
>       ...
>       #0  0x00000000144a0487 in ?? ()
> 
> 0x144a0487 - 0x400481 == 0x140a0006, this matches the additional 2 .bytes 
> treated
> as offset.

Ah, OK. Ive also forgotten the operand size prefix on x86/x86-64.

The callw is actually "call with operand-size override prefix".
The operand-size prefix(0x66) changes the number of bytes (size) of
its operand (including immediate). But that depends on the opcode.

As I said, opcode 0xe8 (call) has Jz operand (jump offset immediate
with 16bit or 32bit size, depends on the operand size).
And on x86-32, the default operand-size is 4bytes, and it
changes to 2bytes with the 0x66 prefix. This means that the "66 e8"
becomes "callw" on x86-32.

However, please see Intel SDM 2b, appendix A,
A.2.5 Superscripts Utilized in Opcode Tables
----
f64
The operand size is forced to a 64-bit operand size when in 64-bit mode
(prefixes that change operand size are ignored for this instruction in 64-bit
mode
----
And Table A-2. One-byte Opcode Map: (08H — FFH)
-----
CALL(f64) Jz
-----

Ah, I got this. This means that "call" on x86-64 never be "callw",
because the operand-size always 64bit, and in that case, immediate
is 4 bytes(*).

(*) again, at A.2.2 Codes for Operand Type
---
z Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size.
---

So, at least for this case, objdump is wrong. lib/insn.c is correct. :)

Thank you,

-- 
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: [email protected]


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to