This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
[PATCH]: v850 pseudo-relocs can corrupt opcodes
- From: Nick Clifton <nickc at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: Tue, 17 May 2005 12:55:39 +0100
- Subject: [PATCH]: v850 pseudo-relocs can corrupt opcodes
Hi Guys,
A user recently reported a problem with the v850 toolchain whereby
the pseudo relocs (lo(), hi(), etc) can result in the generation of
corrupt instructions. The cause was the fact that when the pseudo
reloc was resolved to a value it was just plonked into the
instruction's binary without following the correct insertion
procedure for the corresponding operand.
I am therefore applying the patch below to fix this problem and to
add a test to the v850 testsuite to make sure that it does not
happen again.
Cheers
Nick
gas/ChangeLog
2005-05-17 Nick Clifton <nickc@redhat.com>
* config/tc-v850,h (TC_FIX_TYPE): Define.
(TC_INIT_FIX_TYPE): Define.
* config/tc-v850.c (md_assemble): When creating a fix record the
operand in the tc_fix_data field.
(md_apply_fix3): When applying a resolved fix use the operand's
insertion procedure to store the value, if the operand has been
recorded.
gas/testsuite/ChangeLog
2005-05-17 Nick Clifton <nickc@redhat.com>
* gas/v850/split-lo16.s: Add test for a lo() pseudo reloc
corrupting an ld.w instruction.
* gas/v850/split-lo16.d: Add expected, correct (ie not corrupt)
output.
Index: gas/config/tc-v850.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.c,v
retrieving revision 1.45
diff -c -3 -p -r1.45 tc-v850.c
*** gas/config/tc-v850.c 5 May 2005 09:13:04 -0000 1.45
--- gas/config/tc-v850.c 17 May 2005 11:48:05 -0000
*************** md_assemble (char *str)
*** 2125,2130 ****
--- 2125,2132 ----
reloc_howto->pc_relative,
reloc);
+ fixP->tc_fix_data = (void *) operand;
+
switch (reloc)
{
case BFD_RELOC_LO16:
*************** md_apply_fix3 (fixS *fixP, valueT *value
*** 2319,2334 ****
/* We still have to insert the value into memory! */
where = fixP->fx_frag->fr_literal + fixP->fx_where;
! if (fixP->fx_r_type == BFD_RELOC_V850_LO16_SPLIT_OFFSET)
! bfd_putl32 (((value << 16) & 0xfffe0000)
! | ((value << 5) & 0x20)
! | (bfd_getl32 (where) & ~0xfffe0020), where);
! else if (fixP->fx_size == 1)
! *where = value & 0xff;
! else if (fixP->fx_size == 2)
! bfd_putl16 (value & 0xffff, (unsigned char *) where);
! else if (fixP->fx_size == 4)
! bfd_putl32 (value, (unsigned char *) where);
}
}
--- 2321,2362 ----
/* We still have to insert the value into memory! */
where = fixP->fx_frag->fr_literal + fixP->fx_where;
! if (fixP->tc_fix_data != NULL)
! {
! struct v850_operand * operand = (struct v850_operand *) fixP->tc_fix_data;
! unsigned long insn;
!
! /* The variable "where" currently points at the exact point inside
! the insn where we need to insert the value. But we need to
! extract the entire insn so we probably need to move "where"
! back a few bytes. */
! if (fixP->fx_size == 2)
! where -= 2;
! else if (fixP->fx_size == 1)
! where -= 3;
!
! insn = bfd_getl32 ((unsigned char *) where);
!
! /* Use the operand's insertion procedure, if present, in order to
! make sure that the value is correctly stored in the insn. */
! insn = v850_insert_operand (insn, operand, (offsetT) value,
! fixP->fx_file, fixP->fx_line, NULL);
!
! bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
! }
! else
! {
! if (fixP->fx_r_type == BFD_RELOC_V850_LO16_SPLIT_OFFSET)
! bfd_putl32 (((value << 16) & 0xfffe0000)
! | ((value << 5) & 0x20)
! | (bfd_getl32 (where) & ~0xfffe0020), where);
! else if (fixP->fx_size == 1)
! *where = value & 0xff;
! else if (fixP->fx_size == 2)
! bfd_putl16 (value & 0xffff, (unsigned char *) where);
! else if (fixP->fx_size == 4)
! bfd_putl32 (value, (unsigned char *) where);
! }
}
}
Index: gas/config/tc-v850.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.h,v
retrieving revision 1.18
diff -c -3 -p -r1.18 tc-v850.h
*** gas/config/tc-v850.h 5 May 2005 09:13:04 -0000 1.18
--- gas/config/tc-v850.h 17 May 2005 11:48:05 -0000
*************** extern void v850_handle_align (fragS *);
*** 78,80 ****
--- 78,85 ----
extern long v850_pcrel_from_section (struct fix *, asection *);
#define DWARF2_LINE_MIN_INSN_LENGTH 2
+
+ /* We need to record the operand involved when a pseudo-reloc is
+ processed so that the resulting value can be inserted correctly. */
+ #define TC_FIX_TYPE void *
+ #define TC_INIT_FIX_DATA(fixP) (fixP)->tc_fix_data = NULL
Index: gas/testsuite/gas/v850/split-lo16.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/v850/split-lo16.d,v
retrieving revision 1.1
diff -c -3 -p -r1.1 split-lo16.d
*** gas/testsuite/gas/v850/split-lo16.d 16 Dec 2004 16:56:04 -0000 1.1
--- gas/testsuite/gas/v850/split-lo16.d 17 May 2005 11:49:37 -0000
***************
*** 13,16 ****
--- 13,18 ----
c: R_V850_LO16_SPLIT_OFFSET foo
10: a1 17 45 23 ld\.bu 9029\[r1\],r2
14: 81 17 57 34 ld\.bu 13398\[r1\],r2
+ 18: 20 57 01 00 ld.w 0\[r0\],r10
+ 1c: 20 57 79 56 ld.w 22136\[r0\],r10
#pass
Index: gas/testsuite/gas/v850/split-lo16.s
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/v850/split-lo16.s,v
retrieving revision 1.1
diff -c -3 -p -r1.1 split-lo16.s
*** gas/testsuite/gas/v850/split-lo16.s 16 Dec 2004 16:56:04 -0000 1.1
--- gas/testsuite/gas/v850/split-lo16.s 17 May 2005 11:49:37 -0000
***************
*** 5,7 ****
--- 5,11 ----
ld.bu lo(0x12345),r1,r2
ld.bu lo(0x123456),r1,r2
+
+ ld.w lo(0)[r0], r10
+ ld.w lo(0x12345678)[r0], r10
+