|
From: | Sean Watkinson |
Subject: | Possible bug in binutils: objdump |
Date: | Tue, 12 Mar 2002 18:43:49 +0000 |
objdump -D -m i8086 -b binary stripped.exeone line in the resulting code reads:
1878c: e8 87 f5 call 0x7d16which should read:
1878c: e8 87 f5 call 0x17d16[Notice the missing "1" prefix to the address]
I've tracked down the problem to the file i386-dis.c in the binutils/opcodes source directory. The function OP_J() reads:
static voidI've checked on the binutils CVS site and the code is still the same on Revision: 1.34.2.1 - branch: binutils-2_12.
OP_J (bytemode, sizeflag)
int bytemode;
int sizeflag;
{
bfd_vma disp;
bfd_vma mask = -1;switch (bytemode)
{
case b_mode:
FETCH_DATA (the_info, codep + 1);
disp = *codep++;
if ((disp & 0x80) != 0)
disp -= 0x100;
break;
case v_mode:
if (sizeflag & DFLAG)
disp = get32s ();
else
{
disp = get16 ();
/* For some reason, a data16 prefix on a jump instruction
means that the pc is masked to 16 bits after the
displacement is added! */
mask = 0xffff;
}
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
return;
}
disp = (start_pc + codep - start_codep + disp) & mask;
set_op (disp, 0);
print_operand_value (scratchbuf, 1, disp);
oappend (scratchbuf);
}
I believe that the comment (and subsequent code) beginning, /* For some reason ... */, is wrong. I don't believe there should be a 'mask' involved at all. A potential problem (which I presume the author was trying to solve) is that the get16() function returns a 16-bit displacement into a 32-bit integer value (at least 'int' is defined as 32-bits on my RedHat Linux 7.2 system). However, if the returned 16-bit displacement happens to be negative, it will become a positive value when stored in the 32-bit return value thereby giving a positive displacement ... obviously incorrect.
An alternative to the above listed function that I am currently using reads as follows:
static void
OP_J (bytemode, sizeflag)
int bytemode;[Notice the removal of the 'mask' and the sign extension of the 16-bit value to a 32-bit 'int' ... someone has already done this for the 8-bit jump address].
int sizeflag;
{
bfd_vma disp;switch (bytemode)
{
case b_mode:
FETCH_DATA (the_info, codep + 1);
disp = *codep++;
if ((disp & 0x80) != 0)
disp -= 0x100;
break;
case v_mode:
if (sizeflag & DFLAG)
disp = get32s ();
else
{
disp = get16 ();
if((disp & 0x8000) != 0)
disp -= 0x10000;
}
break;
default:
oappend (INTERNAL_DISASSEMBLER_ERROR);
return;
}
disp = start_pc + codep - start_codep + disp;
set_op (disp, 0);
print_operand_value (scratchbuf, 1, disp);
oappend (scratchbuf);
}
Hope this helps.
All the best,
Sean Watkinson
[Prev in Thread] | Current Thread | [Next in Thread] |