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, xcoff relocate section rewrite.


This is a reworking of an earlier patch.
http://sources.redhat.com/ml/binutils/2001-08/msg00060.html

This patch replaces r_type case statement withing
xcoff*_ppc_relocate_section with a function table.

Tom



--
Tom Rix
GCC Engineer
trix@redhat.com


2002-04-27  Tom Rix  <trix@redhat.com>

	* coff-rs6000.c (xcoff_calculate_relocation) : Function table for
	calulating relocations. 
	(xcoff_complain_overflow) : Function table for relocation errors.
	(xcoff_ppc_relocate_section): Use relocation and complain function 
	tables. 
	(xcoff_complain_overflow_unsigned_func): New complain function. 
	(xcoff_complain_overflow_signed_func): Same.
	(xcoff_complain_overflow_bitfield_func): Same.
	(xcoff_complain_overflow_dont_func): Same.
	(xcoff_reloc_type_crel): New recot function.
	(xcoff_reloc_type_br): Same.
	(xcoff_reloc_type_ba): Same.
	(xcoff_reloc_type_toc): Same.
	(xcoff_reloc_type_rel): Same.
	(xcoff_reloc_type_neg): Same.
	(xcoff_reloc_type_pos): Same.
	(xcoff_reloc_type_fail): Same.
	(xcoff_reloc_type_noop): Same.
	* libxcoff.h : Declare common parts for xcoff64.
	* coff64-rs6000.c (xcoff64_ppc_relocate_section): Use relocation
	and complain function tables. 

Index: bfd/coff-rs6000.c
===================================================================
RCS file: /cvs/src/src/bfd/coff-rs6000.c,v
retrieving revision 1.36
diff -d -u -p -r1.36 coff-rs6000.c
--- bfd/coff-rs6000.c	4 Apr 2002 19:53:35 -0000	1.36
+++ bfd/coff-rs6000.c	28 Apr 2002 03:24:51 -0000
@@ -149,6 +149,68 @@ static boolean do_pad PARAMS((bfd *, uns
 static boolean do_copy PARAMS((bfd *, bfd *));
 static boolean do_shared_object_padding PARAMS ((bfd *, bfd *, ufile_ptr *, int));
 
+/* Relocation functions */
+static boolean xcoff_reloc_type_noop PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_fail PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_pos PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_neg PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_rel PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_toc PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_ba PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_br PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+static boolean xcoff_reloc_type_crel PARAMS ((XCOFF_RELOC_FUNCTION_ARGS));
+
+static boolean xcoff_complain_overflow_dont_func 
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_bitfield_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_signed_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+static boolean xcoff_complain_overflow_unsigned_func
+  PARAMS ((XCOFF_COMPLAIN_FUNCTION_ARGS));
+
+boolean (*xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION])
+     (XCOFF_RELOC_FUNCTION_ARGS) =
+{
+  xcoff_reloc_type_pos,  /* R_POS   (0x00) */
+  xcoff_reloc_type_neg,  /* R_NEG   (0x01) */
+  xcoff_reloc_type_rel,  /* R_REL   (0x02) */
+  xcoff_reloc_type_toc,  /* R_TOC   (0x03) */
+  xcoff_reloc_type_fail, /* R_RTB   (0x04) */
+  xcoff_reloc_type_toc,  /* R_GL    (0x05) */
+  xcoff_reloc_type_toc,  /* R_TCL   (0x06) */
+  xcoff_reloc_type_fail, /*         (0x07) */
+  xcoff_reloc_type_ba,   /* R_BA    (0x08) */
+  xcoff_reloc_type_fail, /*         (0x09) */
+  xcoff_reloc_type_br,   /* R_BR    (0x0a) */
+  xcoff_reloc_type_fail, /*         (0x0b) */
+  xcoff_reloc_type_pos,  /* R_RL    (0x0c) */
+  xcoff_reloc_type_pos,  /* R_RLA   (0x0d) */
+  xcoff_reloc_type_fail, /*         (0x0e) */
+  xcoff_reloc_type_noop, /* R_REF   (0x0f) */
+  xcoff_reloc_type_fail, /*         (0x10) */
+  xcoff_reloc_type_fail, /*         (0x11) */
+  xcoff_reloc_type_toc,  /* R_TRL   (0x12) */
+  xcoff_reloc_type_toc,  /* R_TRLA  (0x13) */
+  xcoff_reloc_type_fail, /* R_RRTBI (0x14) */
+  xcoff_reloc_type_fail, /* R_RRTBA (0x15) */
+  xcoff_reloc_type_ba,   /* R_CAI   (0x16) */
+  xcoff_reloc_type_crel, /* R_CREL  (0x17) */
+  xcoff_reloc_type_ba,   /* R_RBA   (0x18) */
+  xcoff_reloc_type_ba,   /* R_RBAC  (0x19) */
+  xcoff_reloc_type_br,   /* R_RBR   (0x1a) */
+  xcoff_reloc_type_ba,   /* R_RBRC  (0x1b) */
+};
+
+boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW])
+     (XCOFF_COMPLAIN_FUNCTION_ARGS) = 
+{
+  xcoff_complain_overflow_dont_func,
+  xcoff_complain_overflow_bitfield_func,
+  xcoff_complain_overflow_signed_func,
+  xcoff_complain_overflow_unsigned_func,
+};
+
 /* We use our own tdata type.  Its first field is the COFF tdata type,
    so the COFF routines are compatible.  */
 
@@ -2621,12 +2683,575 @@ xcoff_swap_ldrel_out (abfd, src, d)
 }
 
 
+static boolean 
+xcoff_reloc_type_noop (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		       val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation ATTRIBUTE_UNUSED;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_fail (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		       val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation ATTRIBUTE_UNUSED;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  (*_bfd_error_handler)
+    (_("%s: unsupported relocation type 0x%02x"),
+     bfd_get_filename (input_bfd), (unsigned int) rel->r_type);
+  bfd_set_error (bfd_error_bad_value);
+  return false;
+}
+
+static boolean 
+xcoff_reloc_type_pos (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		      val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  *relocation = val + addend;
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_neg (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		      val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  *relocation = addend - val;
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_rel (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		      val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->pc_relative = true;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+		  input_section->output_offset);
+  return true;
+}
+static boolean 
+xcoff_reloc_type_toc (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		      val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd;
+     struct internal_reloc *rel;
+     struct internal_syment *sym;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+     bfd_vma val;
+     bfd_vma addend ATTRIBUTE_UNUSED;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  struct xcoff_link_hash_entry *h;
+
+  if (0 > rel->r_symndx) 
+    return false;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+
+  if (h != NULL && h->smclas != XMC_TD)
+    {
+      if (h->toc_section == NULL)
+	{
+	  (*_bfd_error_handler)
+	    (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
+	     bfd_get_filename (input_bfd), rel->r_vaddr,
+	     h->root.root.string);
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+      
+      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
+      val = (h->toc_section->output_section->vma
+	      + h->toc_section->output_offset);
+    }
+  
+  *relocation = ((val - xcoff_data (output_bfd)->toc) - 
+		 (sym->n_value - xcoff_data (input_bfd)->toc));
+  return true;
+}
+static boolean 
+xcoff_reloc_type_ba (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		     val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  *relocation = val + addend;
+
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_br (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		     val, addend, relocation, contents)
+     bfd *input_bfd;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents;
+{
+  struct xcoff_link_hash_entry *h;
+
+  if (0 > rel->r_symndx) 
+    return false;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+
+  /* If we see an R_BR or R_RBR reloc which is jumping to global
+     linkage code, and it is followed by an appropriate cror nop
+     instruction, we replace the cror with lwz r2,20(r1).  This
+     restores the TOC after the glink code.  Contrariwise, if the
+     call is followed by a lwz r2,20(r1), but the call is not
+     going to global linkage code, we can replace the load with a
+     cror.  */
+  if (NULL != h 
+      && bfd_link_hash_defined == h->root.type 
+      && (rel->r_vaddr - input_section->vma + 8 <= 
+	  input_section->_cooked_size)) 
+    {
+      bfd_byte *pnext;
+      unsigned long next;
+      
+      pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
+      next = bfd_get_32 (input_bfd, pnext);
+      
+      /* The _ptrgl function is magic.  It is used by the AIX
+	 compiler to call a function through a pointer.  */
+      if (h->smclas == XMC_GL || strcmp (h->root.root.string, "._ptrgl") == 0)
+	{
+	  if (next == 0x4def7b82                        /* cror 15,15,15 */
+	      || next == 0x4ffffb82                     /* cror 31,31,31 */
+	      || next == 0x60000000)	                /* ori r0,r0,0 */
+	    bfd_put_32 (input_bfd, 0x80410014, pnext);  /* lwz r1,20(r1) */
+	  
+	} else 
+	  {
+	    if (next == 0x80410014)		         /* lwz r1,20(r1) */
+	      bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */
+	  }
+    } 
+  else if (NULL != h && bfd_link_hash_undefined == h->root.type) 
+    {
+      /* Normally, this relocation is against a defined symbol.  In the
+	 case where this is a partial link and the output section offset
+	 is greater than 2^25, the linker will return an invalid error 
+	 message that the relocation has been truncated.  Yes it has been
+	 truncated but no it not important.  For this case, disable the 
+	 overflow checking. */
+      
+      howto->complain_on_overflow = complain_overflow_dont;
+    }
+  
+  howto->pc_relative = true;
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+  
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+		  input_section->output_offset);
+  return true;
+}
+
+static boolean 
+xcoff_reloc_type_crel (input_bfd, input_section, output_bfd, rel, sym, howto, 
+		       val, addend, relocation, contents)
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     asection *input_section;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
+     struct internal_reloc *rel ATTRIBUTE_UNUSED;
+     struct internal_syment *sym ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma addend;
+     bfd_vma *relocation;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
+{
+  howto->pc_relative = true;
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  /* A PC relative reloc includes the section address.  */
+  addend += input_section->vma;
+
+  *relocation = val + addend;
+  *relocation -= (input_section->output_section->vma + 
+		  input_section->output_offset);
+  return true;
+}
+
+static boolean 
+xcoff_complain_overflow_dont_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+     bfd_vma relocation ATTRIBUTE_UNUSED;
+     struct reloc_howto_struct *howto ATTRIBUTE_UNUSED;
+{
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_bitfield_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto; 
+{
+  bfd_vma addrmask, fieldmask, signmask, ss;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  /* Much like unsigned, except no trimming with addrmask.  In
+     addition, the sum overflows if there is a carry out of
+     the bfd_vma, i.e., the sum is less than either input
+     operand.  */
+  a >>= howto->rightshift;
+  b >>= howto->bitpos;
+  
+  /* Bitfields are sometimes used for signed numbers; for
+     example, a 13-bit field sometimes represents values in
+     0..8191 and sometimes represents values in -4096..4095.
+     If the field is signed and a is -4095 (0x1001) and b is
+     -1 (0x1fff), the sum is -4096 (0x1000), but (0x1001 +
+     0x1fff is 0x3000).  It's not clear how to handle this
+     everywhere, since there is not way to know how many bits
+     are significant in the relocation, but the original code
+     assumed that it was fully sign extended, and we will keep
+     that assumption.  */
+  signmask = (fieldmask >> 1) + 1;
+		  
+  if ((a & ~ fieldmask) != 0)
+    {
+      /* Some bits out of the field are set.  This might not
+	 be a problem: if this is a signed bitfield, it is OK
+	 iff all the high bits are set, including the sign
+	 bit.  We'll try setting all but the most significant
+	 bit in the original relocation value: if this is all
+	 ones, we are OK, assuming a signed bitfield.  */
+      ss = (signmask << howto->rightshift) - 1;
+      if ((ss | relocation) != ~ (bfd_vma) 0)
+	return true;
+      a &= fieldmask;
+    }
+  
+  /* We just assume (b & ~ fieldmask) == 0.  */
+  
+  /* We explicitly permit wrap around if this relocation
+     covers the high bit of an address.  The Linux kernel
+     relies on it, and it is the only way to write assembler
+     code which can run when loaded at a location 0x80000000
+     away from the location at which it is linked.  */
+  if (howto->bitsize + howto->rightshift
+      == bfd_arch_bits_per_address (input_bfd))
+    return false;
+  
+  sum = a + b;
+  if (sum < a || (sum & ~ fieldmask) != 0)
+    {
+      /* There was a carry out, or the field overflow.  Test
+	 for signed operands again.  Here is the overflow test
+	 is as for complain_overflow_signed.  */
+      if (((~ (a ^ b)) & (a ^ sum)) & signmask)
+	return true;
+    }
+  
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_signed_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto;
+{
+  bfd_vma addrmask, fieldmask, signmask, ss;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  a = (a & addrmask) >> howto->rightshift;
+  
+  /* If any sign bits are set, all sign bits must be set.
+     That is, A must be a valid negative address after
+     shifting.  */
+  signmask = ~ (fieldmask >> 1);
+  ss = a & signmask;
+  if (ss != 0 && ss != ((addrmask >> howto->rightshift) & signmask))
+    return true;
+  
+  /* We only need this next bit of code if the sign bit of B
+     is below the sign bit of A.  This would only happen if
+     SRC_MASK had fewer bits than BITSIZE.  Note that if
+     SRC_MASK has more bits than BITSIZE, we can get into
+     trouble; we would need to verify that B is in range, as
+     we do for A above.  */
+  signmask = ((~ howto->src_mask) >> 1) & howto->src_mask;
+  if ((b & signmask) != 0)
+    {
+      /* Set all the bits above the sign bit.  */
+      b -= signmask <<= 1;
+    }
+  
+  b = (b & addrmask) >> howto->bitpos;
+  
+  /* Now we can do the addition.  */
+  sum = a + b;
+  
+  /* See if the result has the correct sign.  Bits above the
+     sign bit are junk now; ignore them.  If the sum is
+     positive, make sure we did not have all negative inputs;
+     if the sum is negative, make sure we did not have all
+     positive inputs.  The test below looks only at the sign
+     bits, and it really just
+     SIGN (A) == SIGN (B) && SIGN (A) != SIGN (SUM)
+  */
+  signmask = (fieldmask >> 1) + 1;
+  if (((~ (a ^ b)) & (a ^ sum)) & signmask)
+    return true;
+  
+  return false;
+}
+
+static boolean 
+xcoff_complain_overflow_unsigned_func (input_bfd, val, relocation, howto) 
+     bfd *input_bfd;
+     bfd_vma val;
+     bfd_vma relocation;
+     struct reloc_howto_struct *howto; 
+{
+  bfd_vma addrmask, fieldmask;
+  bfd_vma a, b, sum;
+  
+  /* Get the values to be added together.  For signed and unsigned
+     relocations, we assume that all values should be truncated to
+     the size of an address.  For bitfields, all the bits matter.
+     See also bfd_check_overflow.  */
+  fieldmask = N_ONES (howto->bitsize);
+  addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask;
+  a = relocation;
+  b = val & howto->src_mask;
+
+  /* Checking for an unsigned overflow is relatively easy:
+     trim the addresses and add, and trim the result as well.
+     Overflow is normally indicated when the result does not
+     fit in the field.  However, we also need to consider the
+     case when, e.g., fieldmask is 0x7fffffff or smaller, an
+     input is 0x80000000, and bfd_vma is only 32 bits; then we
+     will get sum == 0, but there is an overflow, since the
+     inputs did not fit in the field.  Instead of doing a
+     separate test, we can check for this by or-ing in the
+     operands when testing for the sum overflowing its final
+     field.  */
+  a = (a & addrmask) >> howto->rightshift;
+  b = (b & addrmask) >> howto->bitpos;
+  sum = (a + b) & addrmask;
+  if ((a | b | sum) & ~ fieldmask)
+    return true;
+  
+  return false;
+}
 
 /* This is the relocation function for the RS/6000/POWER/PowerPC.
    This is currently the only processor which uses XCOFF; I hope that
-   will never change.  */
+   will never change.  
 
-static boolean
+   I took the relocation type definitions from two documents:
+   the PowerPC AIX Version 4 Application Binary Interface, First
+   Edition (April 1992), and the PowerOpen ABI, Big-Endian
+   32-Bit Hardware Implementation (June 30, 1994).  Differences
+   between the documents are noted below. 
+
+   Unsupported r_type's 
+
+   R_RTB:
+   R_RRTBI:
+   R_RRTBA:
+	
+   These relocs are defined by the PowerPC ABI to be
+   relative branches which use half of the difference
+   between the symbol and the program counter.  I can't
+   quite figure out when this is useful.  These relocs are
+   not defined by the PowerOpen ABI. 
+
+   Supported r_type's
+
+   R_POS:
+   Simple positive relocation.
+
+   R_NEG:
+   Simple negative relocation. 
+
+   R_REL:
+   Simple PC relative relocation.
+
+   R_TOC:
+   TOC relative relocation.  The value in the instruction in
+   the input file is the offset from the input file TOC to
+   the desired location.  We want the offset from the final
+   TOC to the desired location.  We have:
+   isym = iTOC + in
+   iinsn = in + o
+   osym = oTOC + on
+   oinsn = on + o
+   so we must change insn by on - in.
+
+   R_GL:
+   GL linkage relocation.  The value of this relocation
+   is the address of the entry in the TOC section. 
+
+   R_TCL:
+   Local object TOC address.  I can't figure out the
+   difference between this and case R_GL. 
+
+   R_TRL:
+   TOC relative relocation.  A TOC relative load instruction
+   which may be changed to a load address instruction.
+   FIXME: We don't currently implement this optimization. 
+
+   R_TRLA:
+   TOC relative relocation.  This is a TOC relative load
+   address instruction which may be changed to a load
+   instruction.  FIXME: I don't know if this is the correct
+   implementation.
+
+   R_BA:
+   Absolute branch.  We don't want to mess with the lower
+   two bits of the instruction. 
+
+   R_CAI:
+   The PowerPC ABI defines this as an absolute call which
+   may be modified to become a relative call.  The PowerOpen
+   ABI does not define this relocation type. 
+   
+   R_RBA:
+   Absolute branch which may be modified to become a
+   relative branch. 
+
+   R_RBAC:
+   The PowerPC ABI defines this as an absolute branch to a
+   fixed address which may be modified to an absolute branch
+   to a symbol.  The PowerOpen ABI does not define this
+   relocation type. 
+
+   R_RBRC:
+   The PowerPC ABI defines this as an absolute branch to a
+   fixed address which may be modified to a relative branch.
+   The PowerOpen ABI does not define this relocation type. 
+
+   R_BR:
+   Relative branch.  We don't want to mess with the lower
+   two bits of the instruction. 
+
+   R_CREL:
+   The PowerPC ABI defines this as a relative call which may
+   be modified to become an absolute call.  The PowerOpen
+   ABI does not define this relocation type. 
+
+   R_RBR:
+   A relative branch which may be modified to become an
+   absolute branch.  FIXME: We don't implement this,
+   although we should for symbols of storage mapping class
+   XMC_XO. 
+
+   R_RL:
+   The PowerPC AIX ABI describes this as a load which may be
+   changed to a load address.  The PowerOpen ABI says this
+   is the same as case R_POS. 
+
+   R_RLA:
+   The PowerPC AIX ABI describes this as a load address
+   which may be changed to a load.  The PowerOpen ABI says
+   this is the same as R_POS. 
+*/
+
+boolean
 xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
 			    input_section, contents, relocs, syms,
 			    sections)
@@ -2644,7 +3269,6 @@ xcoff_ppc_relocate_section (output_bfd, 
 
   rel = relocs;
   relend = rel + input_section->reloc_count;
-
   for (; rel < relend; rel++)
     {
       long symndx;
@@ -2653,7 +3277,10 @@ xcoff_ppc_relocate_section (output_bfd, 
       bfd_vma addend;
       bfd_vma val;
       struct reloc_howto_struct howto;
-      bfd_reloc_status_type rstat;
+      bfd_vma relocation;
+      bfd_vma value_to_relocate;
+      bfd_vma address;
+      bfd_byte *location;
 
       /* Relocation type R_REF is a special relocation type which is
          merely used to prevent garbage collection from occurring for
@@ -2661,327 +3288,151 @@ xcoff_ppc_relocate_section (output_bfd, 
       if (rel->r_type == R_REF)
 	continue;
 
-      symndx = rel->r_symndx;
-
-      if (symndx == -1)
-	{
-	  h = NULL;
-	  sym = NULL;
-	  addend = 0;
-	}
-      else
-	{
-	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
-	  sym = syms + symndx;
-	  addend = - sym->n_value;
-
-	}
-
-      /* We build the howto information on the fly.  */
-
+      /* howto */
       howto.type = rel->r_type;
       howto.rightshift = 0;
-      howto.size = 2;
       howto.bitsize = (rel->r_size & 0x1f) + 1;
+      howto.size = howto.bitsize > 16 ? 2 : 1;
       howto.pc_relative = false;
       howto.bitpos = 0;
-      if ((rel->r_size & 0x80) != 0)
-	howto.complain_on_overflow = complain_overflow_signed;
-      else
-	howto.complain_on_overflow = complain_overflow_bitfield;
+      howto.complain_on_overflow = rel->r_size & 0x80 ? 
+	complain_overflow_signed : complain_overflow_bitfield;
       howto.special_function = NULL;
       howto.name = "internal";
       howto.partial_inplace = true;
-      if (howto.bitsize == 32)
-	howto.src_mask = howto.dst_mask = 0xffffffff;
-      else
-	{
-	  howto.src_mask = howto.dst_mask = (1 << howto.bitsize) - 1;
-	  if (howto.bitsize == 16)
-	    howto.size = 1;
-	}
+      howto.src_mask = howto.dst_mask = N_ONES(howto.bitsize);
       howto.pcrel_offset = false;
 
+      /* symbol */
       val = 0;
+      addend = 0;
+      h = NULL;
+      sym = NULL;
+      symndx = rel->r_symndx;      
 
-      if (h == NULL)
+      if (-1 != symndx)	
 	{
 	  asection *sec;
-
-	  if (symndx == -1)
-	    {
-	      sec = bfd_abs_section_ptr;
-	      val = 0;
-	    }
-	  else
+	  
+	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
+	  sym = syms + symndx;
+	  addend = - sym->n_value;
+	  
+	  if (NULL == h) 
 	    {
 	      sec = sections[symndx];
 	      /* Hack to make sure we use the right TOC anchor value
-                 if this reloc is against the TOC anchor.  */
-
+		 if this reloc is against the TOC anchor.  */
 	      if (sec->name[3] == '0'
-			  && strcmp (sec->name, ".tc0") == 0)
-		{
-		  val = xcoff_data (output_bfd)->toc;
-		}
+		  && strcmp (sec->name, ".tc0") == 0)
+		val = xcoff_data (output_bfd)->toc;
 	      else
+		val = (sec->output_section->vma
+		       + sec->output_offset
+		       + sym->n_value
+		       - sec->vma);
+	    } 
+	  else 
+	    {
+	      if (h->root.type == bfd_link_hash_defined 
+		  || h->root.type == bfd_link_hash_defweak) 
 		{
+		  sec = h->root.u.def.section;
+		  val = (h->root.u.def.value
+			 + sec->output_section->vma
+			 + sec->output_offset);
+		} 
+	      else if (h->root.type == bfd_link_hash_common) 
+		{
+		  sec = h->root.u.c.p->section;
 		  val = (sec->output_section->vma
-			 + sec->output_offset
-			 + sym->n_value
-			 - sec->vma);
+			 + sec->output_offset);
+		  
+		} 
+	      else if ((0 == (h->flags & (XCOFF_DEF_DYNAMIC | XCOFF_IMPORT))) 
+		       && ! info->relocateable) 
+		{
+		  if (! ((*info->callbacks->undefined_symbol)
+			 (info, h->root.root.string, input_bfd, input_section,
+			  rel->r_vaddr - input_section->vma, true)))
+		    return false;
+		  
+		  /* Don't try to process the reloc.  It can't help, and
+		     it may generate another error.  */
+		  continue;
 		}
 	    }
 	}
-      else
-	{
-	  if (h->root.type == bfd_link_hash_defined
-	      || h->root.type == bfd_link_hash_defweak)
-	    {
-	      asection *sec;
-
-	      sec = h->root.u.def.section;
-	      val = (h->root.u.def.value
-		     + sec->output_section->vma
-		     + sec->output_offset);
-	    }
-	  else if (h->root.type == bfd_link_hash_common)
-	    {
-	      asection *sec;
-
-	      sec = h->root.u.c.p->section;
-	      val = (sec->output_section->vma
-		     + sec->output_offset);
-	    }
-	  else if ((h->flags & XCOFF_DEF_DYNAMIC) != 0
-		   || (h->flags & XCOFF_IMPORT) != 0)
-	    {
-	      /* Every symbol in a shared object is defined somewhere.  */
-	      val = 0;
-	    }
-	  else if (! info->relocateable)
-	    {
-	      if (! ((*info->callbacks->undefined_symbol)
-		     (info, h->root.root.string, input_bfd, input_section,
-		      rel->r_vaddr - input_section->vma, true)))
-		return false;
 
-	      /* Don't try to process the reloc.  It can't help, and
-                 it may generate another error.  */
-	      continue;
-	    }
-	}
+      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION 
+	  || (false == xcoff_calculate_relocation[rel->r_type]
+	      (input_bfd, input_section, output_bfd, rel, sym, &howto, val, 
+	       addend, &relocation, contents))) 
+	return false;
+      
+      /* address */
+      address = rel->r_vaddr - input_section->vma;
+      location = contents + address;
+      
+      if (address > input_section->_raw_size)
+	abort();
 
-      /* I took the relocation type definitions from two documents:
-	 the PowerPC AIX Version 4 Application Binary Interface, First
-	 Edition (April 1992), and the PowerOpen ABI, Big-Endian
-	 32-Bit Hardware Implementation (June 30, 1994).  Differences
-	 between the documents are noted below.  */
+      /* Get the value we are going to relocate.  */
+      if (1 == howto.size)
+	value_to_relocate = bfd_get_16 (input_bfd, location);
+      else 
+	value_to_relocate = bfd_get_32 (input_bfd, location);
+      
+      /* overflow.  
+	 
+	 FIXME: We may drop bits during the addition
+	 which we don't check for.  We must either check at every single
+	 operation, which would be tedious, or we must do the computations
+	 in a type larger than bfd_vma, which would be inefficient.  */
+      
+      if ((unsigned int) howto.complain_on_overflow >= 
+	  XCOFF_MAX_COMPLAIN_OVERFLOW)
+	abort();
 
-      switch (rel->r_type)
+      if ((true == xcoff_complain_overflow[howto.complain_on_overflow]
+	   (input_bfd, value_to_relocate, relocation, &howto))) 
 	{
-	case R_RTB:
-	case R_RRTBI:
-	case R_RRTBA:
-	  /* These relocs are defined by the PowerPC ABI to be
-             relative branches which use half of the difference
-             between the symbol and the program counter.  I can't
-             quite figure out when this is useful.  These relocs are
-             not defined by the PowerOpen ABI.  */
-	default:
-	  (*_bfd_error_handler)
-	    (_("%s: unsupported relocation type 0x%02x"),
-	     bfd_archive_filename (input_bfd), (unsigned int) rel->r_type);
-	  bfd_set_error (bfd_error_bad_value);
-	  return false;
-	case R_POS:
-	  /* Simple positive relocation.  */
-	  break;
-	case R_NEG:
-	  /* Simple negative relocation.  */
-	  val = - val;
-	  break;
-	case R_REL:
-	  /* Simple PC relative relocation.  */
-	  howto.pc_relative = true;
-	  break;
-	case R_TOC:
-	  /* TOC relative relocation.  The value in the instruction in
-             the input file is the offset from the input file TOC to
-             the desired location.  We want the offset from the final
-             TOC to the desired location.  We have:
-	         isym = iTOC + in
-		 iinsn = in + o
-		 osym = oTOC + on
-		 oinsn = on + o
-	     so we must change insn by on - in.
-	     */
-	case R_GL:
-	  /* Global linkage relocation.  The value of this relocation
-             is the address of the entry in the TOC section.  */
-	case R_TCL:
-	  /* Local object TOC address.  I can't figure out the
-             difference between this and case R_GL.  */
-	case R_TRL:
-	  /* TOC relative relocation.  A TOC relative load instruction
-             which may be changed to a load address instruction.
-             FIXME: We don't currently implement this optimization.  */
-	case R_TRLA:
-	  /* TOC relative relocation.  This is a TOC relative load
-             address instruction which may be changed to a load
-             instruction.  FIXME: I don't know if this is the correct
-             implementation.  */
-	  if (h != NULL && h->smclas != XMC_TD)
+	  const char *name;
+	  char buf[SYMNMLEN + 1];
+	  char reloc_type_name[10];
+	  
+	  if (symndx == -1) 
 	    {
-	      if (h->toc_section == NULL)
-		{
-		  (*_bfd_error_handler)
-		    (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
-		     bfd_archive_filename (input_bfd), rel->r_vaddr,
-		     h->root.root.string);
-		  bfd_set_error (bfd_error_bad_value);
-		  return false;
-		}
-
-	      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
-	      val = (h->toc_section->output_section->vma
-		     + h->toc_section->output_offset);
-	    }
-
-	  val = ((val - xcoff_data (output_bfd)->toc)
-		 - (sym->n_value - xcoff_data (input_bfd)->toc));
-	  addend = 0;
-	  break;
-	case R_BA:
-	  /* Absolute branch.  We don't want to mess with the lower
-             two bits of the instruction.  */
-	case R_CAI:
-	  /* The PowerPC ABI defines this as an absolute call which
-             may be modified to become a relative call.  The PowerOpen
-             ABI does not define this relocation type.  */
-	case R_RBA:
-	  /* Absolute branch which may be modified to become a
-             relative branch.  */
-	case R_RBAC:
-	  /* The PowerPC ABI defines this as an absolute branch to a
-             fixed address which may be modified to an absolute branch
-             to a symbol.  The PowerOpen ABI does not define this
-             relocation type.  */
-	case R_RBRC:
-	  /* The PowerPC ABI defines this as an absolute branch to a
-             fixed address which may be modified to a relative branch.
-             The PowerOpen ABI does not define this relocation type.  */
-	  howto.src_mask &= ~3;
-	  howto.dst_mask = howto.src_mask;
-	  break;
-	case R_BR:
-	  /* Relative branch.  We don't want to mess with the lower
-             two bits of the instruction.  */
-	case R_CREL:
-	  /* The PowerPC ABI defines this as a relative call which may
-             be modified to become an absolute call.  The PowerOpen
-             ABI does not define this relocation type.  */
-	case R_RBR:
-	  /* A relative branch which may be modified to become an
-             absolute branch.  FIXME: We don't implement this,
-             although we should for symbols of storage mapping class
-             XMC_XO.  */
-	  howto.pc_relative = true;
-	  howto.src_mask &= ~3;
-	  howto.dst_mask = howto.src_mask;
-	  break;
-	case R_RL:
-	  /* The PowerPC AIX ABI describes this as a load which may be
-             changed to a load address.  The PowerOpen ABI says this
-             is the same as case R_POS.  */
-	  break;
-	case R_RLA:
-	  /* The PowerPC AIX ABI describes this as a load address
-             which may be changed to a load.  The PowerOpen ABI says
-             this is the same as R_POS.  */
-	  break;
-	}
-
-      /* If we see an R_BR or R_RBR reloc which is jumping to global
-         linkage code, and it is followed by an appropriate cror nop
-         instruction, we replace the cror with lwz r2,20(r1).  This
-         restores the TOC after the glink code.  Contrariwise, if the
-         call is followed by a lwz r2,20(r1), but the call is not
-         going to global linkage code, we can replace the load with a
-         cror.  */
-      if ((rel->r_type == R_BR || rel->r_type == R_RBR)
-	  && h != NULL
-	  && h->root.type == bfd_link_hash_defined
-	  && (rel->r_vaddr - input_section->vma + 8
-	      <= input_section->_cooked_size))
-	{
-	  bfd_byte *pnext;
-	  unsigned long next;
-
-	  pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
-	  next = bfd_get_32 (input_bfd, pnext);
-
-	  /* The _ptrgl function is magic.  It is used by the AIX
-             compiler to call a function through a pointer.  */
-	  if (h->smclas == XMC_GL
-	      || strcmp (h->root.root.string, "._ptrgl") == 0)
+	      name = "*ABS*";
+	    } 
+	  else if (h != NULL) 
 	    {
-	      if (next == 0x4def7b82		/* cror 15,15,15 */
-		  || next == 0x4ffffb82		/* cror 31,31,31 */
-		  || next == 0x60000000)	/* ori r0,r0,0 */
-		bfd_put_32 (input_bfd,
-			    (bfd_vma) 0x80410014, /* lwz r1,20(r1) */
-			    pnext);
-	    }
-	  else
+	      name = h->root.root.string;
+	    } 
+	  else 
 	    {
-	      if (next == 0x80410014)		/* lwz r1,20(r1) */
-		bfd_put_32 (input_bfd,
-			    (bfd_vma) 0x60000000, /* ori r0,r0,0 */
-			    pnext);
+	      name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+	      if (name == NULL)
+		name = "UNKNOWN";
 	    }
+	  sprintf (reloc_type_name, "0x%02x", rel->r_type);
+	  
+	  if (! ((*info->callbacks->reloc_overflow)
+		 (info, name, reloc_type_name, (bfd_vma) 0, input_bfd,
+		  input_section, rel->r_vaddr - input_section->vma)))
+	    return false;
 	}
-
-      /* A PC relative reloc includes the section address.  */
-      if (howto.pc_relative)
-	addend += input_section->vma;
-
-      rstat = _bfd_final_link_relocate (&howto, input_bfd, input_section,
-					contents,
-					rel->r_vaddr - input_section->vma,
-					val, addend);
-
-      switch (rstat)
-	{
-	default:
-	  abort ();
-	case bfd_reloc_ok:
-	  break;
-	case bfd_reloc_overflow:
-	  {
-	    const char *name;
-	    char buf[SYMNMLEN + 1];
-	    char howto_name[10];
-
-	    if (symndx == -1)
-	      name = "*ABS*";
-	    else if (h != NULL)
-	      name = h->root.root.string;
-	    else
-	      {
-		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
-
-		if (name == NULL)
-		  return false;
-	      }
-	    sprintf (howto_name, "0x%02x", rel->r_type);
-
-	    if (! ((*info->callbacks->reloc_overflow)
-		   (info, name, howto_name, (bfd_vma) 0, input_bfd,
-		    input_section, rel->r_vaddr - input_section->vma)))
-	      return false;
-	  }
-	}
+      
+      /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE.  */
+      value_to_relocate = ((value_to_relocate & ~howto.dst_mask) | 
+			   (((value_to_relocate & howto.src_mask) + 
+			     relocation) & howto.dst_mask));
+      
+      /* Put the value back in the object file.  */
+      if (1 == howto.size)
+	bfd_put_16 (input_bfd, value_to_relocate, location);
+      else 
+	bfd_put_32 (input_bfd, value_to_relocate, location);
     }
 
   return true;
Index: bfd/coff64-rs6000.c
===================================================================
RCS file: /cvs/src/src/bfd/coff64-rs6000.c,v
retrieving revision 1.24
diff -d -u -p -r1.24 coff64-rs6000.c
--- bfd/coff64-rs6000.c	20 Apr 2002 06:47:24 -0000	1.24
+++ bfd/coff64-rs6000.c	28 Apr 2002 03:24:51 -0000
@@ -992,11 +992,10 @@ xcoff64_write_object_contents (abfd)
   return true;
 }
 
-/* This is the relocation function for the RS/6000/POWER/PowerPC.
-   This is currently the only processor which uses XCOFF; I hope that
-   will never change.  */
+/* This is the relocation function for the PowerPC64.
+   See xcoff_ppc_relocation_section for more information. */
 
-static boolean
+boolean
 xcoff64_ppc_relocate_section (output_bfd, info, input_bfd,
 			      input_section, contents, relocs, syms,
 			      sections)
@@ -1022,73 +1021,48 @@ xcoff64_ppc_relocate_section (output_bfd
       bfd_vma addend;
       bfd_vma val;
       struct reloc_howto_struct howto;
-      bfd_reloc_status_type rstat;
+      bfd_vma relocation;
+      bfd_vma value_to_relocate;
+      bfd_vma address;
+      bfd_byte *location;
 
       /* Relocation type R_REF is a special relocation type which is
-	 merely used to prevent garbage collection from occurring for
-	 the csect including the symbol which it references.  */
+         merely used to prevent garbage collection from occurring for
+         the csect including the symbol which it references.  */
       if (rel->r_type == R_REF)
 	continue;
 
-      symndx = rel->r_symndx;
-
-      if (symndx == -1)
-	{
-	  h = NULL;
-	  sym = NULL;
-	  addend = 0;
-	}
-      else
-	{
-	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
-	  sym = syms + symndx;
-	  addend = - sym->n_value;
-	}
-
-      /* We build the howto information on the fly.  */
-
+      /* howto */
       howto.type = rel->r_type;
       howto.rightshift = 0;
-      howto.size = 4;
       howto.bitsize = (rel->r_size & 0x3f) + 1;
+      howto.size = howto.bitsize > 16 ? (howto.bitsize > 32 ? 4 : 2) : 1;
       howto.pc_relative = false;
       howto.bitpos = 0;
-      if ((rel->r_size & 0x80) != 0)
-	howto.complain_on_overflow = complain_overflow_signed;
-      else
-	howto.complain_on_overflow = complain_overflow_bitfield;
+      howto.complain_on_overflow = rel->r_size & 0x80 ? 
+	complain_overflow_signed : complain_overflow_bitfield;
       howto.special_function = NULL;
       howto.name = "internal";
       howto.partial_inplace = true;
-
-      if (howto.bitsize == 64)
-	{
-	  howto.src_mask = howto.dst_mask = MINUS_ONE;
-	}
-      else if (howto.bitsize == 32)
-	{
-	  howto.src_mask = howto.dst_mask = 0xffffffff;
-	}
-      else
-	{
-	  howto.src_mask = howto.dst_mask = (1 << howto.bitsize) - 1;
-	  if (howto.bitsize == 16)
-	    howto.size = 1;
-	}
+      howto.src_mask = howto.dst_mask = N_ONES(howto.bitsize);
       howto.pcrel_offset = false;
 
+      /* symbol */
       val = 0;
+      addend = 0;
+      h = NULL;
+      sym = NULL;
+      symndx = rel->r_symndx;      
 
-      if (h == NULL)
+      if (-1 != symndx)	
 	{
 	  asection *sec;
-
-	  if (symndx == -1)
-	    {
-	      sec = bfd_abs_section_ptr;
-	      val = 0;
-	    }
-	  else
+	  
+	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
+	  sym = syms + symndx;
+	  addend = - sym->n_value;
+	  
+	  if (NULL == h) 
 	    {
 	      sec = sections[symndx];
 	      /* Hack to make sure we use the right TOC anchor value
@@ -1101,266 +1075,113 @@ xcoff64_ppc_relocate_section (output_bfd
 		       + sec->output_offset
 		       + sym->n_value
 		       - sec->vma);
-	    }
-
-	}
-      else
-	{
-
-	  if (h->root.type == bfd_link_hash_defined
-	      || h->root.type == bfd_link_hash_defweak)
-	    {
-	      asection *sec;
-
-	      sec = h->root.u.def.section;
-	      val = (h->root.u.def.value
-		     + sec->output_section->vma
-		     + sec->output_offset);
-
-	    }
-	  else if (h->root.type == bfd_link_hash_common)
-	    {
-	      asection *sec;
-
-	      sec = h->root.u.c.p->section;
-	      val = (sec->output_section->vma
-		     + sec->output_offset);
-	    }
-	  else if ((h->flags & XCOFF_DEF_DYNAMIC) != 0
-		   || (h->flags & XCOFF_IMPORT) != 0)
-	    {
-	      /* Every symbol in a shared object is defined somewhere.  */
-	      val = 0;
-	    }
-	  else if (! info->relocateable)
-	    {
-	      if (! ((*info->callbacks->undefined_symbol)
-		     (info, h->root.root.string, input_bfd, input_section,
-		      rel->r_vaddr - input_section->vma, true)))
-		return false;
-
-	      /* Don't try to process the reloc.  It can't help, and
-		 it may generate another error.  */
-	      continue;
-	    }
-	}
-
-      /* I took the relocation type definitions from two documents:
-	 the PowerPC AIX Version 4 Application Binary Interface, First
-	 Edition (April 1992), and the PowerOpen ABI, Big-Endian
-	 32-Bit Hardware Implementation (June 30, 1994).  Differences
-	 between the documents are noted below.  */
-
-      switch (rel->r_type)
-	{
-	case R_RTB:
-	case R_RRTBI:
-	case R_RRTBA:
-	  /* These relocs are defined by the PowerPC ABI to be
-	     relative branches which use half of the difference
-	     between the symbol and the program counter.  I can't
-	     quite figure out when this is useful.  These relocs are
-	     not defined by the PowerOpen ABI.  */
-	default:
-	  (*_bfd_error_handler)
-	    (_("%s: unsupported relocation type 0x%02x"),
-	     bfd_archive_filename (input_bfd), (unsigned int) rel->r_type);
-	  bfd_set_error (bfd_error_bad_value);
-	  return false;
-	case R_POS:
-	  /* Simple positive relocation.  */
-	  break;
-	case R_NEG:
-	  /* Simple negative relocation.  */
-	  val = - val;
-	  break;
-	case R_REL:
-	  /* Simple PC relative relocation.  */
-	  howto.pc_relative = true;
-	  break;
-	case R_TOC:
-	  /* TOC relative relocation.  The value in the instruction in
-	     the input file is the offset from the input file TOC to
-	     the desired location.  We want the offset from the final
-	     TOC to the desired location.  We have:
-	     isym = iTOC + in
-	     iinsn = in + o
-	     osym = oTOC + on
-	     oinsn = on + o
-	     so we must change insn by on - in.
-	  */
-	case R_GL:
-	  /* Global linkage relocation.  The value of this relocation
-	     is the address of the entry in the TOC section.  */
-	case R_TCL:
-	  /* Local object TOC address.  I can't figure out the
-	     difference between this and case R_GL.  */
-	case R_TRL:
-	  /* TOC relative relocation.  A TOC relative load instruction
-	     which may be changed to a load address instruction.
-	     FIXME: We don't currently implement this optimization.  */
-	case R_TRLA:
-	  /* TOC relative relocation.  This is a TOC relative load
-	     address instruction which may be changed to a load
-	     instruction.  FIXME: I don't know if this is the correct
-	     implementation.  */
-	  if (h != NULL && h->smclas != XMC_TD)
+	    } 
+	  else 
 	    {
-	      if (h->toc_section == NULL)
+	      if (h->root.type == bfd_link_hash_defined 
+		  || h->root.type == bfd_link_hash_defweak) 
 		{
-		  (*_bfd_error_handler)
-		    (_("%s: TOC reloc at 0x%x to symbol `%s' with no TOC entry"),
-		     bfd_archive_filename (input_bfd), rel->r_vaddr,
-		     h->root.root.string);
-		  bfd_set_error (bfd_error_bad_value);
-		  return false;
+		  sec = h->root.u.def.section;
+		  val = (h->root.u.def.value
+			 + sec->output_section->vma
+			 + sec->output_offset);
+		} 
+	      else if (h->root.type == bfd_link_hash_common) 
+		{
+		  sec = h->root.u.c.p->section;
+		  val = (sec->output_section->vma
+			 + sec->output_offset);
+		} 
+	      else if ((0 == (h->flags & (XCOFF_DEF_DYNAMIC | XCOFF_IMPORT))) 
+		       && ! info->relocateable) 
+		{
+		  if (! ((*info->callbacks->undefined_symbol)
+			 (info, h->root.root.string, input_bfd, input_section,
+			  rel->r_vaddr - input_section->vma, true)))
+		    return false;
+		  
+		  /* Don't try to process the reloc.  It can't help, and
+		     it may generate another error.  */
+		  continue;
 		}
-
-	      BFD_ASSERT ((h->flags & XCOFF_SET_TOC) == 0);
-	      val = (h->toc_section->output_section->vma
-		     + h->toc_section->output_offset);
 	    }
-
-	  val = ((val - xcoff_data (output_bfd)->toc)
-		 - (sym->n_value - xcoff_data (input_bfd)->toc));
-
-	  addend = 0;
-	  break;
-	case R_BA:
-	  /* Absolute branch.  We don't want to mess with the lower
-	     two bits of the instruction.  */
-	case R_CAI:
-	  /* The PowerPC ABI defines this as an absolute call which
-	     may be modified to become a relative call.  The PowerOpen
-	     ABI does not define this relocation type.  */
-	case R_RBA:
-	  /* Absolute branch which may be modified to become a
-	     relative branch.  */
-	case R_RBAC:
-	  /* The PowerPC ABI defines this as an absolute branch to a
-	     fixed address which may be modified to an absolute branch
-	     to a symbol.  The PowerOpen ABI does not define this
-	     relocation type.  */
-	case R_RBRC:
-	  /* The PowerPC ABI defines this as an absolute branch to a
-	     fixed address which may be modified to a relative branch.
-	     The PowerOpen ABI does not define this relocation type.  */
-	  howto.src_mask &= ~3;
-	  howto.dst_mask = howto.src_mask;
-	  break;
-	case R_BR:
-	  /* Relative branch.  We don't want to mess with the lower
-	     two bits of the instruction.  */
-	case R_CREL:
-	  /* The PowerPC ABI defines this as a relative call which may
-	     be modified to become an absolute call.  The PowerOpen
-	     ABI does not define this relocation type.  */
-	case R_RBR:
-	  /* A relative branch which may be modified to become an
-	     absolute branch.  FIXME: We don't implement this,
-	     although we should for symbols of storage mapping class
-	     XMC_XO.  */
-	  howto.pc_relative = true;
-	  howto.src_mask &= ~3;
-	  howto.dst_mask = howto.src_mask;
-	  howto.size = 2;
-	  howto.complain_on_overflow = complain_overflow_bitfield;
-	  break;
-	case R_RL:
-	  /* The PowerPC AIX ABI describes this as a load which may be
-	     changed to a load address.  The PowerOpen ABI says this
-	     is the same as case R_POS.  */
-	  break;
-	case R_RLA:
-	  /* The PowerPC AIX ABI describes this as a load address
-	     which may be changed to a load.  The PowerOpen ABI says
-	     this is the same as R_POS.  */
-	  break;
 	}
-
-      /* If we see an R_BR or R_RBR reloc which is jumping to global
-	 linkage code, and it is followed by an appropriate cror nop
-	 instruction, we replace the cror with ld r2,40(r1).  This
-	 restores the TOC after the glink code.  Contrariwise, if the
-	 call is followed by a ld r2,40(r1), but the call is not
-	 going to global linkage code, we can replace the load with a
-	 cror.  */
-      if ((rel->r_type == R_BR || rel->r_type == R_RBR)
-	  && h != NULL
-	  && h->root.type == bfd_link_hash_defined
-	  && (rel->r_vaddr - input_section->vma + 8
-	      <= input_section->_cooked_size))
+      
+      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION 
+	  || (false == xcoff_calculate_relocation[rel->r_type]
+	      (input_bfd, input_section, output_bfd, rel, sym, &howto, val, 
+	       addend, &relocation, contents))) 
+	return false;
+      
+      /* address */
+      address = rel->r_vaddr - input_section->vma;
+      location = contents + address;
+      
+      if (address > input_section->_raw_size)
+	abort();
+      
+      /* Get the value we are going to relocate.  */
+      if (1 == howto.size)
+	value_to_relocate = bfd_get_16 (input_bfd, location);
+      else if (2 == howto.size)
+	value_to_relocate = bfd_get_32 (input_bfd, location);
+      else 
+	value_to_relocate = bfd_get_64 (input_bfd, location);
+      
+      /* overflow.  
+	 
+	 FIXME: We may drop bits during the addition
+	 which we don't check for.  We must either check at every single
+	 operation, which would be tedious, or we must do the computations
+	 in a type larger than bfd_vma, which would be inefficient.  */
+      
+      if ((unsigned int) howto.complain_on_overflow >= 
+	  XCOFF_MAX_COMPLAIN_OVERFLOW)
+	abort();
+      
+      if ((true == xcoff_complain_overflow[howto.complain_on_overflow]
+	   (input_bfd, value_to_relocate, relocation, &howto))) 
 	{
-	  bfd_byte *pnext;
-	  unsigned long next;
-
-	  pnext = contents + (rel->r_vaddr - input_section->vma) + 4;
-	  next = bfd_get_32 (input_bfd, pnext);
-
-
-	  /* The _ptrgl function is magic.  It is used by the AIX
-	   * compiler to call a function through a pointer.
-	   *
-	   * special case XMC_GL, global linkage
-	   */
-	  if (h->smclas == XMC_GL
-	      || strcmp (h->root.root.string, "._ptrgl") == 0)
+	  const char *name;
+	  char buf[SYMNMLEN + 1];
+	  char reloc_type_name[10];
+	  
+	  if (symndx == -1) 
 	    {
-	      if (next == 0x4def7b82 /* cror 15,15,15 */
-		  || next == 0x4ffffb82 /* cror 31,31,31 */
-		  || next == 0x60000000 /* ori r0,r0,0 */)
-		bfd_put_32 (input_bfd, (bfd_vma) 0xe8410028 /* ld r2,40(r1) */,
-			    pnext);
-	    }
-	  else
+	      name = "*ABS*";
+	    } 
+	  else if (h != NULL) 
 	    {
-	      if (next == 0xe8410028 /* ld r2,40(r1) */)
-		bfd_put_32 (input_bfd, (bfd_vma) 0x60000000 /* ori r0,r0,0 */,
-			    pnext);
+	      name = h->root.root.string;
+	    } 
+	  else 
+	    {
+	      name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
+	      if (name == NULL)
+		name = "UNKNOWN";
 	    }
+	  sprintf (reloc_type_name, "0x%02x", rel->r_type);
+	  
+	  if (! ((*info->callbacks->reloc_overflow)
+		 (info, name, reloc_type_name, (bfd_vma) 0, input_bfd,
+		  input_section, rel->r_vaddr - input_section->vma)))
+	    return false;
 	}
 
-      /* A PC relative reloc includes the section address.  */
-      if (howto.pc_relative)
-	addend += input_section->vma;
-
-      rstat = _bfd_final_link_relocate (&howto, input_bfd, input_section,
-					contents,
-					rel->r_vaddr - input_section->vma,
-					val, addend);
-
-      switch (rstat)
-	{
-	default:
-	  abort ();
-	case bfd_reloc_ok:
-	  break;
-	case bfd_reloc_overflow:
-	  {
-	    const char *name;
-	    char buf[SYMNMLEN + 1];
-	    char howto_name[10];
-
-	    if (symndx == -1)
-	      name = "*ABS*";
-	    else if (h != NULL)
-	      name = h->root.root.string;
-	    else
-	      {
-		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
-		if (name == NULL)
-		  return false;
-	      }
-	    sprintf (howto_name, "0x%02x", rel->r_type);
-
-	    if (! ((*info->callbacks->reloc_overflow)
-		   (info, name, howto_name, (bfd_vma) 0, input_bfd,
-		    input_section, rel->r_vaddr - input_section->vma)))
-	      return false;
-	  }
-	}
+      /* Add RELOCATION to the right bits of VALUE_TO_RELOCATE.  */
+      value_to_relocate = ((value_to_relocate & ~howto.dst_mask) | 
+			   (((value_to_relocate & howto.src_mask) + 
+			     relocation) & howto.dst_mask));
+      
+      /* Put the value back in the object file.  */
+      if (1 == howto.size)
+	bfd_put_16 (input_bfd, value_to_relocate, location);
+      else if (2 == howto.size)
+	bfd_put_32 (input_bfd, value_to_relocate, location);
+      else
+	bfd_put_64 (input_bfd, value_to_relocate, location);
+      
     }
-
   return true;
 }
 
Index: bfd/libxcoff.h
===================================================================
RCS file: /cvs/src/src/bfd/libxcoff.h,v
retrieving revision 1.9
diff -d -u -p -r1.9 libxcoff.h
--- bfd/libxcoff.h	18 Mar 2002 12:45:41 -0000	1.9
+++ bfd/libxcoff.h	28 Apr 2002 03:24:51 -0000
@@ -200,4 +200,26 @@ struct xcoff_backend_data_rec
 #define bfd_xcoff_text_align_power(a) ((xcoff_data (a)->text_align_power))
 #define bfd_xcoff_data_align_power(a) ((xcoff_data (a)->data_align_power))
 
+/* xcoff*_ppc_relocate_section macros  */
+#define XCOFF_MAX_CALCULATE_RELOCATION (0x1c)
+#define XCOFF_MAX_COMPLAIN_OVERFLOW (4)
+/* N_ONES produces N one bits, without overflowing machine arithmetic.  */
+#ifdef N_ONES
+#undef N_ONES
+#endif
+#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
+
+#define XCOFF_RELOC_FUNCTION_ARGS \
+  bfd *, asection *, bfd *, struct internal_reloc *, \
+  struct internal_syment *, struct reloc_howto_struct *, bfd_vma, bfd_vma, \
+  bfd_vma *relocation, bfd_byte *contents
+
+#define XCOFF_COMPLAIN_FUNCTION_ARGS \
+  bfd *, bfd_vma, bfd_vma, struct reloc_howto_struct *howto
+
+extern boolean (*xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION])
+     (XCOFF_RELOC_FUNCTION_ARGS);
+extern boolean (*xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW])
+     (XCOFF_COMPLAIN_FUNCTION_ARGS);
+
 #endif /* LIBXCOFF_H */

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