This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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
+ 

  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]