PATCH: Fix i8086 disassembler for 16bit displacements

H. J. Lu hjl@lucon.org
Mon Feb 5 19:15:00 GMT 2007


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);



More information about the Binutils mailing list