public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 4/6] aix: correct HOWTO table and add missing relocations
@ 2021-02-16  9:57 CHIGOT, CLEMENT
  2021-02-22  7:17 ` Alan Modra
  0 siblings, 1 reply; 5+ messages in thread
From: CHIGOT, CLEMENT @ 2021-02-16  9:57 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1652 bytes --]

Since the last time AIX HOWTO table was modified, IBM has now
released an official documentation about XCOFF relocations.
This commit corrects the wrong ones and add some missing.
For now, the "custom" relocations made for xcoff_rtype2howto have
been kept.
The new relocations are still set as EMPTY_HOWTO because they will
be implemented in later commits.

In xcoff[64]_ppc_relocate_section, instead of recreating howto
from scratch, it's better to use the existing howto from the
table and fixing it according to r_size field.

bfd/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff-rs6000.c (xcoff_calculate_relocation): Correct and
        add new relocations.
        (xcoff_howto_table): Likewise.
        (xcoff_rtype2howto): Increase r_type maximum value possible.
        (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
        of create a new one from scratch.  Enable only some relocations
        to have a changing r_size.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
        (xcoff64_howto_table): Likewise.
        (xcoff64_rtype2howto): Likewise.
        (xcoff64_reloc_type_br): Moved.
        (xcoff64_ppc_relocate_section): Moved and reuse predefined HOWTOs.
        * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.

binutils/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * od-xcoff.c: Replace RTB by TRL entry.

include/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff/xcoff.h (R_RTB): Removed.
        (R_TRL): Fix value.







Clément Chigot



[-- Attachment #2: 0004-aix-correct-HOWTO-table-and-add-missing-relocations.patch --]
[-- Type: application/octet-stream, Size: 71179 bytes --]

From 8a010abd593a807bb8fe21dcb01bfc8b669159f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= <clement.chigot@atos.net>
Date: Tue, 16 Feb 2021 10:40:32 +0100
Subject: [PATCH 4/6] aix: correct HOWTO table and add missing relocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Since the last time AIX HOWTO table was modified, IBM has now
released an official documentation about XCOFF relocations.
This commit corrects the wrong ones and add some missing.
For now, the "custom" relocations made for xcoff_rtype2howto have
been kept.
The new relocations are still set as EMPTY_HOWTO because they will
be implemented in later commits.

In xcoff[64]_ppc_relocate_section, instead of recreating howto
from scratch, it's better to use the existing howto from the
table and fixing it according to r_size field.

bfd/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff-rs6000.c (xcoff_calculate_relocation): Correct and
        add new relocations.
        (xcoff_howto_table): Likewise.
        (xcoff_rtype2howto): Increase r_type maximum value possible.
        (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
        of create a new one from scratch.  Enable only some relocations
        to have a changing r_size.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
        (xcoff64_howto_table): Likewise.
        (xcoff64_rtype2howto): Likewise.
        (xcoff64_reloc_type_br): Moved.
        (xcoff64_ppc_relocate_section): Moved and reuse predefined HOWTOs.
        * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.

binutils/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * od-xcoff.c: Replace RTB by TRL entry.

include/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff/xcoff.h (R_RTB): Removed.
        (R_TRL): Fix value.
---
 bfd/coff-rs6000.c    |  322 +++++++----
 bfd/coff64-rs6000.c  | 1307 ++++++++++++++++++++++--------------------
 bfd/libxcoff.h       |    2 +-
 binutils/od-xcoff.c  |    3 +-
 include/coff/xcoff.h |   53 +-
 5 files changed, 911 insertions(+), 776 deletions(-)

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 194846794a..ae2738772b 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -158,34 +158,56 @@ static xcoff_complain_function xcoff_complain_overflow_unsigned_func;
 xcoff_reloc_function *const
 xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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_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_toc,  /* R_TRL   (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, /*         (0x10) */
+  xcoff_reloc_type_fail, /*         (0x11) */
+  xcoff_reloc_type_fail, /*         (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_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) */
+  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) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 xcoff_complain_function *const
@@ -652,11 +674,18 @@ _bfd_xcoff_swap_aux_out (bfd *abfd, void * inp, int type, int in_class,
   return bfd_coff_auxesz (abfd);
 }
 \f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
+/* The XCOFF reloc table.
+   XCOFF relocations aren't defined only by the type field r_type.
+   The bitsize and whether they are signed or not, are defined by
+   r_size field.  Thus, it's complicated to create a constant
+   table reference every possible relocation.
+   This table contains the "default" relocation and few modified
+   relocations what were already there.  It's enough when
+   xcoff_rtype2howto is called.
+   For relocations from an input bfd to an output bfd, the default
+   relocation is retrieved and when manually adapted.
+
+   For now, it seems to be enought.  */
 
 reloc_howto_type xcoff_howto_table[] =
 {
@@ -720,19 +749,19 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.  */
-  HOWTO (R_RTB,			/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+  /* 0x04: Same as R_TOC  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* 0x05: External TOC relative symbol.  */
@@ -767,7 +796,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (7),
 
-  /* 0x08: Non modifiable absolute branch.  */
+  /* 0x08: Same as R_RBA.  */
   HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -784,7 +813,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (9),
 
-  /* 0x0a: Non modifiable relative branch.  */
+  /* 0x0a: Same as R_RBR.  */
   HOWTO (R_BR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -801,34 +830,34 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0xb),
 
-  /* 0x0c: Indirect load.  */
+  /* 0x0c: Same as R_POS.  */
   HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
+  /* 0x0d: Same as R_POS.  */
   HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   EMPTY_HOWTO (0xe),
@@ -850,23 +879,9 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0x10),
   EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
 
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x13: TOC relative load address.  */
+  /* 0x13: Same as R_TOC.  */
   HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -882,7 +897,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x14: Modifiable relative branch.  */
-  HOWTO (R_RRTBI,		 /* type */
+  HOWTO (R_RRTBI,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -897,7 +912,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x15: Modifiable absolute branch.  */
-  HOWTO (R_RRTBA,		 /* type */
+  HOWTO (R_RRTBA,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -1045,12 +1060,50 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
+
+  EMPTY_HOWTO (0x1f),
+
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
+
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
+
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
 };
 
 void
 xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_RBRC)
+  if (internal->r_type > R_TOCL)
     abort ();
 
   /* Default howto layout works most of the time */
@@ -3222,11 +3275,14 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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 original version was based on 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.
+   Now, IBM has released an official documentation about XCOFF
+   format:
+   https://www.ibm.com/support/knowledgecenter/ssw_aix_72/filesreference/XCOFF.html
 
    Unsupported r_type's
 
@@ -3240,6 +3296,15 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    quite figure out when this is useful.  These relocs are
    not defined by the PowerOpen ABI.
 
+   R_TOCU
+   R_TOCL
+   R_TLS
+   R_TLS_IE
+   R_TLS_LD
+   R_TLSLE
+
+   Not yet implemented.
+
    Supported r_type's
 
    R_POS:
@@ -3261,38 +3326,68 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    osym = oTOC + on
    oinsn = on + o
    so we must change insn by on - in.
+   This relocation allows the linker to perform optimizations
+   by transforming a load instruction into a add-immediate
+   when possible. The relocation is, then, changed to R_TRLA
+   in the output file.
+   TODO: Currently, the optimisation isn't implemented.
+
+   R_TRL:
+   TOC relative relocation.  Same as R_TOC, except that
+   the optimization isn't allowed
+
+   R_TRLA:
+   TOC relative relocation.  This is a TOC relative load
+   address instruction which have been changed to an add-
+   immediate instruction.
 
    R_GL:
    GL linkage relocation.  The value of this relocation
-   is the address of the entry in the TOC section.
+   is the address of the external symbol 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_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_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_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.
+
+   R_REF:
+   Not a relocation but a way to prevent the garbage
+   collector of AIX linker to remove symbols.
+   This is not needed in our case.
 
    R_BA:
-   Absolute branch.  We don't want to mess with the lower
-   two bits of the instruction.
+   The PowerOpen ABI says this is the same as R_RBA.
+
+   R_RBA:
+   Absolute branch which may be modified to become a
+   relative branch.
+
+   R_BR:
+   The PowerOpen ABI says this is the same as R_RBR.
+
+   R_RBR:
+   A relative branch which may be modified to become an
+   absolute branch.
 
    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_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_RBAC:
    The PowerPC ABI defines this as an absolute branch to a
@@ -3304,29 +3399,6 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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.
-
-   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.
 */
 
 bfd_boolean
@@ -3369,21 +3441,33 @@ xcoff_ppc_relocate_section (bfd *output_bfd,
 	 aren't handled by the function.  */
       BFD_ASSERT(0 <= rel->r_symndx);
 
-      /* 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;
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+         This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.  */
+      memcpy(&howto, &xcoff_howto_table[rel->r_type], sizeof(howto));
+      if (howto.bitsize != (rel->r_size & 0x1f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x1f) + 1;
+	    howto.size = howto.bitsize > 16 ? 2 : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
       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;
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index bc2810b126..55bb141626 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -180,34 +180,56 @@ static xcoff_reloc_function xcoff64_reloc_type_br;
 xcoff_reloc_function *const
 xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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) */
-  xcoff64_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) */
-  xcoff64_reloc_type_br, /* R_RBR   (0x1a) */
-  xcoff_reloc_type_ba,	 /* R_RBRC  (0x1b) */
+  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_toc,  /* R_TRL     (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) */
+  xcoff64_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_fail, /*           (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) */
+  xcoff64_reloc_type_br, /* R_RBR     (0x1a) */
+  xcoff_reloc_type_ba,   /* R_RBRC    (0x1b) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 /* coffcode.h needs these to be defined.  */
@@ -710,303 +732,156 @@ xcoff64_swap_ldrel_out (bfd *abfd, const struct internal_ldrel *src, void *d)
 }
 
 
-static bfd_boolean
-xcoff64_reloc_type_br (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;
-  bfd_vma section_offset;
-
-  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
-  section_offset = rel->r_vaddr - input_section->vma;
 
-  /* 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
-	  || bfd_link_hash_defweak == h->root.type)
-      && section_offset + 8 <= input_section->size)
-    {
-      bfd_byte *pnext;
-      unsigned long next;
+\f
+/* The XCOFF reloc table.
+   Cf xcoff_howto_table comments.  */
 
-      pnext = contents + section_offset + 4;
-      next = bfd_get_32 (input_bfd, pnext);
+reloc_howto_type xcoff64_howto_table[] =
+{
+  /* 0x00: Standard 64 bit relocation.  */
+  HOWTO (R_POS,			/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_POS_64",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* 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, 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;
-    }
+  /* 0x01: 64 bit relocation, but store negative value.  */
+  HOWTO (R_NEG,			/* type */
+	 0,			/* rightshift */
+	 -4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_NEG",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  /* The original PC-relative relocation is biased by -r_vaddr, so adding
-     the value below will give the absolute target address.  */
-  *relocation = val + addend + rel->r_vaddr;
+  /* 0x02: 64 bit PC relative relocation.  */
+  HOWTO (R_REL,			/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_REL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  howto->src_mask &= ~3;
-  howto->dst_mask = howto->src_mask;
+  /* 0x03: 16 bit TOC relative relocation.  */
+  HOWTO (R_TOC,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOC",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  if (h != NULL
-      && (h->root.type == bfd_link_hash_defined
-	  || h->root.type == bfd_link_hash_defweak)
-      && bfd_is_abs_section (h->root.u.def.section)
-      && section_offset + 4 <= input_section->size)
-    {
-      bfd_byte *ptr;
-      bfd_vma insn;
+  /* 0x04: Same as R_TOC.  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TRL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* Turn the relative branch into an absolute one by setting the
-	 AA bit.  */
-      ptr = contents + section_offset;
-      insn = bfd_get_32 (input_bfd, ptr);
-      insn |= 2;
-      bfd_put_32 (input_bfd, insn, ptr);
+  /* 0x05: External TOC relative symbol.  */
+  HOWTO (R_GL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_GL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* Make the howto absolute too.  */
-      howto->pc_relative = FALSE;
-      howto->complain_on_overflow = complain_overflow_bitfield;
-    }
-  else
-    {
-      /* Use a PC-relative howto and subtract the instruction's address
-	 from the target address we calculated above.  */
-      howto->pc_relative = TRUE;
-      *relocation -= (input_section->output_section->vma
-		      + input_section->output_offset
-		      + section_offset);
-    }
-  return TRUE;
-}
+  /* 0x06: Local TOC relative symbol.	 */
+  HOWTO (R_TCL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-/* This is the relocation function for the PowerPC64.
-   See xcoff_ppc_relocation_section for more information. */
+  EMPTY_HOWTO (7),
 
-bfd_boolean
-xcoff64_ppc_relocate_section (bfd *output_bfd,
-			      struct bfd_link_info *info,
-			      bfd *input_bfd,
-			      asection *input_section,
-			      bfd_byte *contents,
-			      struct internal_reloc *relocs,
-			      struct internal_syment *syms,
-			      asection **sections)
-{
-  struct internal_reloc *rel;
-  struct internal_reloc *relend;
+  /* 0x08: Same as R_RBA.  */
+  HOWTO (R_BA,			/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_BA_26",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x03fffffc,		/* src_mask */
+	 0x03fffffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  rel = relocs;
-  relend = rel + input_section->reloc_count;
-  for (; rel < relend; rel++)
-    {
-      long symndx;
-      struct xcoff_link_hash_entry *h;
-      struct internal_syment *sym;
-      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;
+  EMPTY_HOWTO (9),
 
-      asection *sec;
+  /* 0x0a: Same as R_RBR.  */
+  HOWTO (R_BR,			/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_BR",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x03fffffc,		/* src_mask */
+	 0x03fffffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* 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.  */
-      if (rel->r_type == R_REF)
-	continue;
+  EMPTY_HOWTO (0xb),
 
-      /* Previous version of the code was handling negative r_symndx.
-	 But AFAIK, it can't appear except in .loader relocations which
-	 aren't handled by the function.  */
-      BFD_ASSERT(0 <= rel->r_symndx);
-
-      /* 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;
-
-      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 (info->unresolved_syms_in_objects != RM_IGNORE
-	      && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
-	    info->callbacks->undefined_symbol
-	      (info, h->root.root.string, input_bfd, input_section,
-	       rel->r_vaddr - input_section->vma,
-	       info->unresolved_syms_in_objects == RM_DIAGNOSE
-	       && !info->warn_unresolved_syms);
-
-	  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
-	    {
-	      BFD_ASSERT (bfd_link_relocatable (info)
-			  || (h->flags & XCOFF_DEF_DYNAMIC) != 0
-			  || (h->flags & XCOFF_IMPORT) != 0);
-	    }
-	}
-
-      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
-	  || !((*xcoff64_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->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 (((*xcoff_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 (h != NULL)
-	      name = NULL;
-	  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);
-
-	  (*info->callbacks->reloc_overflow)
-	    (info, (h ? &h->root : NULL), name, reloc_type_name,
-	     (bfd_vma) 0, input_bfd, input_section,
-	     rel->r_vaddr - input_section->vma);
-	}
-
-      /* 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;
-}
-
-\f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
-
-reloc_howto_type xcoff64_howto_table[] =
-{
-  /* 0x00: Standard 64 bit relocation.  */
-  HOWTO (R_POS,			/* type */
+  /* 0x0c: Same as R_POS.  */
+  HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
 	 64,			/* bitsize */
@@ -1014,44 +889,50 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_POS_64",		/* name */
+	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
 	 MINUS_ONE,		/* src_mask */
 	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x01: 64 bit relocation, but store negative value.  */
-  HOWTO (R_NEG,			/* type */
+  /* 0x0d: Same as R_POS.  */
+  HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 -4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
 	 64,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_NEG",		/* name */
+	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 MINUS_ONE,		/* src_mask */
 	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x02: 32 bit PC relative relocation.  */
-  HOWTO (R_REL,			/* type */
+  EMPTY_HOWTO (0xe),
+
+  /* 0x0f: Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
+  HOWTO (R_REF,			/* type */
 	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 TRUE,			/* pc_relative */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 1,			/* bitsize */
+	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_REL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 "R_REF",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x03: 16 bit TOC relative relocation.  */
-  HOWTO (R_TOC,			/* type */
+  EMPTY_HOWTO (0x10),
+  EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
+
+  /* 0x13: Same as R_TOC  */
+  HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1059,14 +940,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TOC",		/* name */
+	 "R_TRLA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.	*/
-  HOWTO (R_RTB,			/* type */
+  /* 0x14: Modifiable relative branch.  */
+  HOWTO (R_RRTBI,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -1074,14 +955,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_RRTBI",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffffffff,		/* src_mask */
 	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x05: External TOC relative symbol.  */
-  HOWTO (R_GL,			/* type */
+  /* 0x15: Modifiable absolute branch.  */
+  HOWTO (R_RRTBA,		/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_RRTBA",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* 0x16: Modifiable call absolute indirect.  */
+  HOWTO (R_CAI,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1089,14 +985,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_GL",		/* name */
+	 "R_CAI",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x06: Local TOC relative symbol.	 */
-  HOWTO (R_TCL,			/* type */
+  /* 0x17: Modifiable call relative.  */
+  HOWTO (R_CREL,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1104,16 +1000,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TCL",		/* name */
+	 "R_CREL",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (7),
-
-  /* 0x08: Non modifiable absolute branch.  */
-  HOWTO (R_BA,			/* type */
+  /* 0x18: Modifiable branch absolute.  */
+  HOWTO (R_RBA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 26,			/* bitsize */
@@ -1121,33 +1015,44 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_BA_26",		/* name */
+	 "R_RBA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0x03fffffc,		/* src_mask */
 	 0x03fffffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (9),
+  /* 0x19: Modifiable branch absolute.  */
+  HOWTO (R_RBAC,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_RBAC",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  /* 0x0a: Non modifiable relative branch.  */
-  HOWTO (R_BR,			/* type */
+  /* 0x1a: Modifiable branch relative.  */
+  HOWTO (R_RBR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 26,			/* bitsize */
-	 TRUE,			/* pc_relative */
+	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_BR",		/* name */
+	 "R_RBR_26",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0x03fffffc,		/* src_mask */
 	 0x03fffffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (0xb),
-
-  /* 0x0c: Indirect load.  */
-  HOWTO (R_RL,			/* type */
+  /* 0x1b: Modifiable branch absolute.  */
+  HOWTO (R_RBRC,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1155,49 +1060,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RL",		/* name */
+	 "R_RBRC",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
-  HOWTO (R_RLA,			/* type */
+  /* 0x1c: Standard 32 bit relocation.  */
+  HOWTO (R_POS,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RLA",		/* name */
+	 "R_POS_32",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (0xe),
-
-  /* 0x0f: Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
-  HOWTO (R_REF,			/* type */
-	 0,			/* rightshift */
-	 0,			/* size (0 = byte, 1 = short, 2 = long) */
-	 1,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_REF",		/* name */
-	 FALSE,			/* partial_inplace */
-	 0,			/* src_mask */
-	 0,			/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  EMPTY_HOWTO (0x10),
-  EMPTY_HOWTO (0x11),
-
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
+  /* 0x1d: 16 bit Non modifiable absolute branch.  */
+  HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1205,59 +1090,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TRL",		/* name */
+	 "R_BA_16",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xfffc,		/* src_mask */
+	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x13: TOC relative load address.	 */
-  HOWTO (R_TRLA,		/* type */
+  /* 0x1e: Modifiable branch relative.  */
+  HOWTO (R_RBR,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRLA",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x14: Modifiable relative branch.  */
-  HOWTO (R_RRTBI,		/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RRTBI",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x15: Modifiable absolute branch.  */
-  HOWTO (R_RRTBA,		/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
+	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RRTBA",		/* name */
+	 "R_RBR_16",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xfffc,		/* src_mask */
+	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x16: Modifiable call absolute indirect.	 */
-  HOWTO (R_CAI,			/* type */
+  /* 0x1f: Modifiable branch absolute.  */
+  HOWTO (R_RBA,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1265,231 +1120,429 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_CAI",		/* name */
+	 "R_RBA_16",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x17: Modifiable call relative.	*/
-  HOWTO (R_CREL,		/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_CREL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
 
-  /* 0x18: Modifiable branch absolute.  */
-  HOWTO (R_RBA,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 26,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBA",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0x03fffffc,		/* src_mask */
-	 0x03fffffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
 
-  /* 0x19: Modifiable branch absolute.  */
-  HOWTO (R_RBAC,		/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBAC",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
 
-  /* 0x1a: Modifiable branch relative.  */
-  HOWTO (R_RBR,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 26,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBR_26",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0x03fffffc,		/* src_mask */
-	 0x03fffffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
+};
+
+void
+xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
+{
+  if (internal->r_type > R_TOCL)
+    abort ();
+
+  /* Default howto layout works most of the time */
+  relent->howto = &xcoff64_howto_table[internal->r_type];
+
+  /* Special case some 16 bit reloc */
+  if (15 == (internal->r_size & 0x3f))
+    {
+      if (R_BA == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1d];
+      else if (R_RBR == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1e];
+      else if (R_RBA == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1f];
+    }
+  /* Special case 32 bit */
+  else if (31 == (internal->r_size & 0x3f))
+    {
+      if (R_POS == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1c];
+    }
+
+  /* The r_size field of an XCOFF reloc encodes the bitsize of the
+     relocation, as well as indicating whether it is signed or not.
+     Doublecheck that the relocation information gathered from the
+     type matches this information.  The bitsize is not significant
+     for R_REF relocs.  */
+  if (relent->howto->dst_mask != 0
+      && (relent->howto->bitsize
+	  != ((unsigned int) internal->r_size & 0x3f) + 1))
+    abort ();
+}
+
+reloc_howto_type *
+xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+			   bfd_reloc_code_real_type code)
+{
+  switch (code)
+    {
+    case BFD_RELOC_PPC_B26:
+      return &xcoff64_howto_table[0xa];
+    case BFD_RELOC_PPC_BA16:
+      return &xcoff64_howto_table[0x1d];
+    case BFD_RELOC_PPC_BA26:
+      return &xcoff64_howto_table[8];
+    case BFD_RELOC_PPC_TOC16:
+      return &xcoff64_howto_table[3];
+    case BFD_RELOC_16:
+      /* Note that this relocation is only internally used by gas.  */
+      return &xcoff64_howto_table[0xc];
+    case BFD_RELOC_PPC_B16:
+      return &xcoff64_howto_table[0x1e];
+    case BFD_RELOC_32:
+    case BFD_RELOC_CTOR:
+      return &xcoff64_howto_table[0x1c];
+    case BFD_RELOC_64:
+      return &xcoff64_howto_table[0];
+    case BFD_RELOC_NONE:
+      return &xcoff64_howto_table[0xf];
+    default:
+      return NULL;
+    }
+}
+
+static reloc_howto_type *
+xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+			   const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]);
+       i++)
+    if (xcoff64_howto_table[i].name != NULL
+	&& strcasecmp (xcoff64_howto_table[i].name, r_name) == 0)
+      return &xcoff64_howto_table[i];
+
+  return NULL;
+}
+
+static bfd_boolean
+xcoff64_reloc_type_br (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;
+  bfd_vma section_offset;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+  section_offset = rel->r_vaddr - input_section->vma;
+
+  /* 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
+	  || bfd_link_hash_defweak == h->root.type)
+      && section_offset + 8 <= input_section->size)
+    {
+      bfd_byte *pnext;
+      unsigned long next;
+
+      pnext = contents + section_offset + 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, 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;
+    }
+
+  /* The original PC-relative relocation is biased by -r_vaddr, so adding
+     the value below will give the absolute target address.  */
+  *relocation = val + addend + rel->r_vaddr;
+
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  if (h != NULL
+      && (h->root.type == bfd_link_hash_defined
+	  || h->root.type == bfd_link_hash_defweak)
+      && bfd_is_abs_section (h->root.u.def.section)
+      && section_offset + 4 <= input_section->size)
+    {
+      bfd_byte *ptr;
+      bfd_vma insn;
+
+      /* Turn the relative branch into an absolute one by setting the
+	 AA bit.  */
+      ptr = contents + section_offset;
+      insn = bfd_get_32 (input_bfd, ptr);
+      insn |= 2;
+      bfd_put_32 (input_bfd, insn, ptr);
+
+      /* Make the howto absolute too.  */
+      howto->pc_relative = FALSE;
+      howto->complain_on_overflow = complain_overflow_bitfield;
+    }
+  else
+    {
+      /* Use a PC-relative howto and subtract the instruction's address
+	 from the target address we calculated above.  */
+      howto->pc_relative = TRUE;
+      *relocation -= (input_section->output_section->vma
+		      + input_section->output_offset
+		      + section_offset);
+    }
+  return TRUE;
+}
+
+/* This is the relocation function for the PowerPC64.
+   See xcoff_ppc_relocation_section for more information. */
+
+bfd_boolean
+xcoff64_ppc_relocate_section (bfd *output_bfd,
+			      struct bfd_link_info *info,
+			      bfd *input_bfd,
+			      asection *input_section,
+			      bfd_byte *contents,
+			      struct internal_reloc *relocs,
+			      struct internal_syment *syms,
+			      asection **sections)
+{
+  struct internal_reloc *rel;
+  struct internal_reloc *relend;
+
+  rel = relocs;
+  relend = rel + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      long symndx;
+      struct xcoff_link_hash_entry *h;
+      struct internal_syment *sym;
+      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;
+      asection *sec;
+
+      /* 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.  */
+      if (rel->r_type == R_REF)
+	continue;
+
+      /* Previous version of the code was handling negative r_symndx.
+	 But AFAIK, it can't appear except in .loader relocations which
+	 aren't handled by the function.  */
+      BFD_ASSERT(0 <= rel->r_symndx);
+
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+         This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.  */
+      memcpy(&howto, &xcoff64_howto_table[rel->r_type], sizeof(howto));
+      if (howto.bitsize != (rel->r_size & 0x3f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x3f) + 1;
+	    howto.size = howto.bitsize > 16 ? (howto.bitsize > 32 ? 4 : 2) : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
+      howto.complain_on_overflow = (rel->r_size & 0x80
+				    ? complain_overflow_signed
+				    : complain_overflow_bitfield);
 
-  /* 0x1b: Modifiable branch absolute.  */
-  HOWTO (R_RBRC,		/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBRC",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      /* symbol */
+      val = 0;
+      addend = 0;
+      h = NULL;
+      sym = NULL;
+      symndx = rel->r_symndx;
 
-  /* 0x1c: Standard 32 bit relocation.  */
-  HOWTO (R_POS,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_POS_32",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      h = obj_xcoff_sym_hashes (input_bfd)[symndx];
+      sym = syms + symndx;
+      addend = - sym->n_value;
 
-  /* 0x1d: 16 bit Non modifiable absolute branch.  */
-  HOWTO (R_BA,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_BA_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xfffc,		/* src_mask */
-	 0xfffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      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 (info->unresolved_syms_in_objects != RM_IGNORE
+	      && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
+	    info->callbacks->undefined_symbol
+	      (info, h->root.root.string, input_bfd, input_section,
+	       rel->r_vaddr - input_section->vma,
+	       info->unresolved_syms_in_objects == RM_DIAGNOSE
+	       && !info->warn_unresolved_syms);
 
-  /* 0x1e: Modifiable branch relative.  */
-  HOWTO (R_RBR,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 TRUE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBR_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xfffc,		/* src_mask */
-	 0xfffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+	  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
+	    {
+	      BFD_ASSERT (bfd_link_relocatable (info)
+			  || (h->flags & XCOFF_DEF_DYNAMIC) != 0
+			  || (h->flags & XCOFF_IMPORT) != 0);
+	    }
+	}
 
-  /* 0x1f: Modifiable branch absolute.  */
-  HOWTO (R_RBA,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBA_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
+	  || !((*xcoff64_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;
 
-void
-xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
-{
-  if (internal->r_type > R_RBRC)
-    abort ();
+      if (address > input_section->size)
+	abort ();
 
-  /* Default howto layout works most of the time */
-  relent->howto = &xcoff64_howto_table[internal->r_type];
+      /* 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);
 
-  /* Special case some 16 bit reloc */
-  if (15 == (internal->r_size & 0x3f))
-    {
-      if (R_BA == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1d];
-      else if (R_RBR == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1e];
-      else if (R_RBA == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1f];
-    }
-  /* Special case 32 bit */
-  else if (31 == (internal->r_size & 0x3f))
-    {
-      if (R_POS == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1c];
-    }
+      /* overflow.
 
-  /* The r_size field of an XCOFF reloc encodes the bitsize of the
-     relocation, as well as indicating whether it is signed or not.
-     Doublecheck that the relocation information gathered from the
-     type matches this information.  The bitsize is not significant
-     for R_REF relocs.  */
-  if (relent->howto->dst_mask != 0
-      && (relent->howto->bitsize
-	  != ((unsigned int) internal->r_size & 0x3f) + 1))
-    abort ();
-}
+	 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.  */
 
-reloc_howto_type *
-xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-			   bfd_reloc_code_real_type code)
-{
-  switch (code)
-    {
-    case BFD_RELOC_PPC_B26:
-      return &xcoff64_howto_table[0xa];
-    case BFD_RELOC_PPC_BA16:
-      return &xcoff64_howto_table[0x1d];
-    case BFD_RELOC_PPC_BA26:
-      return &xcoff64_howto_table[8];
-    case BFD_RELOC_PPC_TOC16:
-      return &xcoff64_howto_table[3];
-    case BFD_RELOC_16:
-      /* Note that this relocation is only internally used by gas.  */
-      return &xcoff64_howto_table[0xc];
-    case BFD_RELOC_PPC_B16:
-      return &xcoff64_howto_table[0x1e];
-    case BFD_RELOC_32:
-    case BFD_RELOC_CTOR:
-      return &xcoff64_howto_table[0x1c];
-    case BFD_RELOC_64:
-      return &xcoff64_howto_table[0];
-    case BFD_RELOC_NONE:
-      return &xcoff64_howto_table[0xf];
-    default:
-      return NULL;
-    }
-}
+      if (((*xcoff_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];
 
-static reloc_howto_type *
-xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-			   const char *r_name)
-{
-  unsigned int i;
+	  if (h != NULL)
+	    name = NULL;
+	  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);
 
-  for (i = 0;
-       i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]);
-       i++)
-    if (xcoff64_howto_table[i].name != NULL
-	&& strcasecmp (xcoff64_howto_table[i].name, r_name) == 0)
-      return &xcoff64_howto_table[i];
+	  (*info->callbacks->reloc_overflow)
+	    (info, (h ? &h->root : NULL), name, reloc_type_name,
+	     (bfd_vma) 0, input_bfd, input_section,
+	     rel->r_vaddr - input_section->vma);
+	}
 
-  return NULL;
+      /* 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;
 }
 
 /* PR 21786:  The PE/COFF standard does not require NUL termination for any of
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index e96f53260e..229e47c2ae 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -202,7 +202,7 @@ struct xcoff_backend_data_rec
 #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_CALCULATE_RELOCATION (0x32)
 #define XCOFF_MAX_COMPLAIN_OVERFLOW (4)
 /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
 #ifdef N_ONES
diff --git a/binutils/od-xcoff.c b/binutils/od-xcoff.c
index ad3235e643..f0d566b190 100644
--- a/binutils/od-xcoff.c
+++ b/binutils/od-xcoff.c
@@ -300,7 +300,7 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (NEG),
     RTYPE_ENTRY (REL),
     RTYPE_ENTRY (TOC),
-    RTYPE_ENTRY (RTB),
+    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (GL),
     RTYPE_ENTRY (TCL),
     RTYPE_ENTRY (BA),
@@ -308,7 +308,6 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (RL),
     RTYPE_ENTRY (RLA),
     RTYPE_ENTRY (REF),
-    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (TRLA),
     RTYPE_ENTRY (RRTBI),
     RTYPE_ENTRY (RRTBA),
diff --git a/include/coff/xcoff.h b/include/coff/xcoff.h
index 50ac0df20d..36651d4375 100644
--- a/include/coff/xcoff.h
+++ b/include/coff/xcoff.h
@@ -97,36 +97,35 @@
    The relocations are described in the function  
    xcoff[64]_ppc_relocate_section in coff64-rs6000.c and coff-rs6000.c  */
 
-#define R_POS   (0x00)
-#define R_NEG   (0x01)
-#define R_REL   (0x02)
-#define R_TOC   (0x03)
-#define R_RTB   (0x04)
-#define R_GL    (0x05)
-#define R_TCL   (0x06)
-#define R_BA    (0x08)
-#define R_BR    (0x0a)
-#define R_RL    (0x0c)
-#define R_RLA   (0x0d)
-#define R_REF   (0x0f)
-#define R_TRL   (0x12)
-#define R_TRLA  (0x13)
-#define R_RRTBI (0x14)
-#define R_RRTBA (0x15)
-#define R_CAI   (0x16)
-#define R_CREL  (0x17)
-#define R_RBA   (0x18)
-#define R_RBAC  (0x19)
-#define R_RBR   (0x1a)
-#define R_RBRC  (0x1b)
-#define R_TLS   (0x20)
+#define R_POS    (0x00)
+#define R_NEG    (0x01)
+#define R_REL    (0x02)
+#define R_TOC    (0x03)
+#define R_TRL    (0x04)
+#define R_GL     (0x05)
+#define R_TCL    (0x06)
+#define R_BA     (0x08)
+#define R_BR     (0x0a)
+#define R_RL     (0x0c)
+#define R_RLA    (0x0d)
+#define R_REF    (0x0f)
+#define R_TRLA   (0x13)
+#define R_RRTBI  (0x14)
+#define R_RRTBA  (0x15)
+#define R_CAI    (0x16)
+#define R_CREL   (0x17)
+#define R_RBA    (0x18)
+#define R_RBAC   (0x19)
+#define R_RBR    (0x1a)
+#define R_RBRC   (0x1b)
+#define R_TLS    (0x20)
 #define R_TLS_IE (0x21)
 #define R_TLS_LD (0x22)
 #define R_TLS_LE (0x23)
-#define R_TLSM  (0x24)
-#define R_TLSML (0x25)
-#define R_TOCU  (0x30)
-#define R_TOCL  (0x31)
+#define R_TLSM   (0x24)
+#define R_TLSML  (0x25)
+#define R_TOCU   (0x30)
+#define R_TOCL   (0x31)
 
 /* Storage class #defines, from /usr/include/storclass.h that are not already 
    defined in internal.h */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 4/6] aix: correct HOWTO table and add missing relocations
  2021-02-16  9:57 [PATCH 4/6] aix: correct HOWTO table and add missing relocations CHIGOT, CLEMENT
@ 2021-02-22  7:17 ` Alan Modra
  2021-02-26  7:55   ` CHIGOT, CLEMENT
  0 siblings, 1 reply; 5+ messages in thread
From: Alan Modra @ 2021-02-22  7:17 UTC (permalink / raw)
  To: CHIGOT, CLEMENT; +Cc: binutils

On Tue, Feb 16, 2021 at 09:57:48AM +0000, CHIGOT, CLEMENT wrote:
> Since the last time AIX HOWTO table was modified, IBM has now
> released an official documentation about XCOFF relocations.
> This commit corrects the wrong ones and add some missing.
> For now, the "custom" relocations made for xcoff_rtype2howto have
> been kept.
> The new relocations are still set as EMPTY_HOWTO because they will
> be implemented in later commits.
> 
> In xcoff[64]_ppc_relocate_section, instead of recreating howto
> from scratch, it's better to use the existing howto from the
> table and fixing it according to r_size field.
> 
> bfd/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * coff-rs6000.c (xcoff_calculate_relocation): Correct and
>         add new relocations.
>         (xcoff_howto_table): Likewise.
>         (xcoff_rtype2howto): Increase r_type maximum value possible.
>         (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
>         of create a new one from scratch.  Enable only some relocations
>         to have a changing r_size.
>         * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
>         (xcoff64_howto_table): Likewise.
>         (xcoff64_rtype2howto): Likewise.
>         (xcoff64_reloc_type_br): Moved.
>         (xcoff64_ppc_relocate_section): Moved and reuse predefined HOWTOs.
>         * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.
> 
> binutils/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * od-xcoff.c: Replace RTB by TRL entry.
> 
> include/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * coff/xcoff.h (R_RTB): Removed.
>         (R_TRL): Fix value.

This all looks reasonable, but for ease of review in future please
split out patches that move functions around from changes to the moved
functions.

+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+         This should be made during relocation reading but the algorithms

Leading whitespace ought to be a tab.

+	 are expecting constant howtos.  */
+      memcpy(&howto, &xcoff64_howto_table[rel->r_type], sizeof(howto));

Space before '(' here, twice.


-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 4/6] aix: correct HOWTO table and add missing relocations
  2021-02-22  7:17 ` Alan Modra
@ 2021-02-26  7:55   ` CHIGOT, CLEMENT
  2021-02-26 11:07     ` Alan Modra
  0 siblings, 1 reply; 5+ messages in thread
From: CHIGOT, CLEMENT @ 2021-02-26  7:55 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

[-- Attachment #1: Type: text/plain, Size: 230 bytes --]

Hi Alan, 

Here is the new version with the fix you asked for. 
I've also rebased it as I've removed the commit linked to r_symndx handlers.

PS: Assignment is on the way, but it might take some times. 

Thanks, 
Clément

[-- Attachment #2: 0003-aix-correct-HOWTO-table-and-add-missing-relocations-V2.patch --]
[-- Type: application/octet-stream, Size: 70715 bytes --]

From 879bf652be6b2a5e4df810531e0c5e0eed7eafbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= <clement.chigot@atos.net>
Date: Tue, 16 Feb 2021 10:40:32 +0100
Subject: [PATCH 3/5] aix: correct HOWTO table and add missing relocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Since the last time AIX HOWTO table was modified, IBM has now
released an official documentation about XCOFF relocations.
This commit corrects the wrong ones and add some missing.
For now, the "custom" relocations made for xcoff_rtype2howto have
been kept.
The new relocations are still set as EMPTY_HOWTO because they will
be implemented in later commits.

In xcoff[64]_ppc_relocate_section, instead of recreating howto
from scratch, it's better to use the existing howto from the
table and fixing it according to r_size field.

bfd/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff-rs6000.c (xcoff_calculate_relocation): Correct and
        add new relocations.
        (xcoff_howto_table): Likewise.
        (xcoff_rtype2howto): Increase r_type maximum value possible.
        (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
        of create a new one from scratch.  Enable only some relocations
        to have a changing r_size.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
        (xcoff64_howto_table): Likewise.
        (xcoff64_rtype2howto): Likewise.
        (xcoff64_reloc_type_br): Moved.
        (xcoff64_ppc_relocate_section): Moved and reuse predefined HOWTOs.
        * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.

binutils/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * od-xcoff.c: Replace RTB by TRL entry.

include/ChangeLog:
2020-11-20  Clément Chigot  <clement.chigot@atos.net>

        * coff/xcoff.h (R_RTB): Removed.
        (R_TRL): Fix value.
---
 bfd/coff-rs6000.c    |  322 +++++++----
 bfd/coff64-rs6000.c  | 1315 ++++++++++++++++++++++--------------------
 bfd/libxcoff.h       |    2 +-
 binutils/od-xcoff.c  |    3 +-
 include/coff/xcoff.h |   53 +-
 5 files changed, 915 insertions(+), 780 deletions(-)

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 54fbf58e3a..cb3c657f66 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -158,34 +158,56 @@ static xcoff_complain_function xcoff_complain_overflow_unsigned_func;
 xcoff_reloc_function *const
 xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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_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_toc,  /* R_TRL   (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, /*         (0x10) */
+  xcoff_reloc_type_fail, /*         (0x11) */
+  xcoff_reloc_type_fail, /*         (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_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) */
+  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) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 xcoff_complain_function *const
@@ -652,11 +674,18 @@ _bfd_xcoff_swap_aux_out (bfd *abfd, void * inp, int type, int in_class,
   return bfd_coff_auxesz (abfd);
 }
 \f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
+/* The XCOFF reloc table.
+   XCOFF relocations aren't defined only by the type field r_type.
+   The bitsize and whether they are signed or not, are defined by
+   r_size field.  Thus, it's complicated to create a constant
+   table reference every possible relocation.
+   This table contains the "default" relocation and few modified
+   relocations what were already there.  It's enough when
+   xcoff_rtype2howto is called.
+   For relocations from an input bfd to an output bfd, the default
+   relocation is retrieved and when manually adapted.
+
+   For now, it seems to be enought.  */
 
 reloc_howto_type xcoff_howto_table[] =
 {
@@ -720,19 +749,19 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.  */
-  HOWTO (R_RTB,			/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+  /* 0x04: Same as R_TOC  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* 0x05: External TOC relative symbol.  */
@@ -767,7 +796,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (7),
 
-  /* 0x08: Non modifiable absolute branch.  */
+  /* 0x08: Same as R_RBA.  */
   HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -784,7 +813,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (9),
 
-  /* 0x0a: Non modifiable relative branch.  */
+  /* 0x0a: Same as R_RBR.  */
   HOWTO (R_BR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -801,34 +830,34 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0xb),
 
-  /* 0x0c: Indirect load.  */
+  /* 0x0c: Same as R_POS.  */
   HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
+  /* 0x0d: Same as R_POS.  */
   HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   EMPTY_HOWTO (0xe),
@@ -850,23 +879,9 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0x10),
   EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
 
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x13: TOC relative load address.  */
+  /* 0x13: Same as R_TOC.  */
   HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -882,7 +897,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x14: Modifiable relative branch.  */
-  HOWTO (R_RRTBI,		 /* type */
+  HOWTO (R_RRTBI,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -897,7 +912,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x15: Modifiable absolute branch.  */
-  HOWTO (R_RRTBA,		 /* type */
+  HOWTO (R_RRTBA,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -1045,12 +1060,50 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
+
+  EMPTY_HOWTO (0x1f),
+
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
+
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
+
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
 };
 
 void
 xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_RBRC)
+  if (internal->r_type > R_TOCL)
     abort ();
 
   /* Default howto layout works most of the time */
@@ -3225,11 +3278,14 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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 original version was based on 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.
+   Now, IBM has released an official documentation about XCOFF
+   format:
+   https://www.ibm.com/support/knowledgecenter/ssw_aix_72/filesreference/XCOFF.html
 
    Unsupported r_type's
 
@@ -3243,6 +3299,15 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    quite figure out when this is useful.  These relocs are
    not defined by the PowerOpen ABI.
 
+   R_TOCU
+   R_TOCL
+   R_TLS
+   R_TLS_IE
+   R_TLS_LD
+   R_TLSLE
+
+   Not yet implemented.
+
    Supported r_type's
 
    R_POS:
@@ -3264,38 +3329,68 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    osym = oTOC + on
    oinsn = on + o
    so we must change insn by on - in.
+   This relocation allows the linker to perform optimizations
+   by transforming a load instruction into a add-immediate
+   when possible. The relocation is, then, changed to R_TRLA
+   in the output file.
+   TODO: Currently, the optimisation isn't implemented.
+
+   R_TRL:
+   TOC relative relocation.  Same as R_TOC, except that
+   the optimization isn't allowed
+
+   R_TRLA:
+   TOC relative relocation.  This is a TOC relative load
+   address instruction which have been changed to an add-
+   immediate instruction.
 
    R_GL:
    GL linkage relocation.  The value of this relocation
-   is the address of the entry in the TOC section.
+   is the address of the external symbol 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_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_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_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.
+
+   R_REF:
+   Not a relocation but a way to prevent the garbage
+   collector of AIX linker to remove symbols.
+   This is not needed in our case.
 
    R_BA:
-   Absolute branch.  We don't want to mess with the lower
-   two bits of the instruction.
+   The PowerOpen ABI says this is the same as R_RBA.
+
+   R_RBA:
+   Absolute branch which may be modified to become a
+   relative branch.
+
+   R_BR:
+   The PowerOpen ABI says this is the same as R_RBR.
+
+   R_RBR:
+   A relative branch which may be modified to become an
+   absolute branch.
 
    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_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_RBAC:
    The PowerPC ABI defines this as an absolute branch to a
@@ -3307,29 +3402,6 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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.
-
-   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.
 */
 
 bfd_boolean
@@ -3366,21 +3438,33 @@ xcoff_ppc_relocate_section (bfd *output_bfd,
       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;
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+	 This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.	 */
+      memcpy (&howto, &xcoff_howto_table[rel->r_type], sizeof (howto));
+      if (howto.bitsize != (rel->r_size & 0x1f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x1f) + 1;
+	    howto.size = howto.bitsize > 16 ? 2 : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
       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;
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index a31a6fb91a..5ad4c656a4 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -180,34 +180,56 @@ static xcoff_reloc_function xcoff64_reloc_type_br;
 xcoff_reloc_function *const
 xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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) */
-  xcoff64_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) */
-  xcoff64_reloc_type_br, /* R_RBR   (0x1a) */
-  xcoff_reloc_type_ba,	 /* R_RBRC  (0x1b) */
+  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_toc,  /* R_TRL     (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) */
+  xcoff64_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_fail, /*           (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) */
+  xcoff64_reloc_type_br, /* R_RBR     (0x1a) */
+  xcoff_reloc_type_ba,   /* R_RBRC    (0x1b) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 /* coffcode.h needs these to be defined.  */
@@ -710,310 +732,156 @@ xcoff64_swap_ldrel_out (bfd *abfd, const struct internal_ldrel *src, void *d)
 }
 
 
-static bfd_boolean
-xcoff64_reloc_type_br (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;
-  bfd_vma section_offset;
-
-  if (0 > rel->r_symndx)
-    return FALSE;
 
-  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
-  section_offset = rel->r_vaddr - input_section->vma;
+\f
+/* The XCOFF reloc table.
+   Cf xcoff_howto_table comments.  */
 
-  /* 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
-	  || bfd_link_hash_defweak == h->root.type)
-      && section_offset + 8 <= input_section->size)
-    {
-      bfd_byte *pnext;
-      unsigned long next;
+reloc_howto_type xcoff64_howto_table[] =
+{
+  /* 0x00: Standard 64 bit relocation.  */
+  HOWTO (R_POS,			/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_POS_64",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      pnext = contents + section_offset + 4;
-      next = bfd_get_32 (input_bfd, pnext);
+  /* 0x01: 64 bit relocation, but store negative value.  */
+  HOWTO (R_NEG,			/* type */
+	 0,			/* rightshift */
+	 -4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_NEG",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* 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, 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;
-    }
+  /* 0x02: 64 bit PC relative relocation.  */
+  HOWTO (R_REL,			/* type */
+	 0,			/* rightshift */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_REL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  /* The original PC-relative relocation is biased by -r_vaddr, so adding
-     the value below will give the absolute target address.  */
-  *relocation = val + addend + rel->r_vaddr;
+  /* 0x03: 16 bit TOC relative relocation.  */
+  HOWTO (R_TOC,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOC",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  howto->src_mask &= ~3;
-  howto->dst_mask = howto->src_mask;
+  /* 0x04: Same as R_TOC.  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TRL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  if (h != NULL
-      && (h->root.type == bfd_link_hash_defined
-	  || h->root.type == bfd_link_hash_defweak)
-      && bfd_is_abs_section (h->root.u.def.section)
-      && section_offset + 4 <= input_section->size)
-    {
-      bfd_byte *ptr;
-      bfd_vma insn;
+  /* 0x05: External TOC relative symbol.  */
+  HOWTO (R_GL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_GL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* Turn the relative branch into an absolute one by setting the
-	 AA bit.  */
-      ptr = contents + section_offset;
-      insn = bfd_get_32 (input_bfd, ptr);
-      insn |= 2;
-      bfd_put_32 (input_bfd, insn, ptr);
+  /* 0x06: Local TOC relative symbol.	 */
+  HOWTO (R_TCL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* Make the howto absolute too.  */
-      howto->pc_relative = FALSE;
-      howto->complain_on_overflow = complain_overflow_bitfield;
-    }
-  else
-    {
-      /* Use a PC-relative howto and subtract the instruction's address
-	 from the target address we calculated above.  */
-      howto->pc_relative = TRUE;
-      *relocation -= (input_section->output_section->vma
-		      + input_section->output_offset
-		      + section_offset);
-    }
-  return TRUE;
-}
+  EMPTY_HOWTO (7),
 
-/* This is the relocation function for the PowerPC64.
-   See xcoff_ppc_relocation_section for more information. */
+  /* 0x08: Same as R_RBA.  */
+  HOWTO (R_BA,			/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_BA_26",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x03fffffc,		/* src_mask */
+	 0x03fffffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-bfd_boolean
-xcoff64_ppc_relocate_section (bfd *output_bfd,
-			      struct bfd_link_info *info,
-			      bfd *input_bfd,
-			      asection *input_section,
-			      bfd_byte *contents,
-			      struct internal_reloc *relocs,
-			      struct internal_syment *syms,
-			      asection **sections)
-{
-  struct internal_reloc *rel;
-  struct internal_reloc *relend;
+  EMPTY_HOWTO (9),
 
-  rel = relocs;
-  relend = rel + input_section->reloc_count;
-  for (; rel < relend; rel++)
-    {
-      long symndx;
-      struct xcoff_link_hash_entry *h;
-      struct internal_syment *sym;
-      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;
+  /* 0x0a: Same as R_RBR.  */
+  HOWTO (R_BR,			/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 26,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_BR",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x03fffffc,		/* src_mask */
+	 0x03fffffc,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-      /* 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.  */
-      if (rel->r_type == R_REF)
-	continue;
+  EMPTY_HOWTO (0xb),
 
-      /* 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.  */
-	      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 (info->unresolved_syms_in_objects != RM_IGNORE
-		  && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
-                info->callbacks->undefined_symbol
-		  (info, h->root.root.string, input_bfd, input_section,
-		   rel->r_vaddr - input_section->vma,
-		   info->unresolved_syms_in_objects == RM_DIAGNOSE
-		   && !info->warn_unresolved_syms);
-
-	      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
-		{
-		  BFD_ASSERT (bfd_link_relocatable (info)
-			      || (h->flags & XCOFF_DEF_DYNAMIC) != 0
-			      || (h->flags & XCOFF_IMPORT) != 0);
-		}
-	    }
-	}
-
-      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
-	  || !((*xcoff64_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->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 (((*xcoff_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 = NULL;
-	    }
-	  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);
-
-	  (*info->callbacks->reloc_overflow)
-	    (info, (h ? &h->root : NULL), name, reloc_type_name,
-	     (bfd_vma) 0, input_bfd, input_section,
-	     rel->r_vaddr - input_section->vma);
-	}
-
-      /* 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;
-}
-
-\f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
-
-reloc_howto_type xcoff64_howto_table[] =
-{
-  /* 0x00: Standard 64 bit relocation.  */
-  HOWTO (R_POS,			/* type */
+  /* 0x0c: Same as R_POS.  */
+  HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
 	 64,			/* bitsize */
@@ -1021,44 +889,50 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_POS_64",		/* name */
+	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
 	 MINUS_ONE,		/* src_mask */
 	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x01: 64 bit relocation, but store negative value.  */
-  HOWTO (R_NEG,			/* type */
+  /* 0x0d: Same as R_POS.  */
+  HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 -4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
 	 64,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_NEG",		/* name */
+	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 MINUS_ONE,		/* src_mask */
 	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x02: 32 bit PC relative relocation.  */
-  HOWTO (R_REL,			/* type */
+  EMPTY_HOWTO (0xe),
+
+  /* 0x0f: Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
+  HOWTO (R_REF,			/* type */
 	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 TRUE,			/* pc_relative */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 1,			/* bitsize */
+	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
+	 complain_overflow_dont, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_REL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 "R_REF",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x03: 16 bit TOC relative relocation.  */
-  HOWTO (R_TOC,			/* type */
+  EMPTY_HOWTO (0x10),
+  EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
+
+  /* 0x13: Same as R_TOC  */
+  HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1066,14 +940,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TOC",		/* name */
+	 "R_TRLA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.	*/
-  HOWTO (R_RTB,			/* type */
+  /* 0x14: Modifiable relative branch.  */
+  HOWTO (R_RRTBI,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -1081,14 +955,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_RRTBI",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffffffff,		/* src_mask */
 	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x05: External TOC relative symbol.  */
-  HOWTO (R_GL,			/* type */
+  /* 0x15: Modifiable absolute branch.  */
+  HOWTO (R_RRTBA,		/* type */
+	 1,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_RRTBA",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  /* 0x16: Modifiable call absolute indirect.  */
+  HOWTO (R_CAI,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1096,14 +985,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_GL",		/* name */
+	 "R_CAI",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x06: Local TOC relative symbol.	 */
-  HOWTO (R_TCL,			/* type */
+  /* 0x17: Modifiable call relative.  */
+  HOWTO (R_CREL,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1111,16 +1000,14 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TCL",		/* name */
+	 "R_CREL",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (7),
-
-  /* 0x08: Non modifiable absolute branch.  */
-  HOWTO (R_BA,			/* type */
+  /* 0x18: Modifiable branch absolute.  */
+  HOWTO (R_RBA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 26,			/* bitsize */
@@ -1128,33 +1015,44 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_BA_26",		/* name */
+	 "R_RBA",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0x03fffffc,		/* src_mask */
 	 0x03fffffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (9),
+  /* 0x19: Modifiable branch absolute.  */
+  HOWTO (R_RBAC,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_RBAC",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
-  /* 0x0a: Non modifiable relative branch.  */
-  HOWTO (R_BR,			/* type */
+  /* 0x1a: Modifiable branch relative.  */
+  HOWTO (R_RBR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 26,			/* bitsize */
-	 TRUE,			/* pc_relative */
+	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_BR",		/* name */
+	 "R_RBR_26",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0x03fffffc,		/* src_mask */
 	 0x03fffffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (0xb),
-
-  /* 0x0c: Indirect load.  */
-  HOWTO (R_RL,			/* type */
+  /* 0x1b: Modifiable branch absolute.  */
+  HOWTO (R_RBRC,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1162,49 +1060,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RL",		/* name */
+	 "R_RBRC",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
-  HOWTO (R_RLA,			/* type */
+  /* 0x1c: Standard 32 bit relocation.  */
+  HOWTO (R_POS,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RLA",		/* name */
+	 "R_POS_32",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  EMPTY_HOWTO (0xe),
-
-  /* 0x0f: Non-relocating reference.  Bitsize is 1 so that r_rsize is 0.  */
-  HOWTO (R_REF,			/* type */
-	 0,			/* rightshift */
-	 0,			/* size (0 = byte, 1 = short, 2 = long) */
-	 1,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_dont, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_REF",		/* name */
-	 FALSE,			/* partial_inplace */
-	 0,			/* src_mask */
-	 0,			/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  EMPTY_HOWTO (0x10),
-  EMPTY_HOWTO (0x11),
-
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
+  /* 0x1d: 16 bit Non modifiable absolute branch.  */
+  HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1212,59 +1090,29 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_TRL",		/* name */
+	 "R_BA_16",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xfffc,		/* src_mask */
+	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x13: TOC relative load address.	 */
-  HOWTO (R_TRLA,		/* type */
+  /* 0x1e: Modifiable branch relative.  */
+  HOWTO (R_RBR,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRLA",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x14: Modifiable relative branch.  */
-  HOWTO (R_RRTBI,		/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RRTBI",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x15: Modifiable absolute branch.  */
-  HOWTO (R_RRTBA,		/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
+	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
+	 complain_overflow_signed, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RRTBA",		/* name */
+	 "R_RBR_16",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xfffc,		/* src_mask */
+	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x16: Modifiable call absolute indirect.	 */
-  HOWTO (R_CAI,			/* type */
+  /* 0x1f: Modifiable branch absolute.  */
+  HOWTO (R_RBA,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
 	 16,			/* bitsize */
@@ -1272,228 +1120,433 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_CAI",		/* name */
+	 "R_RBA_16",		/* name */
 	 TRUE,			/* partial_inplace */
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x17: Modifiable call relative.	*/
-  HOWTO (R_CREL,		/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_CREL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
 
-  /* 0x18: Modifiable branch absolute.  */
-  HOWTO (R_RBA,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 26,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBA",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0x03fffffc,		/* src_mask */
-	 0x03fffffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
 
-  /* 0x19: Modifiable branch absolute.  */
-  HOWTO (R_RBAC,		/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBAC",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
 
-  /* 0x1a: Modifiable branch relative.  */
-  HOWTO (R_RBR,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 26,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBR_26",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0x03fffffc,		/* src_mask */
-	 0x03fffffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
+};
+
+void
+xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
+{
+  if (internal->r_type > R_TOCL)
+    abort ();
+
+  /* Default howto layout works most of the time */
+  relent->howto = &xcoff64_howto_table[internal->r_type];
+
+  /* Special case some 16 bit reloc */
+  if (15 == (internal->r_size & 0x3f))
+    {
+      if (R_BA == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1d];
+      else if (R_RBR == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1e];
+      else if (R_RBA == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1f];
+    }
+  /* Special case 32 bit */
+  else if (31 == (internal->r_size & 0x3f))
+    {
+      if (R_POS == internal->r_type)
+	relent->howto = &xcoff64_howto_table[0x1c];
+    }
+
+  /* The r_size field of an XCOFF reloc encodes the bitsize of the
+     relocation, as well as indicating whether it is signed or not.
+     Doublecheck that the relocation information gathered from the
+     type matches this information.  The bitsize is not significant
+     for R_REF relocs.  */
+  if (relent->howto->dst_mask != 0
+      && (relent->howto->bitsize
+	  != ((unsigned int) internal->r_size & 0x3f) + 1))
+    abort ();
+}
+
+reloc_howto_type *
+xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+			   bfd_reloc_code_real_type code)
+{
+  switch (code)
+    {
+    case BFD_RELOC_PPC_B26:
+      return &xcoff64_howto_table[0xa];
+    case BFD_RELOC_PPC_BA16:
+      return &xcoff64_howto_table[0x1d];
+    case BFD_RELOC_PPC_BA26:
+      return &xcoff64_howto_table[8];
+    case BFD_RELOC_PPC_TOC16:
+      return &xcoff64_howto_table[3];
+    case BFD_RELOC_PPC_B16:
+      return &xcoff64_howto_table[0x1e];
+    case BFD_RELOC_32:
+    case BFD_RELOC_CTOR:
+      return &xcoff64_howto_table[0x1c];
+    case BFD_RELOC_64:
+      return &xcoff64_howto_table[0];
+    case BFD_RELOC_NONE:
+      return &xcoff64_howto_table[0xf];
+    default:
+      return NULL;
+    }
+}
+
+static reloc_howto_type *
+xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+			   const char *r_name)
+{
+  unsigned int i;
+
+  for (i = 0;
+       i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]);
+       i++)
+    if (xcoff64_howto_table[i].name != NULL
+	&& strcasecmp (xcoff64_howto_table[i].name, r_name) == 0)
+      return &xcoff64_howto_table[i];
+
+  return NULL;
+}
+
+static bfd_boolean
+xcoff64_reloc_type_br (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;
+  bfd_vma section_offset;
+
+  if (0 > rel->r_symndx)
+    return FALSE;
+
+  h = obj_xcoff_sym_hashes (input_bfd)[rel->r_symndx];
+  section_offset = rel->r_vaddr - input_section->vma;
+
+  /* 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
+	  || bfd_link_hash_defweak == h->root.type)
+      && section_offset + 8 <= input_section->size)
+    {
+      bfd_byte *pnext;
+      unsigned long next;
+
+      pnext = contents + section_offset + 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, 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;
+    }
+
+  /* The original PC-relative relocation is biased by -r_vaddr, so adding
+     the value below will give the absolute target address.  */
+  *relocation = val + addend + rel->r_vaddr;
+
+  howto->src_mask &= ~3;
+  howto->dst_mask = howto->src_mask;
+
+  if (h != NULL
+      && (h->root.type == bfd_link_hash_defined
+	  || h->root.type == bfd_link_hash_defweak)
+      && bfd_is_abs_section (h->root.u.def.section)
+      && section_offset + 4 <= input_section->size)
+    {
+      bfd_byte *ptr;
+      bfd_vma insn;
+
+      /* Turn the relative branch into an absolute one by setting the
+	 AA bit.  */
+      ptr = contents + section_offset;
+      insn = bfd_get_32 (input_bfd, ptr);
+      insn |= 2;
+      bfd_put_32 (input_bfd, insn, ptr);
+
+      /* Make the howto absolute too.  */
+      howto->pc_relative = FALSE;
+      howto->complain_on_overflow = complain_overflow_bitfield;
+    }
+  else
+    {
+      /* Use a PC-relative howto and subtract the instruction's address
+	 from the target address we calculated above.  */
+      howto->pc_relative = TRUE;
+      *relocation -= (input_section->output_section->vma
+		      + input_section->output_offset
+		      + section_offset);
+    }
+  return TRUE;
+}
+
+/* This is the relocation function for the PowerPC64.
+   See xcoff_ppc_relocation_section for more information. */
+
+bfd_boolean
+xcoff64_ppc_relocate_section (bfd *output_bfd,
+			      struct bfd_link_info *info,
+			      bfd *input_bfd,
+			      asection *input_section,
+			      bfd_byte *contents,
+			      struct internal_reloc *relocs,
+			      struct internal_syment *syms,
+			      asection **sections)
+{
+  struct internal_reloc *rel;
+  struct internal_reloc *relend;
+
+  rel = relocs;
+  relend = rel + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      long symndx;
+      struct xcoff_link_hash_entry *h;
+      struct internal_syment *sym;
+      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
+	 the csect including the symbol which it references.  */
+      if (rel->r_type == R_REF)
+	continue;
+
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+	 This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.	 */
+      memcpy (&howto, &xcoff64_howto_table[rel->r_type], sizeof (howto));
+      if (howto.bitsize != (rel->r_size & 0x3f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x3f) + 1;
+	    howto.size = howto.bitsize > 16 ? (howto.bitsize > 32 ? 4 : 2) : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
+      howto.complain_on_overflow = (rel->r_size & 0x80
+				    ? complain_overflow_signed
+				    : complain_overflow_bitfield);
+
+      /* symbol */
+      val = 0;
+      addend = 0;
+      h = NULL;
+      sym = NULL;
+      symndx = rel->r_symndx;
 
-  /* 0x1b: Modifiable branch absolute.  */
-  HOWTO (R_RBRC,		/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBRC",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      if (-1 != symndx)
+	{
+	  asection *sec;
+	  h = obj_xcoff_sym_hashes (input_bfd)[symndx];
+	  sym = syms + symndx;
+	  addend = - sym->n_value;
 
-  /* 0x1c: Standard 32 bit relocation.  */
-  HOWTO (R_POS,			/* type */
-	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_POS_32",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+	  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 (info->unresolved_syms_in_objects != RM_IGNORE
+		  && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
+		info->callbacks->undefined_symbol
+		  (info, h->root.root.string, input_bfd, input_section,
+		   rel->r_vaddr - input_section->vma,
+		   info->unresolved_syms_in_objects == RM_DIAGNOSE
+		   && !info->warn_unresolved_syms);
 
-  /* 0x1d: 16 bit Non modifiable absolute branch.  */
-  HOWTO (R_BA,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_BA_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xfffc,		/* src_mask */
-	 0xfffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+	      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
+		{
+		  BFD_ASSERT (bfd_link_relocatable (info)
+			      || (h->flags & XCOFF_DEF_DYNAMIC) != 0
+			      || (h->flags & XCOFF_IMPORT) != 0);
+		}
+	    }
+	}
 
-  /* 0x1e: Modifiable branch relative.  */
-  HOWTO (R_RBR,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 TRUE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_signed, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBR_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xfffc,		/* src_mask */
-	 0xfffc,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION
+	  || !((*xcoff64_calculate_relocation[rel->r_type])
+	      (input_bfd, input_section, output_bfd, rel, sym, &howto, val,
+	       addend, &relocation, contents)))
+	return FALSE;
 
-  /* 0x1f: Modifiable branch absolute.  */
-  HOWTO (R_RBA,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_RBA_16",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
+      /* address */
+      address = rel->r_vaddr - input_section->vma;
+      location = contents + address;
 
-};
+      if (address > input_section->size)
+	abort ();
 
-void
-xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
-{
-  if (internal->r_type > R_RBRC)
-    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);
 
-  /* Default howto layout works most of the time */
-  relent->howto = &xcoff64_howto_table[internal->r_type];
+      /* overflow.
 
-  /* Special case some 16 bit reloc */
-  if (15 == (internal->r_size & 0x3f))
-    {
-      if (R_BA == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1d];
-      else if (R_RBR == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1e];
-      else if (R_RBA == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1f];
-    }
-  /* Special case 32 bit */
-  else if (31 == (internal->r_size & 0x3f))
-    {
-      if (R_POS == internal->r_type)
-	relent->howto = &xcoff64_howto_table[0x1c];
-    }
+	 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.  */
 
-  /* The r_size field of an XCOFF reloc encodes the bitsize of the
-     relocation, as well as indicating whether it is signed or not.
-     Doublecheck that the relocation information gathered from the
-     type matches this information.  The bitsize is not significant
-     for R_REF relocs.  */
-  if (relent->howto->dst_mask != 0
-      && (relent->howto->bitsize
-	  != ((unsigned int) internal->r_size & 0x3f) + 1))
-    abort ();
-}
+      if (((*xcoff_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];
 
-reloc_howto_type *
-xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-			   bfd_reloc_code_real_type code)
-{
-  switch (code)
-    {
-    case BFD_RELOC_PPC_B26:
-      return &xcoff64_howto_table[0xa];
-    case BFD_RELOC_PPC_BA16:
-      return &xcoff64_howto_table[0x1d];
-    case BFD_RELOC_PPC_BA26:
-      return &xcoff64_howto_table[8];
-    case BFD_RELOC_PPC_TOC16:
-      return &xcoff64_howto_table[3];
-    case BFD_RELOC_PPC_B16:
-      return &xcoff64_howto_table[0x1e];
-    case BFD_RELOC_32:
-    case BFD_RELOC_CTOR:
-      return &xcoff64_howto_table[0x1c];
-    case BFD_RELOC_64:
-      return &xcoff64_howto_table[0];
-    case BFD_RELOC_NONE:
-      return &xcoff64_howto_table[0xf];
-    default:
-      return NULL;
-    }
-}
+	  if (symndx == -1)
+	    {
+	      name = "*ABS*";
+	    }
+	  if (h != NULL)
+	    {
+	      name = NULL;
+	    }
+	  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);
 
-static reloc_howto_type *
-xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-			   const char *r_name)
-{
-  unsigned int i;
+	  (*info->callbacks->reloc_overflow)
+	    (info, (h ? &h->root : NULL), name, reloc_type_name,
+	     (bfd_vma) 0, input_bfd, input_section,
+	     rel->r_vaddr - input_section->vma);
+	}
 
-  for (i = 0;
-       i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]);
-       i++)
-    if (xcoff64_howto_table[i].name != NULL
-	&& strcasecmp (xcoff64_howto_table[i].name, r_name) == 0)
-      return &xcoff64_howto_table[i];
+      /* 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));
 
-  return NULL;
+      /* 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;
 }
 
 /* PR 21786:  The PE/COFF standard does not require NUL termination for any of
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index e96f53260e..229e47c2ae 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -202,7 +202,7 @@ struct xcoff_backend_data_rec
 #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_CALCULATE_RELOCATION (0x32)
 #define XCOFF_MAX_COMPLAIN_OVERFLOW (4)
 /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
 #ifdef N_ONES
diff --git a/binutils/od-xcoff.c b/binutils/od-xcoff.c
index ad3235e643..f0d566b190 100644
--- a/binutils/od-xcoff.c
+++ b/binutils/od-xcoff.c
@@ -300,7 +300,7 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (NEG),
     RTYPE_ENTRY (REL),
     RTYPE_ENTRY (TOC),
-    RTYPE_ENTRY (RTB),
+    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (GL),
     RTYPE_ENTRY (TCL),
     RTYPE_ENTRY (BA),
@@ -308,7 +308,6 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (RL),
     RTYPE_ENTRY (RLA),
     RTYPE_ENTRY (REF),
-    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (TRLA),
     RTYPE_ENTRY (RRTBI),
     RTYPE_ENTRY (RRTBA),
diff --git a/include/coff/xcoff.h b/include/coff/xcoff.h
index 50ac0df20d..36651d4375 100644
--- a/include/coff/xcoff.h
+++ b/include/coff/xcoff.h
@@ -97,36 +97,35 @@
    The relocations are described in the function  
    xcoff[64]_ppc_relocate_section in coff64-rs6000.c and coff-rs6000.c  */
 
-#define R_POS   (0x00)
-#define R_NEG   (0x01)
-#define R_REL   (0x02)
-#define R_TOC   (0x03)
-#define R_RTB   (0x04)
-#define R_GL    (0x05)
-#define R_TCL   (0x06)
-#define R_BA    (0x08)
-#define R_BR    (0x0a)
-#define R_RL    (0x0c)
-#define R_RLA   (0x0d)
-#define R_REF   (0x0f)
-#define R_TRL   (0x12)
-#define R_TRLA  (0x13)
-#define R_RRTBI (0x14)
-#define R_RRTBA (0x15)
-#define R_CAI   (0x16)
-#define R_CREL  (0x17)
-#define R_RBA   (0x18)
-#define R_RBAC  (0x19)
-#define R_RBR   (0x1a)
-#define R_RBRC  (0x1b)
-#define R_TLS   (0x20)
+#define R_POS    (0x00)
+#define R_NEG    (0x01)
+#define R_REL    (0x02)
+#define R_TOC    (0x03)
+#define R_TRL    (0x04)
+#define R_GL     (0x05)
+#define R_TCL    (0x06)
+#define R_BA     (0x08)
+#define R_BR     (0x0a)
+#define R_RL     (0x0c)
+#define R_RLA    (0x0d)
+#define R_REF    (0x0f)
+#define R_TRLA   (0x13)
+#define R_RRTBI  (0x14)
+#define R_RRTBA  (0x15)
+#define R_CAI    (0x16)
+#define R_CREL   (0x17)
+#define R_RBA    (0x18)
+#define R_RBAC   (0x19)
+#define R_RBR    (0x1a)
+#define R_RBRC   (0x1b)
+#define R_TLS    (0x20)
 #define R_TLS_IE (0x21)
 #define R_TLS_LD (0x22)
 #define R_TLS_LE (0x23)
-#define R_TLSM  (0x24)
-#define R_TLSML (0x25)
-#define R_TOCU  (0x30)
-#define R_TOCL  (0x31)
+#define R_TLSM   (0x24)
+#define R_TLSML  (0x25)
+#define R_TOCU   (0x30)
+#define R_TOCL   (0x31)
 
 /* Storage class #defines, from /usr/include/storclass.h that are not already 
    defined in internal.h */
-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 4/6] aix: correct HOWTO table and add missing relocations
  2021-02-26  7:55   ` CHIGOT, CLEMENT
@ 2021-02-26 11:07     ` Alan Modra
  0 siblings, 0 replies; 5+ messages in thread
From: Alan Modra @ 2021-02-26 11:07 UTC (permalink / raw)
  To: CHIGOT, CLEMENT; +Cc: binutils

On Fri, Feb 26, 2021 at 07:55:09AM +0000, CHIGOT, CLEMENT wrote:
> Here is the new version with the fix you asked for. 
> I've also rebased it as I've removed the commit linked to r_symndx handlers.

You didn't split out moving functions around though.  Please split
this patch into two, the first doing moves without changing anything
else, the second being the functional changes.  It's difficult to
review as is by looking at the diff.  Also, since the patches are
renumbered and many need tweaking, it would be better if you post the
entire series again once you have fixed all the issues.  I wouldn't
want to apply the wrong pieces accidentally.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 4/6] aix: correct HOWTO table and add missing relocations
@ 2021-03-11 13:49 CHIGOT, CLEMENT
  0 siblings, 0 replies; 5+ messages in thread
From: CHIGOT, CLEMENT @ 2021-03-11 13:49 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

Since the last time AIX HOWTO table was modified, IBM has now
released an official documentation about XCOFF relocations.
This commit corrects the wrong ones and add some missing.
For now, the "custom" relocations made for xcoff_rtype2howto have
been kept.
The new relocations are still set as EMPTY_HOWTO because they will
be implemented in later commits.

In xcoff[64]_ppc_relocate_section, instead of recreating howto
from scratch, it's better to use the existing howto from the
table and fixing it according to r_size field.

bfd/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * coff-rs6000.c (xcoff_calculate_relocation): Correct and
        add new relocations.
        (xcoff_howto_table): Likewise.
        (xcoff_rtype2howto): Increase r_type maximum value.
        (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
        of create a new one from scratch.  Enable only some relocations
        to have a changing r_size.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
        (xcoff64_howto_table): Likewise.
        (xcoff64_rtype2howto): Likewise.
        (xcoff64_ppc_relocate_section): Likewise.
        * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.

binutils/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * od-xcoff.c: Replace RTB by TRL entry.

include/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * coff/xcoff.h (R_RTB): Removed.
        (R_TRL): Fix value.

---
Clément Chigot
ATOS Bull SAS
1 rue de Provence - 38432 Échirolles - France


[-- Attachment #2: 0004-aix-correct-HOWTO-table-and-add-missing-relocations.patch --]
[-- Type: application/octet-stream, Size: 34462 bytes --]

From 8f6871da9ccb15252d0abc865335b9be663c76db Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= <clement.chigot@atos.net>
Date: Thu, 11 Mar 2021 11:08:18 +0100
Subject: [PATCH 4/6] aix: correct HOWTO table and add missing relocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Since the last time AIX HOWTO table was modified, IBM has now
released an official documentation about XCOFF relocations.
This commit corrects the wrong ones and add some missing.
For now, the "custom" relocations made for xcoff_rtype2howto have
been kept.
The new relocations are still set as EMPTY_HOWTO because they will
be implemented in later commits.

In xcoff[64]_ppc_relocate_section, instead of recreating howto
from scratch, it's better to use the existing howto from the
table and fixing it according to r_size field.

bfd/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * coff-rs6000.c (xcoff_calculate_relocation): Correct and
        add new relocations.
        (xcoff_howto_table): Likewise.
        (xcoff_rtype2howto): Increase r_type maximum value.
        (xcoff_ppc_relocate_section): Reuse predefined HOWTOs instead
        of create a new one from scratch.  Enable only some relocations
        to have a changing r_size.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Likewise.
        (xcoff64_howto_table): Likewise.
        (xcoff64_rtype2howto): Likewise.
        (xcoff64_ppc_relocate_section): Likewise.
        * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Fix value.

binutils/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * od-xcoff.c: Replace RTB by TRL entry.

include/ChangeLog:
2021-03-11  Clément Chigot  <clement.chigot@atos.net>

        * coff/xcoff.h (R_RTB): Removed.
        (R_TRL): Fix value.
---
 bfd/coff-rs6000.c    | 322 +++++++++++++++++++++++++++----------------
 bfd/coff64-rs6000.c  | 233 +++++++++++++++++++------------
 bfd/libxcoff.h       |   2 +-
 binutils/od-xcoff.c  |   3 +-
 include/coff/xcoff.h |  53 ++++---
 5 files changed, 374 insertions(+), 239 deletions(-)

diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 54fbf58e3ae..45116984fd4 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -158,34 +158,56 @@ static xcoff_complain_function xcoff_complain_overflow_unsigned_func;
 xcoff_reloc_function *const
 xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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_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_toc,  /* R_TRL   (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, /*         (0x10) */
+  xcoff_reloc_type_fail, /*         (0x11) */
+  xcoff_reloc_type_fail, /*         (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_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) */
+  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) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 xcoff_complain_function *const
@@ -652,11 +674,18 @@ _bfd_xcoff_swap_aux_out (bfd *abfd, void * inp, int type, int in_class,
   return bfd_coff_auxesz (abfd);
 }
 \f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
+/* The XCOFF reloc table.
+   XCOFF relocations aren't defined only by the type field r_type.
+   The bitsize and whether they are signed or not, are defined by
+   r_size field.  Thus, it's complicated to create a constant
+   table reference every possible relocation.
+   This table contains the "default" relocation and few modified
+   relocations what were already there.  It's enough when
+   xcoff_rtype2howto is called.
+   For relocations from an input bfd to an output bfd, the default
+   relocation is retrieved and when manually adapted.
+
+   For now, it seems to be enought.  */
 
 reloc_howto_type xcoff_howto_table[] =
 {
@@ -720,19 +749,19 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.  */
-  HOWTO (R_RTB,			/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+  /* 0x04: Same as R_TOC  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* 0x05: External TOC relative symbol.  */
@@ -767,7 +796,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (7),
 
-  /* 0x08: Non modifiable absolute branch.  */
+  /* 0x08: Same as R_RBA.  */
   HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -784,7 +813,7 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (9),
 
-  /* 0x0a: Non modifiable relative branch.  */
+  /* 0x0a: Same as R_RBR.  */
   HOWTO (R_BR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -801,34 +830,34 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0xb),
 
-  /* 0x0c: Indirect load.  */
+  /* 0x0c: Same as R_POS.  */
   HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
+  /* 0x0d: Same as R_POS.  */
   HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   EMPTY_HOWTO (0xe),
@@ -850,23 +879,9 @@ reloc_howto_type xcoff_howto_table[] =
 
   EMPTY_HOWTO (0x10),
   EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
 
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x13: TOC relative load address.  */
+  /* 0x13: Same as R_TOC.  */
   HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -882,7 +897,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x14: Modifiable relative branch.  */
-  HOWTO (R_RRTBI,		 /* type */
+  HOWTO (R_RRTBI,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -897,7 +912,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 FALSE),		/* pcrel_offset */
 
   /* 0x15: Modifiable absolute branch.  */
-  HOWTO (R_RRTBA,		 /* type */
+  HOWTO (R_RRTBA,		/* type */
 	 1,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
 	 32,			/* bitsize */
@@ -1045,12 +1060,50 @@ reloc_howto_type xcoff_howto_table[] =
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
+
+  EMPTY_HOWTO (0x1f),
+
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
+
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
+
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
 };
 
 void
 xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_RBRC)
+  if (internal->r_type > R_TOCL)
     abort ();
 
   /* Default howto layout works most of the time */
@@ -3225,11 +3278,14 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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 original version was based on 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.
+   Now, IBM has released an official documentation about XCOFF
+   format:
+   https://www.ibm.com/support/knowledgecenter/ssw_aix_72/filesreference/XCOFF.html
 
    Unsupported r_type's
 
@@ -3243,6 +3299,15 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    quite figure out when this is useful.  These relocs are
    not defined by the PowerOpen ABI.
 
+   R_TOCU
+   R_TOCL
+   R_TLS
+   R_TLS_IE
+   R_TLS_LD
+   R_TLSLE
+
+   Not yet implemented.
+
    Supported r_type's
 
    R_POS:
@@ -3264,38 +3329,68 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    osym = oTOC + on
    oinsn = on + o
    so we must change insn by on - in.
+   This relocation allows the linker to perform optimizations
+   by transforming a load instruction into a add-immediate
+   when possible. The relocation is, then, changed to R_TRLA
+   in the output file.
+   TODO: Currently, the optimisation isn't implemented.
+
+   R_TRL:
+   TOC relative relocation.  Same as R_TOC, except that
+   the optimization isn't allowed
+
+   R_TRLA:
+   TOC relative relocation.  This is a TOC relative load
+   address instruction which have been changed to an add-
+   immediate instruction.
 
    R_GL:
    GL linkage relocation.  The value of this relocation
-   is the address of the entry in the TOC section.
+   is the address of the external symbol 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_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_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_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.
+
+   R_REF:
+   Not a relocation but a way to prevent the garbage
+   collector of AIX linker to remove symbols.
+   This is not needed in our case.
 
    R_BA:
-   Absolute branch.  We don't want to mess with the lower
-   two bits of the instruction.
+   The PowerOpen ABI says this is the same as R_RBA.
+
+   R_RBA:
+   Absolute branch which may be modified to become a
+   relative branch.
+
+   R_BR:
+   The PowerOpen ABI says this is the same as R_RBR.
+
+   R_RBR:
+   A relative branch which may be modified to become an
+   absolute branch.
 
    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_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_RBAC:
    The PowerPC ABI defines this as an absolute branch to a
@@ -3307,29 +3402,6 @@ xcoff_complain_overflow_unsigned_func (bfd *input_bfd,
    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.
-
-   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.
 */
 
 bfd_boolean
@@ -3366,21 +3438,33 @@ xcoff_ppc_relocate_section (bfd *output_bfd,
       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;
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+	 This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.  */
+      memcpy (&howto, &xcoff_howto_table[rel->r_type], sizeof (howto));
+      if (howto.bitsize != (rel->r_size & 0x1f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x1f) + 1;
+	    howto.size = howto.bitsize > 16 ? 2 : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
       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;
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 3f74130da0d..4ea422c3258 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -180,34 +180,56 @@ static xcoff_reloc_function xcoff64_reloc_type_br;
 xcoff_reloc_function *const
 xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
 {
-  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) */
-  xcoff64_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) */
-  xcoff64_reloc_type_br, /* R_RBR   (0x1a) */
-  xcoff_reloc_type_ba,	 /* R_RBRC  (0x1b) */
+  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_toc,  /* R_TRL     (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) */
+  xcoff64_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_fail, /*           (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) */
+  xcoff64_reloc_type_br, /* R_RBR     (0x1a) */
+  xcoff_reloc_type_ba,   /* R_RBRC    (0x1b) */
+  xcoff_reloc_type_fail, /*           (0x1c) */
+  xcoff_reloc_type_fail, /*           (0x1d) */
+  xcoff_reloc_type_fail, /*           (0x1e) */
+  xcoff_reloc_type_fail, /*           (0x1f) */
+  xcoff_reloc_type_fail, /* R_TLS     (0x20) */
+  xcoff_reloc_type_fail, /* R_TLS_IE  (0x21) */
+  xcoff_reloc_type_fail, /* R_TLS_LD  (0x22) */
+  xcoff_reloc_type_fail, /* R_TLS_LE  (0x23) */
+  xcoff_reloc_type_fail, /* R_TLSM    (0x24) */
+  xcoff_reloc_type_fail, /* R_TLSML   (0x25) */
+  xcoff_reloc_type_fail, /*           (0x26) */
+  xcoff_reloc_type_fail, /*           (0x27) */
+  xcoff_reloc_type_fail, /*           (0x28) */
+  xcoff_reloc_type_fail, /*           (0x29) */
+  xcoff_reloc_type_fail, /*           (0x2a) */
+  xcoff_reloc_type_fail, /*           (0x2b) */
+  xcoff_reloc_type_fail, /*           (0x2c) */
+  xcoff_reloc_type_fail, /*           (0x2d) */
+  xcoff_reloc_type_fail, /*           (0x2e) */
+  xcoff_reloc_type_fail, /*           (0x2f) */
+  xcoff_reloc_type_fail, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_fail, /* R_TOCL    (0x31) */
 };
 
 /* coffcode.h needs these to be defined.  */
@@ -816,11 +838,8 @@ xcoff64_reloc_type_br (bfd *input_bfd,
 
 
 \f
-/* The XCOFF reloc table.  Actually, XCOFF relocations specify the
-   bitsize and whether they are signed or not, along with a
-   conventional type.  This table is for the types, which are used for
-   different algorithms for putting in the reloc.  Many of these
-   relocs need special_function entries, which I have not written.  */
+/* The XCOFF reloc table.
+   Cf xcoff_howto_table comments.  */
 
 reloc_howto_type xcoff64_howto_table[] =
 {
@@ -854,19 +873,19 @@ reloc_howto_type xcoff64_howto_table[] =
 	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x02: 32 bit PC relative relocation.  */
+  /* 0x02: 64 bit PC relative relocation.  */
   HOWTO (R_REL,			/* type */
 	 0,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
 	 TRUE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_signed, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_REL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* 0x03: 16 bit TOC relative relocation.  */
@@ -884,19 +903,19 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x04: I don't really know what this is.	*/
-  HOWTO (R_RTB,			/* type */
-	 1,			/* rightshift */
-	 2,			/* size (0 = byte, 1 = short, 2 = long) */
-	 32,			/* bitsize */
+  /* 0x04: Same as R_TOC.  */
+  HOWTO (R_TRL,			/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
-	 "R_RTB",		/* name */
+	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffffffff,		/* src_mask */
-	 0xffffffff,		/* dst_mask */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   /* 0x05: External TOC relative symbol.  */
@@ -931,7 +950,7 @@ reloc_howto_type xcoff64_howto_table[] =
 
   EMPTY_HOWTO (7),
 
-  /* 0x08: Non modifiable absolute branch.  */
+  /* 0x08: Same as R_RBA.  */
   HOWTO (R_BA,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -948,7 +967,7 @@ reloc_howto_type xcoff64_howto_table[] =
 
   EMPTY_HOWTO (9),
 
-  /* 0x0a: Non modifiable relative branch.  */
+  /* 0x0a: Same as R_RBR.  */
   HOWTO (R_BR,			/* type */
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -965,34 +984,34 @@ reloc_howto_type xcoff64_howto_table[] =
 
   EMPTY_HOWTO (0xb),
 
-  /* 0x0c: Indirect load.  */
+  /* 0x0c: Same as R_POS.  */
   HOWTO (R_RL,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x0d: Load address.  */
+  /* 0x0d: Same as R_POS.  */
   HOWTO (R_RLA,			/* type */
 	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
+	 4,			/* size (0 = byte, 1 = short, 2 = long) */
+	 64,			/* bitsize */
 	 FALSE,			/* pc_relative */
 	 0,			/* bitpos */
 	 complain_overflow_bitfield, /* complain_on_overflow */
 	 0,			/* special_function */
 	 "R_RLA",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
+	 MINUS_ONE,		/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
   EMPTY_HOWTO (0xe),
@@ -1014,23 +1033,9 @@ reloc_howto_type xcoff64_howto_table[] =
 
   EMPTY_HOWTO (0x10),
   EMPTY_HOWTO (0x11),
+  EMPTY_HOWTO (0x12),
 
-  /* 0x12: TOC relative indirect load.  */
-  HOWTO (R_TRL,			/* type */
-	 0,			/* rightshift */
-	 1,			/* size (0 = byte, 1 = short, 2 = long) */
-	 16,			/* bitsize */
-	 FALSE,			/* pc_relative */
-	 0,			/* bitpos */
-	 complain_overflow_bitfield, /* complain_on_overflow */
-	 0,			/* special_function */
-	 "R_TRL",		/* name */
-	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
-	 0xffff,		/* dst_mask */
-	 FALSE),		/* pcrel_offset */
-
-  /* 0x13: TOC relative load address.	 */
+  /* 0x13: Same as R_TOC  */
   HOWTO (R_TRLA,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -1075,7 +1080,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0xffffffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x16: Modifiable call absolute indirect.	 */
+  /* 0x16: Modifiable call absolute indirect.  */
   HOWTO (R_CAI,			/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -1090,7 +1095,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* 0x17: Modifiable call relative.	*/
+  /* 0x17: Modifiable call relative.  */
   HOWTO (R_CREL,		/* type */
 	 0,			/* rightshift */
 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -1225,12 +1230,48 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+
+  /* 0x20: General-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS),
+
+  /* 0x21: Initial-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_IE),
+
+  /* 0x22: Local-dynamic TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LD),
+
+  /* 0x23: Local-exec TLS relocation.  */
+  EMPTY_HOWTO (R_TLS_LE),
+
+  /* 0x24: TLS relocation.  */
+  EMPTY_HOWTO(R_TLSM),
+
+  /* 0x25: TLS module relocation.  */
+  EMPTY_HOWTO(R_TLSML),
+
+  EMPTY_HOWTO(0x26),
+  EMPTY_HOWTO(0x27),
+  EMPTY_HOWTO(0x28),
+  EMPTY_HOWTO(0x29),
+  EMPTY_HOWTO(0x2a),
+  EMPTY_HOWTO(0x2b),
+  EMPTY_HOWTO(0x2c),
+  EMPTY_HOWTO(0x2d),
+  EMPTY_HOWTO(0x2e),
+  EMPTY_HOWTO(0x2f),
+
+  /* 0x30: High-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCU),
+
+  /* 0x31: Low-order 16 bit TOC relative relocation.  */
+  EMPTY_HOWTO (R_TOCL),
+
 };
 
 void
 xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
 {
-  if (internal->r_type > R_RBRC)
+  if (internal->r_type > R_TOCL)
     abort ();
 
   /* Default howto layout works most of the time */
@@ -1345,21 +1386,33 @@ xcoff64_ppc_relocate_section (bfd *output_bfd,
       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;
+      /* Retrieve default value in HOWTO table and fix up according
+	 to r_size field, if it can be different.
+	 This should be made during relocation reading but the algorithms
+	 are expecting constant howtos.  */
+      memcpy (&howto, &xcoff64_howto_table[rel->r_type], sizeof (howto));
+      if (howto.bitsize != (rel->r_size & 0x3f) + 1)
+	{
+	  switch (rel->r_type) {
+	  case R_POS:
+	  case R_NEG:
+	    howto.bitsize = (rel->r_size & 0x3f) + 1;
+	    howto.size = howto.bitsize > 16 ? (howto.bitsize > 32 ? 4 : 2) : 1;
+	    howto.src_mask = howto.dst_mask = N_ONES (howto.bitsize);
+	    break;
+
+	  default:
+	    _bfd_error_handler
+	      (_("%pB: relocatation (%d) at (0x%lx) has wrong"
+		 " r_rsize (0x%x)\n"),
+	       input_bfd, rel->r_type, rel->r_vaddr, rel->r_size);
+	    return FALSE;
+	  }
+	}
+
       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;
@@ -1394,7 +1447,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd,
 	    {
 	      if (info->unresolved_syms_in_objects != RM_IGNORE
 		  && (h->flags & XCOFF_WAS_UNDEFINED) != 0)
-                info->callbacks->undefined_symbol
+		info->callbacks->undefined_symbol
 		  (info, h->root.root.string, input_bfd, input_section,
 		   rel->r_vaddr - input_section->vma,
 		   info->unresolved_syms_in_objects == RM_DIAGNOSE
diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h
index e96f53260ef..229e47c2ae1 100644
--- a/bfd/libxcoff.h
+++ b/bfd/libxcoff.h
@@ -202,7 +202,7 @@ struct xcoff_backend_data_rec
 #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_CALCULATE_RELOCATION (0x32)
 #define XCOFF_MAX_COMPLAIN_OVERFLOW (4)
 /* N_ONES produces N one bits, without overflowing machine arithmetic.  */
 #ifdef N_ONES
diff --git a/binutils/od-xcoff.c b/binutils/od-xcoff.c
index ad3235e6436..f0d566b1902 100644
--- a/binutils/od-xcoff.c
+++ b/binutils/od-xcoff.c
@@ -300,7 +300,7 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (NEG),
     RTYPE_ENTRY (REL),
     RTYPE_ENTRY (TOC),
-    RTYPE_ENTRY (RTB),
+    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (GL),
     RTYPE_ENTRY (TCL),
     RTYPE_ENTRY (BA),
@@ -308,7 +308,6 @@ static const struct xlat_table rtype_xlat[] =
     RTYPE_ENTRY (RL),
     RTYPE_ENTRY (RLA),
     RTYPE_ENTRY (REF),
-    RTYPE_ENTRY (TRL),
     RTYPE_ENTRY (TRLA),
     RTYPE_ENTRY (RRTBI),
     RTYPE_ENTRY (RRTBA),
diff --git a/include/coff/xcoff.h b/include/coff/xcoff.h
index 50ac0df20d6..36651d4375d 100644
--- a/include/coff/xcoff.h
+++ b/include/coff/xcoff.h
@@ -97,36 +97,35 @@
    The relocations are described in the function  
    xcoff[64]_ppc_relocate_section in coff64-rs6000.c and coff-rs6000.c  */
 
-#define R_POS   (0x00)
-#define R_NEG   (0x01)
-#define R_REL   (0x02)
-#define R_TOC   (0x03)
-#define R_RTB   (0x04)
-#define R_GL    (0x05)
-#define R_TCL   (0x06)
-#define R_BA    (0x08)
-#define R_BR    (0x0a)
-#define R_RL    (0x0c)
-#define R_RLA   (0x0d)
-#define R_REF   (0x0f)
-#define R_TRL   (0x12)
-#define R_TRLA  (0x13)
-#define R_RRTBI (0x14)
-#define R_RRTBA (0x15)
-#define R_CAI   (0x16)
-#define R_CREL  (0x17)
-#define R_RBA   (0x18)
-#define R_RBAC  (0x19)
-#define R_RBR   (0x1a)
-#define R_RBRC  (0x1b)
-#define R_TLS   (0x20)
+#define R_POS    (0x00)
+#define R_NEG    (0x01)
+#define R_REL    (0x02)
+#define R_TOC    (0x03)
+#define R_TRL    (0x04)
+#define R_GL     (0x05)
+#define R_TCL    (0x06)
+#define R_BA     (0x08)
+#define R_BR     (0x0a)
+#define R_RL     (0x0c)
+#define R_RLA    (0x0d)
+#define R_REF    (0x0f)
+#define R_TRLA   (0x13)
+#define R_RRTBI  (0x14)
+#define R_RRTBA  (0x15)
+#define R_CAI    (0x16)
+#define R_CREL   (0x17)
+#define R_RBA    (0x18)
+#define R_RBAC   (0x19)
+#define R_RBR    (0x1a)
+#define R_RBRC   (0x1b)
+#define R_TLS    (0x20)
 #define R_TLS_IE (0x21)
 #define R_TLS_LD (0x22)
 #define R_TLS_LE (0x23)
-#define R_TLSM  (0x24)
-#define R_TLSML (0x25)
-#define R_TOCU  (0x30)
-#define R_TOCL  (0x31)
+#define R_TLSM   (0x24)
+#define R_TLSML  (0x25)
+#define R_TOCU   (0x30)
+#define R_TOCL   (0x31)
 
 /* Storage class #defines, from /usr/include/storclass.h that are not already 
    defined in internal.h */
-- 
2.25.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-03-11 13:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-16  9:57 [PATCH 4/6] aix: correct HOWTO table and add missing relocations CHIGOT, CLEMENT
2021-02-22  7:17 ` Alan Modra
2021-02-26  7:55   ` CHIGOT, CLEMENT
2021-02-26 11:07     ` Alan Modra
2021-03-11 13:49 CHIGOT, CLEMENT

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).