patch : aix ppc partial link fix

Tom Rix trix@redhat.com
Fri Aug 3 13:21:00 GMT 2001


This patch fixes a problem with the aix ppc linker. In this case : 
ld -bpT:0x10000000 -o b.o -r a.o
where a.c is 
void foo() { 
	bar();
}

The relocation for bar() was incorrectly reported as a relocation truncation
because the R_BR does not have enough bits to hold the section offset of
~0x10000000.  The native linker does not complain and now neither do we.

While I was stepping through the code,  I cleaned it up.  This is why the patch
is more than just a one line fix.

Tom 
-- 
Tom Rix 
GCC Engineer
trix@redhat.com
256.704.9201
2001-08-1  Tom Rix <trix@redhat.com>

	* coff-rs6000.c : (xcoff_ppc_relocate_section)  Remove incorrect error 
	for R_BR relocations.  Clean up function.  Now uses function tables : 
	complain_overflow and calc_relocation.  
	(complain_overflow_*) : New functions for complain_overflow table.
	(reloc_type_*) : New functions for calc_relocation table.
	* coff64-rs6000.c : Similar
	
diff -rcp -xCVS -x*~ bfd-original/coff-rs6000.c bfd/coff-rs6000.c
*** bfd-original/coff-rs6000.c	Mon Jul 30 12:24:06 2001
--- bfd/coff-rs6000.c	Thu Aug  2 12:54:49 2001
*************** xcoff_swap_ldrel_out (abfd, src, dst)
*** 2350,2359 ****
  }
  
  
  
  /* 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.  */
  
  boolean
  xcoff_ppc_relocate_section (output_bfd, info, input_bfd,
--- 2350,2883 ----
  }
  
  
+ static boolean 
+ reloc_type_noop (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		 struct internal_reloc *rel, struct internal_syment *sym,
+ 		 struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_fail (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		 struct internal_reloc *rel, struct internal_syment *sym,
+ 		 struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   (*_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 
+ reloc_type_pos (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   *relocation = val + addend;
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_neg (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   val = - val;
+   *relocation = val + addend;
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_rel (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   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 
+ reloc_type_toc (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		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 (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 
+ reloc_type_ba (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 	       struct internal_reloc *rel, struct internal_syment *sym,
+ 	       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 	       bfd_vma *relocation, bfd_byte *contents)
+ {
+ 
+   howto->src_mask &= ~3;
+   howto->dst_mask = howto->src_mask;
+ 
+   *relocation = val + addend;
+ 
+   return true;
+ }
+ static boolean 
+ reloc_type_br (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+ 	       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 
+ reloc_type_crel (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   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;
+ }
+ 
+ /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
+ #define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
+ #define RS6000_MAX_RELOC_TYPE 0x1c
+ static boolean (*calc_relocation[RS6000_MAX_RELOC_TYPE])
+      (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+       bfd_vma *relocation, bfd_byte *contents) = {
+   /* R_POS   (0x00) */ reloc_type_pos,
+   /* R_NEG   (0x01) */ reloc_type_neg,
+   /* R_REL   (0x02) */ reloc_type_rel,
+   /* R_TOC   (0x03) */ reloc_type_toc,
+   /* R_RTB   (0x04) */ reloc_type_fail,
+   /* R_GL    (0x05) */ reloc_type_toc,
+   /* R_TCL   (0x06) */ reloc_type_toc,
+   /*         (0x07) */ reloc_type_fail,
+   /* R_BA    (0x08) */ reloc_type_ba,
+   /*         (0x09) */ reloc_type_fail,
+   /* R_BR    (0x0a) */ reloc_type_br,
+   /*         (0x0b) */ reloc_type_fail,
+   /* R_RL    (0x0c) */ reloc_type_pos,
+   /* R_RLA   (0x0d) */ reloc_type_pos,
+   /*         (0x0e) */ reloc_type_fail,
+   /* R_REF   (0x0f) */ reloc_type_noop,
+   /*         (0x10) */ reloc_type_fail,
+   /*         (0x11) */ reloc_type_fail,
+   /* R_TRL   (0x12) */ reloc_type_toc,
+   /* R_TRLA  (0x13) */ reloc_type_toc,
+   /* R_RRTBI (0x14) */ reloc_type_fail,
+   /* R_RRTBA (0x15) */ reloc_type_fail,
+   /* R_CAI   (0x16) */ reloc_type_ba,
+   /* R_CREL  (0x17) */ reloc_type_crel,
+   /* R_RBA   (0x18) */ reloc_type_ba,
+   /* R_RBAC  (0x19) */ reloc_type_ba,
+   /* R_RBR   (0x1a) */ reloc_type_br,
+   /* R_RBRC  (0x1b) */ reloc_type_ba,
+      };
+ 
+ static boolean 
+ complain_overflow_dont_func(bfd *input_bfd, bfd_vma x, bfd_vma relocation, 
+ 			    struct reloc_howto_struct *howto) 
+ {
+   return false;
+ }
+ 
+ static boolean 
+ complain_overflow_bitfield_func(bfd *input_bfd, bfd_vma x, 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 = x & 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 
+ complain_overflow_signed_func(bfd *input_bfd, bfd_vma x, 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 = x & 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 
+ complain_overflow_unsigned_func(bfd *input_bfd, bfd_vma x, 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 = x & 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;
+ }
+ 
+ #define MAX_COMPLAIN_OVERFLOW 4
+ static boolean (*complain_overflow[MAX_COMPLAIN_OVERFLOW])
+      (bfd *input_bfd, bfd_vma x, bfd_vma relocation, 
+       struct reloc_howto_struct *howto) = {
+ 	/* complain_overflow_dont     */ complain_overflow_dont_func,
+ 	/* complain_overflow_bitfield */ complain_overflow_bitfield_func,
+ 	/* complain_overflow_signed   */ complain_overflow_signed_func,
+ 	/* complain_overflow_unsigned */ complain_overflow_unsigned_func,
+       };
  
  /* 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.  
! 
!    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,
*************** xcoff_ppc_relocate_section (output_bfd, 
*** 2381,2387 ****
        bfd_vma addend;
        bfd_vma val;
        struct reloc_howto_struct howto;
!       bfd_reloc_status_type rstat;
  
        /* Relocation type R_REF is a special relocation type which is
           merely used to prevent garbage collection from occurring for
--- 2905,2914 ----
        bfd_vma addend;
        bfd_vma val;
        struct reloc_howto_struct howto;
!       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
*************** xcoff_ppc_relocate_section (output_bfd, 
*** 2389,2706 ****
        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.type = rel->r_type;
        howto.rightshift = 0;
-       howto.size = 2;
        howto.bitsize = (rel->r_size & 0x1f) + 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.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.pcrel_offset = false;
  
        val = 0;
! 
!       if (h == NULL)
! 	{
! 	  asection *sec;
! 
! 	  if (symndx == -1)
! 	    {
! 	      sec = bfd_abs_section_ptr;
! 	      val = 0;
! 	    }
  	  else
! 	    {
! 	      sec = sections[symndx];
! 	      /* Hack to make sure we use the right TOC anchor value
!                  if this reloc is against the TOC anchor.  */
! 	      if (sec->name[3] == '0'
! 		  && 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)
! 	    {
! 	      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)))
! 		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_get_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)
! 	    {
! 	      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);
! 	    }
! 
! 	  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)
! 	    {
! 	      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 */
! 	    }
  	}
  
!       /* 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;
! 	  }
! 	}
      }
  
    return true;
--- 2916,3060 ----
        if (rel->r_type == R_REF)
  	continue;
  
!       /* howto */
        howto.type = rel->r_type;
        howto.rightshift = 0;
        howto.bitsize = (rel->r_size & 0x1f) + 1;
+       howto.size = howto.bitsize > 16 ? 2 : 1;
        howto.pc_relative = false;
        howto.bitpos = 0;
!       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;
!       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 (-1 != symndx)	{
! 	asection *sec;
! 
! 	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 (sec->name[3] == '0'
! 	      && 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);
! 
! 	  } 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)))
! 	      return false;
! 	    
! 	    /* Don't try to process the reloc.  It can't help, and
! 	       it may generate another error.  */
! 	    continue;
! 	  }
  	}
+       }
  
!       if (rel->r_type >= RS6000_MAX_RELOC_TYPE ||
! 	  (false == calc_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 
! 	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 >= 
! 	  MAX_COMPLAIN_OVERFLOW)
! 	abort();
! 
!       if ((true == complain_overflow[howto.complain_on_overflow]
! 	   (input_bfd, value_to_relocate, relocation, &howto))) {
! 	    
! 	const char *name;
! 	char buf[SYMNMLEN + 1];
! 	char reloc_type_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)
! 	    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;
!       }
  
!       /* 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;
diff -rcp -xCVS -x*~ bfd-original/coff64-rs6000.c bfd/coff64-rs6000.c
*** bfd-original/coff64-rs6000.c	Mon Jul 30 12:20:52 2001
--- bfd/coff64-rs6000.c	Thu Aug  2 12:47:11 2001
*************** xcoff64_write_object_contents (abfd)
*** 904,913 ****
    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.  */
  
  boolean
  xcoff64_ppc_relocate_section (output_bfd, info, input_bfd,
  			      input_section, contents, relocs, syms,
--- 904,1441 ----
    return true;
  }
  
+ static boolean 
+ reloc_type_noop (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		 struct internal_reloc *rel, struct internal_syment *sym,
+ 		 struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_fail (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		 struct internal_reloc *rel, struct internal_syment *sym,
+ 		 struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   (*_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 
+ reloc_type_pos (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   *relocation = val + addend;
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_neg (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   val = - val;
+   *relocation = val + addend;
+   return true;
+ }
+ 
+ static boolean 
+ reloc_type_rel (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		bfd_vma *relocation, bfd_byte *contents)
+ {
+   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 
+ reloc_type_toc (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 		struct internal_reloc *rel, struct internal_syment *sym,
+ 		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 (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 
+ reloc_type_ba (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+ 	       struct internal_reloc *rel, struct internal_syment *sym,
+ 	       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 	       bfd_vma *relocation, bfd_byte *contents)
+ {
+ 
+   howto->src_mask &= ~3;
+   howto->dst_mask = howto->src_mask;
+ 
+   *relocation = val + addend;
+ 
+   return true;
+ }
+ static boolean 
+ reloc_type_br (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+ 	       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 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 (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.  
+      * 
+      * special case XMC_GL, global linkage
+      */
+     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, 0xe8410028, pnext); /* ld r2,40(r1) */
+     
+     } else {
+       if (next == 0xe8410028)		/* ld r2,40(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 
+ reloc_type_crel (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+ 		 bfd_vma *relocation, bfd_byte *contents)
+ {
+   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;
+ }
+ 
+ /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
+ #define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1)
+ #define RS6000_MAX_RELOC_TYPE 0x1c
+ static boolean (*calc_relocation[RS6000_MAX_RELOC_TYPE])
+      (bfd *input_bfd, asection *input_section, bfd *output_bfd, 
+       struct internal_reloc *rel, struct internal_syment *sym,
+       struct reloc_howto_struct *howto, bfd_vma val, bfd_vma addend,
+       bfd_vma *relocation, bfd_byte *contents) = {
+   /* R_POS   (0x00) */ reloc_type_pos,
+   /* R_NEG   (0x01) */ reloc_type_neg,
+   /* R_REL   (0x02) */ reloc_type_rel,
+   /* R_TOC   (0x03) */ reloc_type_toc,
+   /* R_RTB   (0x04) */ reloc_type_fail,
+   /* R_GL    (0x05) */ reloc_type_toc,
+   /* R_TCL   (0x06) */ reloc_type_toc,
+   /*         (0x07) */ reloc_type_fail,
+   /* R_BA    (0x08) */ reloc_type_ba,
+   /*         (0x09) */ reloc_type_fail,
+   /* R_BR    (0x0a) */ reloc_type_br,
+   /*         (0x0b) */ reloc_type_fail,
+   /* R_RL    (0x0c) */ reloc_type_pos,
+   /* R_RLA   (0x0d) */ reloc_type_pos,
+   /*         (0x0e) */ reloc_type_fail,
+   /* R_REF   (0x0f) */ reloc_type_noop,
+   /*         (0x10) */ reloc_type_fail,
+   /*         (0x11) */ reloc_type_fail,
+   /* R_TRL   (0x12) */ reloc_type_toc,
+   /* R_TRLA  (0x13) */ reloc_type_toc,
+   /* R_RRTBI (0x14) */ reloc_type_fail,
+   /* R_RRTBA (0x15) */ reloc_type_fail,
+   /* R_CAI   (0x16) */ reloc_type_ba,
+   /* R_CREL  (0x17) */ reloc_type_crel,
+   /* R_RBA   (0x18) */ reloc_type_ba,
+   /* R_RBAC  (0x19) */ reloc_type_ba,
+   /* R_RBR   (0x1a) */ reloc_type_br,
+   /* R_RBRC  (0x1b) */ reloc_type_ba,
+      };
+ 
+ static boolean 
+ complain_overflow_dont_func(bfd *input_bfd, bfd_vma x, bfd_vma relocation, 
+ 			    struct reloc_howto_struct *howto) 
+ {
+   return false;
+ }
+ 
+ static boolean 
+ complain_overflow_bitfield_func(bfd *input_bfd, bfd_vma x, 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 = x & 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 
+ complain_overflow_signed_func(bfd *input_bfd, bfd_vma x, 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 = x & 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 
+ complain_overflow_unsigned_func(bfd *input_bfd, bfd_vma x, 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 = x & 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;
+ }
+ 
+ #define MAX_COMPLAIN_OVERFLOW 4
+ static boolean (*complain_overflow[MAX_COMPLAIN_OVERFLOW])
+      (bfd *input_bfd, bfd_vma x, bfd_vma relocation, 
+       struct reloc_howto_struct *howto) = {
+ 	/* complain_overflow_dont     */ complain_overflow_dont_func,
+ 	/* complain_overflow_bitfield */ complain_overflow_bitfield_func,
+ 	/* complain_overflow_signed   */ complain_overflow_signed_func,
+ 	/* complain_overflow_unsigned */ complain_overflow_unsigned_func,
+       };
+ 
  /* 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.  
  
+    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
  xcoff64_ppc_relocate_section (output_bfd, info, input_bfd,
  			      input_section, contents, relocs, syms,
*************** xcoff64_ppc_relocate_section (output_bfd
*** 934,940 ****
        bfd_vma addend;
        bfd_vma val;
        struct reloc_howto_struct howto;
!       bfd_reloc_status_type rstat;
  
        /* Relocation type R_REF is a special relocation type which is
           merely used to prevent garbage collection from occurring for
--- 1462,1471 ----
        bfd_vma addend;
        bfd_vma val;
        struct reloc_howto_struct howto;
!       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
*************** xcoff64_ppc_relocate_section (output_bfd
*** 942,995 ****
        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.type = rel->r_type;
        howto.rightshift = 0;
-       howto.size = 4;
        howto.bitsize = (rel->r_size & 0x3f) + 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.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.pcrel_offset = false;
  
        val = 0;
  
!       if (h == NULL) {
  	asection *sec;
  
! 	if (symndx == -1) {
! 	  sec = bfd_abs_section_ptr;
! 	  val = 0;
! 	} else {
  	  sec = sections[symndx];
  	  /* Hack to make sure we use the right TOC anchor value
  	     if this reloc is against the TOC anchor.  */
--- 1473,1509 ----
        if (rel->r_type == R_REF)
  	continue;
  
!       /* howto */
        howto.type = rel->r_type;
        howto.rightshift = 0;
        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;
!       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;
!       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 (-1 != symndx)	{
  	asection *sec;
  
! 	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.  */
*************** xcoff64_ppc_relocate_section (output_bfd
*** 1001,1256 ****
  		   + 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)))
! 	    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_get_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)
! 	  {
! 	    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);
  
! 	  }
  
  
! 	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)) {
! 
! 	  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)
! 	    {
! 	      if (next == 0x4def7b82		/* cror 15,15,15 */
! 		  || next == 0x4ffffb82		/* cror 31,31,31 */
! 		  || next == 0x60000000)	/* ori r0,r0,0 */
! 		bfd_put_32 (input_bfd, 0xe8410028, pnext); /* ld r2,40(r1) */
! 	    }
! 	  else
! 	    {
! 	      if (next == 0xe8410028)		/* ld r2,40(r1) */
! 		bfd_put_32 (input_bfd, 0x60000000, pnext); /* ori r0,r0,0 */
! 	    }
  	}
  
!       /* 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;
! 	  }
! 	}
      }
- 
    return true;
  }
  
--- 1515,1623 ----
  		   + 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);
  
! 	  } 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)))
! 	      return false;
! 	    
! 	    /* Don't try to process the reloc.  It can't help, and
! 	       it may generate another error.  */
! 	    continue;
! 	  }
! 	}
!       }
  
!       if (rel->r_type >= RS6000_MAX_RELOC_TYPE ||
! 	  (false == calc_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 >= 
! 	  MAX_COMPLAIN_OVERFLOW)
! 	abort();
! 
!       if ((true == complain_overflow[howto.complain_on_overflow]
! 	   (input_bfd, value_to_relocate, relocation, &howto))) {
! 	    
! 	const char *name;
! 	char buf[SYMNMLEN + 1];
! 	char reloc_type_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)
! 	    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;
!       }
  
!       /* 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;
  }
  



More information about the Binutils mailing list