This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: Fix i8086 disassembler for 16bit displacements
On Mon, Feb 05, 2007 at 03:34:40PM +0000, Jan Beulich wrote:
> >>> "H. J. Lu" <hjl@lucon.org> 05.02.07 16:00 >>>
> >On Mon, Feb 05, 2007 at 09:21:52AM +0000, Jan Beulich wrote:
> >> >>> "H. J. Lu" <hjl@lucon.org> 03.02.07 01:37 >>>
> >> >OP_J masked displacement to 16bit for all 16bit displacements. It
> >> >should do it only when there is a data16 prefix. I am checking in this
> >> >patch to fix it.
> >>
> >> The other way around - a data size prefix in 16-bit mode makes it a
> >> 32-bit jump (and the jump remains confined to a 16-bit target without
> >> a prefix), so I think the changes, clearly the test case adjustments,
> >> are wrong.
> >
> >Jump is PC relative. You can't get 32bit distance with get16.
>
> Exactly, but that's what you broke. A 16 bit jump (obviously with
> origin being 16 bits wide) can only reach a 16-bit wide target, but
> the change you did made it so the disassembled target exceeds
> 16 bits. You forget that while relative, there's wrapping at 64k.
>
> >As
> >for a data size prefix in 16-bit mode, we shouldn't call get16. If
> >we do, it is a bug. Please open a bug report with a testcase.
>
> The test cases are there - the ones you (incorrectly) changed.
>
I believe this patch should properly handle 64K wrap around with the
same segment in 16bit mode.
H.J.
---
ld/testsuite/
2076-02-05 H.J. Lu <hongjiu.lu@intel.com>
* ld-i386/pcrel16.d: Undo the last change.
* ld-x86-64/pcrel16.d: Likewise.
opcodes/
2076-02-05 H.J. Lu <hongjiu.lu@intel.com>
* i386-dis.c (OP_J): Undo the last change. Properly handle 64K
wrap around with the same segment in 16bit mode.
--- binutils/ld/testsuite/ld-i386/pcrel16.d.16bit 2007-02-03 12:03:23.000000000 -0800
+++ binutils/ld/testsuite/ld-i386/pcrel16.d 2007-02-05 09:58:50.000000000 -0800
@@ -12,4 +12,4 @@ Disassembly of section .text:
420: cd 42[ ]+int \$0x42
422: ca 02 00[ ]+lret \$0x2
...
- f065: e9 b8 13[ ]+jmp 10420 <__bss_start\+0x3b8>
+ f065: e9 b8 13[ ]+jmp 420 <_start\+0x420>
--- binutils/ld/testsuite/ld-x86-64/pcrel16.d.16bit 2007-02-03 12:03:23.000000000 -0800
+++ binutils/ld/testsuite/ld-x86-64/pcrel16.d 2007-02-05 09:58:50.000000000 -0800
@@ -12,4 +12,4 @@ Disassembly of section .text:
420: cd 42[ ]+int \$0x42
422: ca 02 00[ ]+lret \$0x2
...
- f065: e9 b8 13[ ]+jmp 10420 <_start\+0x10420>
+ f065: e9 b8 13[ ]+jmp 420 <_start\+0x420>
--- binutils/opcodes/i386-dis.c.16bit 2007-02-03 12:03:23.000000000 -0800
+++ binutils/opcodes/i386-dis.c 2007-02-05 09:57:41.000000000 -0800
@@ -4901,6 +4901,7 @@ OP_J (int bytemode, int sizeflag)
{
bfd_vma disp;
bfd_vma mask = -1;
+ bfd_vma segment = 0;
switch (bytemode)
{
@@ -4918,11 +4919,14 @@ OP_J (int bytemode, int sizeflag)
disp = get16 ();
if ((disp & 0x8000) != 0)
disp -= 0x10000;
- /* For some reason, a data16 prefix on a jump instruction
- means that the pc is masked to 16 bits after the
- displacement is added! */
- if ((prefixes & PREFIX_DATA) != 0)
- mask = 0xffff;
+ /* In 16bit mode, address is wrapped around at 64k within
+ the same segment. Otherwise, a data16 prefix on a jump
+ instruction means that the pc is masked to 16 bits after
+ the displacement is added! */
+ mask = 0xffff;
+ if ((prefixes & PREFIX_DATA) == 0)
+ segment = ((start_pc + codep - start_codep)
+ & ~((bfd_vma) 0xffff));
}
used_prefixes |= (prefixes & PREFIX_DATA);
break;
@@ -4930,7 +4934,7 @@ OP_J (int bytemode, int sizeflag)
oappend (INTERNAL_DISASSEMBLER_ERROR);
return;
}
- disp = (start_pc + codep - start_codep + disp) & mask;
+ disp = ((start_pc + codep - start_codep + disp) & mask) | segment;
set_op (disp, 0);
print_operand_value (scratchbuf, 1, disp);
oappend (scratchbuf);