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]

[committed] Fix handling of lo16() in v850e ld.bu instructions


The lo16() in the following v850e instruction:

        ld.bu   lo(foo)[rn],rm

produces an R_V850_LO16 relocation.  That doesn't work because the
ld.bu offset is split into two separate fields, one for the high 15
bits and one for the low bit.

This patch adds a new relocation, R_V850_LO16_SPLIT_OFFSET, which works
in a similar way to the existing R_V850_[STZ]DA_16_16_SPLIT_OFFSET relocs.
Tested against the v850-elf testsuite (binutils & gcc).  Approved off-line
by Nick and applied.

Richard


include/elf/
	* v850.h (R_V850_LO16_SPLIT_OFFSET): New reloc.

bfd/
	* reloc.c (BFD_RELOC_V850_LO16_SPLIT_OFFSET): New bfd_reloc_code_type.
	* elf32-v850.c (v850_elf_howto_table): Add entry for
	R_V850_LO16_SPLIT_OFFSET.
	(v850_elf_reloc_map): Map it to BFD_RELOC_V850_LO16_SPLIT_OFFSET.
	(v850_elf_perform_lo16_relocation): New function, extracted from...
	(v850_elf_perform_relocation): ...here.  Use it to handle
	R_V850_LO16_SPLIT_OFFSET.
	(v850_elf_check_relocs, v850_elf_final_link_relocate): Handle
	R_V850_LO16_SPLIT_OFFSET.
	* libbfd.h, bfd-in2.h: Regenerate.

gas/
	* config/tc-v850.c (handle_lo16): New function.
	(v850_reloc_prefix): Use it to check lo().
	(md_assemble, md_apply_fix3): Handle BFD_RELOC_V850_LO16_SPLIT_OFFSET.
	
gas/testsuite/
	* gas/v850/split-lo16.{s,d}: New test.
	* gas/v850/v850.exp: Run it.

ld/testsuite/
	* ld-v850: New directory.

Index: include/elf/v850.h
===================================================================
RCS file: /cvs/src/src/include/elf/v850.h,v
retrieving revision 1.9
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.9 v850.h
*** include/elf/v850.h	4 Sep 2003 11:04:37 -0000	1.9
--- include/elf/v850.h	16 Dec 2004 16:25:27 -0000
*************** START_RELOC_NUMBERS (v850_reloc_type)
*** 79,84 ****
--- 79,85 ----
       RELOC_NUMBER (R_V850_LONGJUMP, 26)
       RELOC_NUMBER (R_V850_ALIGN, 27)
       RELOC_NUMBER (R_V850_REL32, 28)
+      RELOC_NUMBER (R_V850_LO16_SPLIT_OFFSET, 29)	/* For ld.bu */
  END_RELOC_NUMBERS (R_V850_max)
  
  
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.117
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.117 reloc.c
*** bfd/reloc.c	4 Nov 2004 14:57:44 -0000	1.117
--- bfd/reloc.c	16 Dec 2004 16:25:28 -0000
*************** ENUM
*** 3099,3104 ****
--- 3099,3109 ----
  ENUMDOC
    Used to maintain alignment whilst relaxing.
  ENUM
+   BFD_RELOC_V850_LO16_SPLIT_OFFSET
+ ENUMDOC
+   This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu
+   instructions.
+ ENUM
    BFD_RELOC_MN10300_32_PCREL
  ENUMDOC
    This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
Index: bfd/elf32-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-v850.c,v
retrieving revision 1.47
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.47 elf32-v850.c
*** bfd/elf32-v850.c	21 Oct 2004 15:28:25 -0000	1.47
--- bfd/elf32-v850.c	16 Dec 2004 16:25:29 -0000
*************** static reloc_howto_type v850_elf_howto_t
*** 533,538 ****
--- 533,553 ----
  	 0xffffffff,			/* src_mask */
  	 0xffffffff,			/* dst_mask */
  	 FALSE),			/* pcrel_offset */
+ 
+   /* An ld.bu version of R_V850_LO16.  */
+   HOWTO (R_V850_LO16_SPLIT_OFFSET,	/* type */
+ 	 0,				/* rightshift */
+ 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
+ 	 16,				/* bitsize */
+ 	 FALSE,				/* pc_relative */
+ 	 0,				/* bitpos */
+ 	 complain_overflow_dont,	/* complain_on_overflow */
+ 	 v850_elf_reloc,		/* special_function */
+ 	 "R_V850_LO16_SPLIT_OFFSET",	/* name */
+ 	 FALSE,				/* partial_inplace */
+ 	 0xfffe0020,			/* src_mask */
+ 	 0xfffe0020,			/* dst_mask */
+ 	 FALSE),			/* pcrel_offset */
  };
  
  /* Map BFD reloc types to V850 ELF reloc types.  */
*************** static const struct v850_elf_reloc_map v
*** 567,572 ****
--- 582,588 ----
    { BFD_RELOC_V850_TDA_16_16_OFFSET,       R_V850_TDA_16_16_OFFSET       },
    { BFD_RELOC_V850_TDA_4_5_OFFSET,         R_V850_TDA_4_5_OFFSET         },
    { BFD_RELOC_V850_TDA_4_4_OFFSET,         R_V850_TDA_4_4_OFFSET         },
+   { BFD_RELOC_V850_LO16_SPLIT_OFFSET,      R_V850_LO16_SPLIT_OFFSET      },
    { BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET },
    { BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET },
    { BFD_RELOC_V850_CALLT_6_7_OFFSET,       R_V850_CALLT_6_7_OFFSET       },
*************** v850_elf_check_relocs (abfd, info, sec, 
*** 687,692 ****
--- 703,709 ----
  	case R_V850_HI16_S:
  	case R_V850_HI16:
  	case R_V850_LO16:
+ 	case R_V850_LO16_SPLIT_OFFSET:
  	case R_V850_ABS32:
  	case R_V850_REL32:
  	case R_V850_16:
*************** find_remembered_hi16s_reloc (addend, alr
*** 902,907 ****
--- 919,1103 ----
    return addr;
  }
  
+ /* Calculate the sum of the value stored in the instruction and the
+    addend and check for overflow from the low 16 bits into the high
+    16 bits.  The assembler has already done some of this:  If the
+    value stored in the instruction has its 15th bit set, (counting
+    from zero) then the assembler will have added 1 to the value
+    stored in the associated HI16S reloc.  So for example, these
+    relocations:
+ 
+        movhi hi( fred ), r0, r1
+        movea lo( fred ), r1, r1
+ 
+    will store 0 in the value fields for the MOVHI and MOVEA instructions
+    and addend will be the address of fred, but for these instructions:
+ 
+        movhi hi( fred + 0x123456), r0, r1
+        movea lo( fred + 0x123456), r1, r1
+ 
+    the value stored in the MOVHI instruction will be 0x12 and the value
+    stored in the MOVEA instruction will be 0x3456.  If however the
+    instructions were:
+ 
+        movhi hi( fred + 0x10ffff), r0, r1
+        movea lo( fred + 0x10ffff), r1, r1
+ 
+    then the value stored in the MOVHI instruction would be 0x11 (not
+    0x10) and the value stored in the MOVEA instruction would be 0xffff.
+    Thus (assuming for the moment that the addend is 0), at run time the
+    MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
+    adds 0xffffffff (sign extension!) producing 0x10ffff.  Similarly if
+    the instructions were:
+ 
+        movhi hi( fred - 1), r0, r1
+        movea lo( fred - 1), r1, r1
+ 
+    then 0 is stored in the MOVHI instruction and -1 is stored in the
+    MOVEA instruction.
+ 
+    Overflow can occur if the addition of the value stored in the
+    instruction plus the addend sets the 15th bit when before it was clear.
+    This is because the 15th bit will be sign extended into the high part,
+    thus reducing its value by one, but since the 15th bit was originally
+    clear, the assembler will not have added 1 to the previous HI16S reloc
+    to compensate for this effect.  For example:
+ 
+       movhi hi( fred + 0x123456), r0, r1
+       movea lo( fred + 0x123456), r1, r1
+ 
+    The value stored in HI16S reloc is 0x12, the value stored in the LO16
+    reloc is 0x3456.  If we assume that the address of fred is 0x00007000
+    then the relocations become:
+ 
+      HI16S: 0x0012 + (0x00007000 >> 16)    = 0x12
+      LO16:  0x3456 + (0x00007000 & 0xffff) = 0xa456
+ 
+    but when the instructions are executed, the MOVEA instruction's value
+    is signed extended, so the sum becomes:
+ 
+ 	0x00120000
+       + 0xffffa456
+       ------------
+ 	0x0011a456    but 'fred + 0x123456' = 0x0012a456
+ 
+    Note that if the 15th bit was set in the value stored in the LO16
+    reloc, then we do not have to do anything:
+ 
+       movhi hi( fred + 0x10ffff), r0, r1
+       movea lo( fred + 0x10ffff), r1, r1
+ 
+       HI16S:  0x0011 + (0x00007000 >> 16)    = 0x11
+       LO16:   0xffff + (0x00007000 & 0xffff) = 0x6fff
+ 
+ 	0x00110000
+       + 0x00006fff
+       ------------
+ 	0x00116fff  = fred + 0x10ffff = 0x7000 + 0x10ffff
+ 
+    Overflow can also occur if the computation carries into the 16th bit
+    and it also results in the 15th bit having the same value as the 15th
+    bit of the original value.   What happens is that the HI16S reloc
+    will have already examined the 15th bit of the original value and
+    added 1 to the high part if the bit is set.  This compensates for the
+    sign extension of 15th bit of the result of the computation.  But now
+    there is a carry into the 16th bit, and this has not been allowed for.
+ 
+    So, for example if fred is at address 0xf000:
+ 
+      movhi hi( fred + 0xffff), r0, r1    [bit 15 of the offset is set]
+      movea lo( fred + 0xffff), r1, r1
+ 
+      HI16S: 0x0001 + (0x0000f000 >> 16)    = 0x0001
+      LO16:  0xffff + (0x0000f000 & 0xffff) = 0xefff   (carry into bit 16 is lost)
+ 
+        0x00010000
+      + 0xffffefff
+      ------------
+        0x0000efff   but 'fred + 0xffff' = 0x0001efff
+ 
+    Similarly, if the 15th bit remains clear, but overflow occurs into
+    the 16th bit then (assuming the address of fred is 0xf000):
+ 
+      movhi hi( fred + 0x7000), r0, r1    [bit 15 of the offset is clear]
+      movea lo( fred + 0x7000), r1, r1
+ 
+      HI16S: 0x0000 + (0x0000f000 >> 16)    = 0x0000
+      LO16:  0x7000 + (0x0000f000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
+ 
+        0x00000000
+      + 0x00006fff
+      ------------
+        0x00006fff   but 'fred + 0x7000' = 0x00016fff
+ 
+    Note - there is no need to change anything if a carry occurs, and the
+    15th bit changes its value from being set to being clear, as the HI16S
+    reloc will have already added in 1 to the high part for us:
+ 
+      movhi hi( fred + 0xffff), r0, r1     [bit 15 of the offset is set]
+      movea lo( fred + 0xffff), r1, r1
+ 
+      HI16S: 0x0001 + (0x00007000 >> 16)
+      LO16:  0xffff + (0x00007000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
+ 
+        0x00010000
+      + 0x00006fff   (bit 15 not set, so the top half is zero)
+      ------------
+        0x00016fff   which is right (assuming that fred is at 0x7000)
+ 
+    but if the 15th bit goes from being clear to being set, then we must
+    once again handle overflow:
+ 
+      movhi hi( fred + 0x7000), r0, r1     [bit 15 of the offset is clear]
+      movea lo( fred + 0x7000), r1, r1
+ 
+      HI16S: 0x0000 + (0x0000ffff >> 16)
+      LO16:  0x7000 + (0x0000ffff & 0xffff) = 0x6fff  (carry into bit 16)
+ 
+        0x00000000
+      + 0x00006fff   (bit 15 not set, so the top half is zero)
+      ------------
+        0x00006fff   which is wrong (assuming that fred is at 0xffff).  */
+ 
+ static bfd_boolean
+ v850_elf_perform_lo16_relocation (bfd *abfd, unsigned long *insn,
+ 				  unsigned long addend)
+ {
+ #define BIT15_SET(x) ((x) & 0x8000)
+ #define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
+   if ((BIT15_SET (*insn + addend) && ! BIT15_SET (addend))
+       || (OVERFLOWS (addend, *insn)
+ 	  && ((! BIT15_SET (*insn)) || (BIT15_SET (addend)))))
+     {
+       bfd_boolean already_updated;
+       bfd_byte *hi16s_address = find_remembered_hi16s_reloc
+ 	(addend, & already_updated);
+ 
+       /* Amend the matching HI16_S relocation.  */
+       if (hi16s_address != NULL)
+ 	{
+ 	  if (! already_updated)
+ 	    {
+ 	      unsigned long hi_insn = bfd_get_16 (abfd, hi16s_address);
+ 	      hi_insn += 1;
+ 	      bfd_put_16 (abfd, hi_insn, hi16s_address);
+ 	    }
+ 	}
+       else
+ 	{
+ 	  fprintf (stderr, _("FAILED to find previous HI16 reloc\n"));
+ 	  return FALSE;
+ 	}
+     }
+ #undef OVERFLOWS
+ #undef BIT15_SET
+ 
+   /* Do not complain if value has top bit set, as this has been
+      anticipated.  */
+   *insn = (*insn + addend) & 0xffff;
+   return TRUE;
+ }
+ 
  /* FIXME:  The code here probably ought to be removed and the code in reloc.c
     allowed to do its stuff instead.  At least for most of the relocs, anyway.  */
  
*************** v850_elf_perform_relocation (abfd, r_typ
*** 913,918 ****
--- 1109,1115 ----
       bfd_byte *address;
  {
    unsigned long insn;
+   unsigned long result;
    bfd_signed_vma saddend = (bfd_signed_vma) addend;
  
    switch (r_type)
*************** v850_elf_perform_relocation (abfd, r_typ
*** 972,1154 ****
        break;
  
      case R_V850_LO16:
!       /* Calculate the sum of the value stored in the instruction and the
! 	 addend and check for overflow from the low 16 bits into the high
! 	 16 bits.  The assembler has already done some of this:  If the
! 	 value stored in the instruction has its 15th bit set, (counting
! 	 from zero) then the assembler will have added 1 to the value
! 	 stored in the associated HI16S reloc.  So for example, these
! 	 relocations:
! 
! 	     movhi hi( fred ), r0, r1
! 	     movea lo( fred ), r1, r1
! 
! 	 will store 0 in the value fields for the MOVHI and MOVEA instructions
! 	 and addend will be the address of fred, but for these instructions:
! 
! 	     movhi hi( fred + 0x123456), r0, r1
! 	     movea lo( fred + 0x123456), r1, r1
! 
! 	 the value stored in the MOVHI instruction will be 0x12 and the value
! 	 stored in the MOVEA instruction will be 0x3456.  If however the
! 	 instructions were:
! 
! 	     movhi hi( fred + 0x10ffff), r0, r1
! 	     movea lo( fred + 0x10ffff), r1, r1
! 
! 	 then the value stored in the MOVHI instruction would be 0x11 (not
! 	 0x10) and the value stored in the MOVEA instruction would be 0xffff.
! 	 Thus (assuming for the moment that the addend is 0), at run time the
! 	 MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
! 	 adds 0xffffffff (sign extension!) producing 0x10ffff.  Similarly if
! 	 the instructions were:
! 
! 	     movhi hi( fred - 1), r0, r1
! 	     movea lo( fred - 1), r1, r1
! 
! 	 then 0 is stored in the MOVHI instruction and -1 is stored in the
! 	 MOVEA instruction.
! 
! 	 Overflow can occur if the addition of the value stored in the
! 	 instruction plus the addend sets the 15th bit when before it was clear.
! 	 This is because the 15th bit will be sign extended into the high part,
! 	 thus reducing its value by one, but since the 15th bit was originally
! 	 clear, the assembler will not have added 1 to the previous HI16S reloc
! 	 to compensate for this effect.  For example:
! 
! 	    movhi hi( fred + 0x123456), r0, r1
! 	    movea lo( fred + 0x123456), r1, r1
! 
! 	 The value stored in HI16S reloc is 0x12, the value stored in the LO16
! 	 reloc is 0x3456.  If we assume that the address of fred is 0x00007000
! 	 then the relocations become:
! 
! 	   HI16S: 0x0012 + (0x00007000 >> 16)    = 0x12
! 	   LO16:  0x3456 + (0x00007000 & 0xffff) = 0xa456
! 
! 	 but when the instructions are executed, the MOVEA instruction's value
! 	 is signed extended, so the sum becomes:
! 
! 	      0x00120000
! 	    + 0xffffa456
! 	    ------------
! 	      0x0011a456    but 'fred + 0x123456' = 0x0012a456
! 
! 	 Note that if the 15th bit was set in the value stored in the LO16
! 	 reloc, then we do not have to do anything:
! 
! 	    movhi hi( fred + 0x10ffff), r0, r1
! 	    movea lo( fred + 0x10ffff), r1, r1
! 
! 	    HI16S:  0x0011 + (0x00007000 >> 16)    = 0x11
! 	    LO16:   0xffff + (0x00007000 & 0xffff) = 0x6fff
! 
! 	      0x00110000
! 	    + 0x00006fff
! 	    ------------
! 	      0x00116fff  = fred + 0x10ffff = 0x7000 + 0x10ffff
! 
! 	 Overflow can also occur if the computation carries into the 16th bit
! 	 and it also results in the 15th bit having the same value as the 15th
! 	 bit of the original value.   What happens is that the HI16S reloc
! 	 will have already examined the 15th bit of the original value and
! 	 added 1 to the high part if the bit is set.  This compensates for the
! 	 sign extension of 15th bit of the result of the computation.  But now
! 	 there is a carry into the 16th bit, and this has not been allowed for.
! 
! 	 So, for example if fred is at address 0xf000:
! 
! 	   movhi hi( fred + 0xffff), r0, r1    [bit 15 of the offset is set]
! 	   movea lo( fred + 0xffff), r1, r1
! 
! 	   HI16S: 0x0001 + (0x0000f000 >> 16)    = 0x0001
! 	   LO16:  0xffff + (0x0000f000 & 0xffff) = 0xefff   (carry into bit 16 is lost)
! 
! 	     0x00010000
! 	   + 0xffffefff
! 	   ------------
! 	     0x0000efff   but 'fred + 0xffff' = 0x0001efff
! 
! 	 Similarly, if the 15th bit remains clear, but overflow occurs into
! 	 the 16th bit then (assuming the address of fred is 0xf000):
! 
! 	   movhi hi( fred + 0x7000), r0, r1    [bit 15 of the offset is clear]
! 	   movea lo( fred + 0x7000), r1, r1
! 
! 	   HI16S: 0x0000 + (0x0000f000 >> 16)    = 0x0000
! 	   LO16:  0x7000 + (0x0000f000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
! 
! 	     0x00000000
! 	   + 0x00006fff
! 	   ------------
! 	     0x00006fff   but 'fred + 0x7000' = 0x00016fff
! 
! 	 Note - there is no need to change anything if a carry occurs, and the
! 	 15th bit changes its value from being set to being clear, as the HI16S
! 	 reloc will have already added in 1 to the high part for us:
! 
! 	   movhi hi( fred + 0xffff), r0, r1     [bit 15 of the offset is set]
! 	   movea lo( fred + 0xffff), r1, r1
! 
! 	   HI16S: 0x0001 + (0x00007000 >> 16)
! 	   LO16:  0xffff + (0x00007000 & 0xffff) = 0x6fff  (carry into bit 16 is lost)
! 
! 	     0x00010000
! 	   + 0x00006fff   (bit 15 not set, so the top half is zero)
! 	   ------------
! 	     0x00016fff   which is right (assuming that fred is at 0x7000)
! 
! 	 but if the 15th bit goes from being clear to being set, then we must
! 	 once again handle overflow:
! 
! 	   movhi hi( fred + 0x7000), r0, r1     [bit 15 of the offset is clear]
! 	   movea lo( fred + 0x7000), r1, r1
! 
! 	   HI16S: 0x0000 + (0x0000ffff >> 16)
! 	   LO16:  0x7000 + (0x0000ffff & 0xffff) = 0x6fff  (carry into bit 16)
! 
! 	     0x00000000
! 	   + 0x00006fff   (bit 15 not set, so the top half is zero)
! 	   ------------
! 	     0x00006fff   which is wrong (assuming that fred is at 0xffff).  */
!       {
! 	long result;
! 
! 	insn   = bfd_get_16 (abfd, address);
! 	result = insn + addend;
! 
! #define BIT15_SET(x) ((x) & 0x8000)
! #define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
! 
! 	if ((BIT15_SET (result) && ! BIT15_SET (addend))
! 	    || (OVERFLOWS (addend, insn)
! 		&& ((! BIT15_SET (insn)) || (BIT15_SET (addend)))))
! 	  {
! 	    bfd_boolean already_updated;
! 	    bfd_byte *hi16s_address = find_remembered_hi16s_reloc
! 	      (addend, & already_updated);
! 
! 	    /* Amend the matching HI16_S relocation.  */
! 	    if (hi16s_address != NULL)
! 	      {
! 		if (! already_updated)
! 		  {
! 		    insn = bfd_get_16 (abfd, hi16s_address);
! 		    insn += 1;
! 		    bfd_put_16 (abfd, (bfd_vma) insn, hi16s_address);
! 		  }
! 	      }
! 	    else
! 	      {
! 		fprintf (stderr, _("FAILED to find previous HI16 reloc\n"));
! 		return bfd_reloc_overflow;
! 	      }
! 	  }
! 
! 	/* Do not complain if value has top bit set, as this has been anticipated.  */
! 	insn = result & 0xffff;
! 	break;
!       }
  
      case R_V850_8:
        addend += (char) bfd_get_8 (abfd, address);
--- 1169,1178 ----
        break;
  
      case R_V850_LO16:
!       insn = bfd_get_16 (abfd, address);
!       if (! v850_elf_perform_lo16_relocation (abfd, &insn, addend))
! 	return bfd_reloc_overflow;
!       break;
  
      case R_V850_8:
        addend += (char) bfd_get_8 (abfd, address);
*************** #define OVERFLOWS(a,i) ((((a) & 0xffff) 
*** 1278,1283 ****
--- 1302,1318 ----
        insn |= addend;
        break;
  
+     case R_V850_LO16_SPLIT_OFFSET:
+       insn = bfd_get_32 (abfd, address);
+       result = ((insn & 0xfffe0000) >> 16) | ((insn & 0x20) >> 5);
+       if (! v850_elf_perform_lo16_relocation (abfd, &result, addend))
+ 	return bfd_reloc_overflow;
+       insn = (((result << 16) & 0xfffe0000)
+ 	      | ((result << 5) & 0x20)
+ 	      | (insn & ~0xfffe0020));
+       bfd_put_32 (abfd, insn, address);
+       return bfd_reloc_ok;
+ 
      case R_V850_ZDA_16_16_SPLIT_OFFSET:
      case R_V850_SDA_16_16_SPLIT_OFFSET:
        insn = bfd_get_32 (abfd, address);
*************** v850_elf_final_link_relocate (howto, inp
*** 1492,1497 ****
--- 1527,1533 ----
      case R_V850_HI16_S:
      case R_V850_HI16:
      case R_V850_LO16:
+     case R_V850_LO16_SPLIT_OFFSET:
      case R_V850_16:
      case R_V850_ABS32:
      case R_V850_8:
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.130
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.130 libbfd.h
*** bfd/libbfd.h	4 Nov 2004 14:57:45 -0000	1.130
--- bfd/libbfd.h	16 Dec 2004 16:25:29 -0000
*************** static const char *const bfd_reloc_code_
*** 1299,1304 ****
--- 1299,1305 ----
    "BFD_RELOC_V850_LONGCALL",
    "BFD_RELOC_V850_LONGJUMP",
    "BFD_RELOC_V850_ALIGN",
+   "BFD_RELOC_V850_LO16_SPLIT_OFFSET",
    "BFD_RELOC_MN10300_32_PCREL",
    "BFD_RELOC_MN10300_16_PCREL",
    "BFD_RELOC_TIC30_LDP",
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.309
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.309 bfd-in2.h
*** bfd/bfd-in2.h	9 Dec 2004 06:08:45 -0000	1.309
--- bfd/bfd-in2.h	16 Dec 2004 16:25:30 -0000
*************** bits placed non-contiguously in the inst
*** 2967,2972 ****
--- 2967,2976 ----
  /* Used to maintain alignment whilst relaxing.  */
    BFD_RELOC_V850_ALIGN,
  
+ /* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu
+ instructions.  */
+   BFD_RELOC_V850_LO16_SPLIT_OFFSET,
+ 
  /* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
  instruction.  */
    BFD_RELOC_MN10300_32_PCREL,
Index: gas/config/tc-v850.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.c,v
retrieving revision 1.39
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.39 tc-v850.c
*** gas/config/tc-v850.c	17 Aug 2004 12:19:57 -0000	1.39
--- gas/config/tc-v850.c	16 Dec 2004 16:25:31 -0000
*************** md_begin ()
*** 1375,1380 ****
--- 1375,1399 ----
    bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine);
  }
  
+ static bfd_reloc_code_real_type
+ handle_lo16 (const struct v850_operand *operand)
+ {
+   if (operand != NULL)
+     {
+       if (operand->bits == -1)
+ 	return BFD_RELOC_V850_LO16_SPLIT_OFFSET;
+ 
+       if (!(operand->bits == 16 && operand->shift == 16)
+ 	  && !(operand->bits == 15 && operand->shift == 17))
+ 	{
+ 	  as_bad (_("lo() relocation used on an instruction which does "
+ 		    "not support it"));
+ 	  return BFD_RELOC_64;  /* Used to indicate an error condition.  */
+ 	}
+     }
+   return BFD_RELOC_LO16;
+ }
+ 
  static bfd_reloc_code_real_type handle_ctoff
    PARAMS ((const struct v850_operand *));
  
*************** #define CHECK_(name, reloc) 						\
*** 1516,1522 ****
  
    CHECK_ ("hi0",    BFD_RELOC_HI16	   );
    CHECK_ ("hi",	    BFD_RELOC_HI16_S	   );
!   CHECK_ ("lo",	    BFD_RELOC_LO16	   );
    CHECK_ ("sdaoff", handle_sdaoff (operand));
    CHECK_ ("zdaoff", handle_zdaoff (operand));
    CHECK_ ("tdaoff", handle_tdaoff (operand));
--- 1535,1541 ----
  
    CHECK_ ("hi0",    BFD_RELOC_HI16	   );
    CHECK_ ("hi",	    BFD_RELOC_HI16_S	   );
!   CHECK_ ("lo",	    handle_lo16 (operand)  );
    CHECK_ ("sdaoff", handle_sdaoff (operand));
    CHECK_ ("zdaoff", handle_zdaoff (operand));
    CHECK_ ("tdaoff", handle_tdaoff (operand));
*************** md_assemble (str)
*** 1755,1760 ****
--- 1774,1780 ----
  		      /* Fall through.  */
  
  		    case BFD_RELOC_LO16:
+ 		    case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
  		      {
  			/* Truncate, then sign extend the value.  */
  			ex.X_add_number = SEXT16 (ex.X_add_number);
*************** md_assemble (str)
*** 2199,2204 ****
--- 2219,2225 ----
  	  switch (reloc)
  	    {
  	    case BFD_RELOC_LO16:
+ 	    case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
  	    case BFD_RELOC_HI16:
  	    case BFD_RELOC_HI16_S:
  	      fixP->fx_no_overflow = 1;
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2405,2411 ****
        /* We still have to insert the value into memory!  */
        where = fixP->fx_frag->fr_literal + fixP->fx_where;
  
!       if (fixP->fx_size == 1)
  	*where = value & 0xff;
        else if (fixP->fx_size == 2)
  	bfd_putl16 (value & 0xffff, (unsigned char *) where);
--- 2426,2436 ----
        /* 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);
Index: gas/testsuite/gas/v850/basic.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/v850/basic.exp,v
retrieving revision 1.3
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.3 basic.exp
*** gas/testsuite/gas/v850/basic.exp	4 Sep 2003 11:04:36 -0000	1.3
--- gas/testsuite/gas/v850/basic.exp	16 Dec 2004 16:25:31 -0000
*************** if [istarget v850*-*-*] then {
*** 436,439 ****
--- 436,440 ----
  
      gas_test_error "range.s" "-mwarn-signed-overflow" "Check for range error on byte load/store"
      run_dump_test "v850e1"
+     run_dump_test "split-lo16"
  }
diff -c /dev/null gas/testsuite/gas/v850/split-lo16.d
*** /dev/null	Fri Apr 23 00:21:55 2004
--- gas/testsuite/gas/v850/split-lo16.d	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,16 ----
+ #objdump: -dr
+ #name: V850E split LO16 tests
+ #as: -mv850e
+ #...
+ 00000000 <.*>:
+    0:	40 0e 00 00 	movhi	0, r0, r1
+ 			2: R_V850_HI16_S	foo
+    4:	01 16 00 00 	addi	0, r1, r2
+ 			6: R_V850_LO16	foo
+    8:	01 17 00 00 	ld\.b	0\[r1\],r2
+ 			a: R_V850_LO16	foo
+    c:	81 17 01 00 	ld\.bu	0\[r1\],r2
+ 			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
+ #pass
diff -c /dev/null gas/testsuite/gas/v850/split-lo16.s
*** /dev/null	Fri Apr 23 00:21:55 2004
--- gas/testsuite/gas/v850/split-lo16.s	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,7 ----
+ 	movhi	hi(foo),r0,r1
+ 	addi	lo(foo),r1,r2
+ 	ld.b	lo(foo),r1,r2
+ 	ld.bu	lo(foo),r1,r2
+ 
+ 	ld.bu	lo(0x12345),r1,r2
+ 	ld.bu	lo(0x123456),r1,r2
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.d
*** /dev/null	Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.d	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,26 ----
+ #source: split-lo16.s -mv850e
+ #ld: -Tsplit-lo16.ld
+ #objdump: -d
+ #...
+ 00010000 <.*>:
+    10000:	40 0e 34 12 	movhi	4660, r0, r1
+    10004:	01 16 78 56 	addi	22136, r1, r2
+    10008:	81 17 79 56 	ld\.bu	22136\[r1\],r2
+    1000c:	40 0e 36 12 	movhi	4662, r0, r1
+    10010:	01 16 78 d8 	addi	-10120, r1, r2
+    10014:	81 17 79 d8 	ld\.bu	-10120\[r1\],r2
+    10018:	40 0e 12 00 	movhi	18, r0, r1
+    1001c:	81 17 57 34 	ld\.bu	13398\[r1\],r2
+    10020:	01 16 56 34 	addi	13398, r1, r2
+    10024:	40 0e 14 00 	movhi	20, r0, r1
+    10028:	81 17 57 b6 	ld\.bu	-18858\[r1\],r2
+    1002c:	01 16 56 b6 	addi	-18858, r1, r2
+    10030:	40 0e 79 56 	movhi	22137, r0, r1
+    10034:	01 16 bc 9a 	addi	-25924, r1, r2
+    10038:	81 17 bd 9a 	ld\.bu	-25924\[r1\],r2
+    1003c:	40 0e 9b 78 	movhi	30875, r0, r1
+    10040:	81 17 df bc 	ld\.bu	-17186\[r1\],r2
+    10044:	01 16 de bc 	addi	-17186, r1, r2
+    10048:	40 0e 45 23 	movhi	9029, r0, r1
+    1004c:	a1 17 89 67 	ld\.bu	26505\[r1\],r2
+ #pass
diff -c /dev/null ld/testsuite/ld-v850/v850.exp
*** /dev/null	Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/v850.exp	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,3 ----
+ if [istarget v850*-*-*] {
+     run_dump_test "split-lo16"
+ }
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.s
*** /dev/null	Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.s	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,20 ----
+ 	movhi	hi(lo16_nocarry),r0,r1
+ 	addi	lo(lo16_nocarry),r1,r2
+ 	ld.bu	lo(lo16_nocarry)[r1],r2
+ 	movhi	hi(lo16_nocarry + 0x18200),r0,r1
+ 	addi	lo(lo16_nocarry + 0x18200),r1,r2
+ 	ld.bu	lo(lo16_nocarry + 0x18200)[r1],r2
+ 	movhi	hi(split_lo16_nocarry),r0,r1
+ 	ld.bu	lo(split_lo16_nocarry)[r1],r2
+ 	addi	lo(split_lo16_nocarry),r1,r2
+ 	movhi	hi(split_lo16_nocarry + 0x18200),r0,r1
+ 	ld.bu	lo(split_lo16_nocarry + 0x18200)[r1],r2
+ 	addi	lo(split_lo16_nocarry + 0x18200),r1,r2
+ 	movhi	hi(lo16_carry),r0,r1
+ 	addi	lo(lo16_carry),r1,r2
+ 	ld.bu	lo(lo16_carry)[r1],r2
+ 	movhi	hi(split_lo16_carry),r0,r1
+ 	ld.bu	lo(split_lo16_carry)[r1],r2
+ 	addi	lo(split_lo16_carry),r1,r2
+ 	movhi	hi(odd),r0,r1
+ 	ld.bu	lo(odd)[r1],r2
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.ld
*** /dev/null	Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.ld	Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,11 ----
+ SECTIONS
+ {
+   lo16_carry = 0x56789abc;
+   lo16_nocarry = 0x12345678;
+   split_lo16_carry = 0x789abcde;
+   split_lo16_nocarry = 0x00123456;
+   odd = 0x23456789;
+   . = 0x10000;
+   .text : { *(.text); }
+   /DISCARD/ : { *(*); }
+ }


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