public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
@ 2021-02-16  9:58 CHIGOT, CLEMENT
  2021-02-22  8:23 ` Alan Modra
  0 siblings, 1 reply; 6+ messages in thread
From: CHIGOT, CLEMENT @ 2021-02-16  9:58 UTC (permalink / raw)
  To: binutils

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

Implement support for largetoc on XCOFF.
R_TOCU and R_TOCL are referenced by the new BFD defines:
BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
A new toc storage class is added XMC_TE.

In gas, add a function to transform addis format used by AIX
"addis RT, D(RA)" into the ELF format "addis RT, RA, SI".

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

        * bfd-in2.h (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
        New defines
        * coff-rs6000.c (xcoff_calculate_relocation): Call
        xcoff_reloc_type_¨toc for R_TOCU and R_TOCL.
        (xcoff_howto_table): Add R_TOCU and R_TOCL howtos.
        (_bfd_xcoff_reloc_type_lookup): Add cases for
        BFD_RELOC_PPC_TOC16_{HI, LO}.
        (xcoff_reloc_type_toc): Implement R_TOCU and R_TOCL.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Call
        xcoff_reloc_type_toc for R_TOCU and R_TOCL.
        (xcoff64_howto_table): Add R_TOCU and R_TOCL howtos.
        (xcoff64_reloc_type_lookup): Add cases for
        BFD_RELOC_PPC_TOC16_{HI, LO}.
        (xcoff64_reloc_type_toc): Implement R_TOCU and R_TOCL.
        * libbfd.h (bfd_reloc_code_real_names): Add
        BFD_RELOC_PPC_TOC16_{HI, LO}.

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

        * config/tc-ppc.c (ppc_xcoff_suffix): New function.
        (MAP, MAP32, MAP64): New macros for XCOFF.
        (ppc_xcoff_fixup_addis): New function.
        (ppc_is_toc_sym): Handle XMC_TE.
        (fixup_size): Add cases for BFD_RELOC_PPC_TOC16_{HI,LO}.
        (md_assemble): Call ppc_xcoff_fixup_addis for XCOFF.
        (ppc_change_csect): Handle XMC_TE.
        (ppc_tc): Enable .tc symbols to have only a XMC_TC or XMC_TE
        storage class.
        (ppc_symbol_new_hook): Handle XMC_TE.
        (ppc_frob_symbol): Likewise.
        (ppc_fix_adjustable): Likewise.
        (md_apply_fix): Handle BFD_RELOC_PPC_TOC16_{HI,LO}.

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

        * scripttempl/aix.sc: Add .te to .data section.
        * testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
        Add aix-largetoc-1 test.
        * testsuite/ld-powerpc/aix-largetoc-1-32.d: New test.
        * testsuite/ld-powerpc/aix-largetoc-1-64.d: New test.
        * testsuite/ld-powerpc/aix-largetoc-1.ex: New test.
        * testsuite/ld-powerpc/aix-largetoc-1.s: New test.



Clément Chigot



[-- Attachment #2: 0005-aix-implement-R_TOCU-and-R_TOCL-relocations.patch --]
[-- Type: application/octet-stream, Size: 21030 bytes --]

From f5ada87cec82616c122a43ff750eb617457f3b0f 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:41:57 +0100
Subject: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Implement support for largetoc on XCOFF.
R_TOCU and R_TOCL are referenced by the new BFD defines:
BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
A new toc storage class is added XMC_TE.

In gas, add a function to transform addis format used by AIX
"addis RT, D(RA)" into the ELF format "addis RT, RA, SI".

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

        * bfd-in2.h (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
        New defines
        * coff-rs6000.c (xcoff_calculate_relocation): Call
        xcoff_reloc_type_¨toc for R_TOCU and R_TOCL.
        (xcoff_howto_table): Add R_TOCU and R_TOCL howtos.
        (_bfd_xcoff_reloc_type_lookup): Add cases for
        BFD_RELOC_PPC_TOC16_{HI, LO}.
        (xcoff_reloc_type_toc): Implement R_TOCU and R_TOCL.
        * coff64-rs6000.c (xcoff64_calculate_relocation): Call
        xcoff_reloc_type_toc for R_TOCU and R_TOCL.
        (xcoff64_howto_table): Add R_TOCU and R_TOCL howtos.
        (xcoff64_reloc_type_lookup): Add cases for
        BFD_RELOC_PPC_TOC16_{HI, LO}.
        (xcoff64_reloc_type_toc): Implement R_TOCU and R_TOCL.
        * libbfd.h (bfd_reloc_code_real_names): Add
        BFD_RELOC_PPC_TOC16_{HI, LO}.

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

        * config/tc-ppc.c (ppc_xcoff_suffix): New function.
        (MAP, MAP32, MAP64): New macros for XCOFF.
        (ppc_xcoff_fixup_addis): New function.
        (ppc_is_toc_sym): Handle XMC_TE.
        (fixup_size): Add cases for BFD_RELOC_PPC_TOC16_{HI,LO}.
        (md_assemble): Call ppc_xcoff_fixup_addis for XCOFF.
        (ppc_change_csect): Handle XMC_TE.
        (ppc_tc): Enable .tc symbols to have only a XMC_TC or XMC_TE
        storage class.
        (ppc_symbol_new_hook): Handle XMC_TE.
        (ppc_frob_symbol): Likewise.
        (ppc_fix_adjustable): Likewise.
        (md_apply_fix): Handle BFD_RELOC_PPC_TOC16_{HI,LO}.

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

        * scripttempl/aix.sc: Add .te to .data section.
        * testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
        Add aix-largetoc-1 test.
        * testsuite/ld-powerpc/aix-largetoc-1-32.d: New test.
        * testsuite/ld-powerpc/aix-largetoc-1-64.d: New test.
        * testsuite/ld-powerpc/aix-largetoc-1.ex: New test.
        * testsuite/ld-powerpc/aix-largetoc-1.s: New test.
---
 bfd/bfd-in2.h                               |   2 +
 bfd/coff-rs6000.c                           |  52 ++++++-
 bfd/coff64-rs6000.c                         |  37 ++++-
 bfd/libbfd.h                                |   2 +
 gas/config/tc-ppc.c                         | 142 ++++++++++++++++++--
 ld/scripttempl/aix.sc                       |   1 +
 ld/testsuite/ld-powerpc/aix-largetoc-1-32.d |  20 +++
 ld/testsuite/ld-powerpc/aix-largetoc-1-64.d |  20 +++
 ld/testsuite/ld-powerpc/aix-largetoc-1.ex   |   1 +
 ld/testsuite/ld-powerpc/aix-largetoc-1.s    |  25 ++++
 ld/testsuite/ld-powerpc/aix52.exp           |  21 +++
 11 files changed, 304 insertions(+), 19 deletions(-)
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1.ex
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1.s

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index d142bb5221..2b2c2c2b16 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2899,6 +2899,8 @@ instruction.  */
   BFD_RELOC_PPC_B26,
   BFD_RELOC_PPC_BA26,
   BFD_RELOC_PPC_TOC16,
+  BFD_RELOC_PPC_TOC16_HI,
+  BFD_RELOC_PPC_TOC16_LO,
   BFD_RELOC_PPC_B16,
   BFD_RELOC_PPC_B16_BRTAKEN,
   BFD_RELOC_PPC_B16_BRNTAKEN,
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index ae2738772b..2094f7f6a4 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -206,8 +206,8 @@ xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
   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_reloc_type_toc,  /* R_TOCU    (0x30) */
+  xcoff_reloc_type_toc,  /* R_TOCL    (0x31) */
 };
 
 xcoff_complain_function *const
@@ -1093,10 +1093,34 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO(0x2f),
 
   /* 0x30: High-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCU),
+  HOWTO (R_TOCU,		/* type */
+	 16,			/* 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_TOCU",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
   /* 0x31: Low-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCL),
+  HOWTO (R_TOCL,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
 };
 
@@ -1145,6 +1169,10 @@ _bfd_xcoff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
       return &xcoff_howto_table[3];
+    case BFD_RELOC_PPC_TOC16_HI:
+      return &xcoff_howto_table[0x30];
+    case BFD_RELOC_PPC_TOC16_LO:
+      return &xcoff_howto_table[0x31];
     case BFD_RELOC_16:
       /* Note that this relocation is only internally used by gas.  */
       return &xcoff_howto_table[0xc];
@@ -2937,6 +2965,12 @@ xcoff_reloc_type_toc (bfd *input_bfd,
 
   *relocation = ((val - xcoff_data (output_bfd)->toc)
 		 - (sym->n_value - xcoff_data (input_bfd)->toc));
+
+  if (rel->r_type == R_TOCU)
+    *relocation = (*relocation & 0xffff0000) >> 16 ;
+  if (rel->r_type == R_TOCL)
+    *relocation = *relocation & 0x0000ffff;
+
   return TRUE;
 }
 
@@ -3296,8 +3330,6 @@ 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
@@ -3399,6 +3431,14 @@ 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_TOCU:
+   Upper TOC relative relocation. The value is the
+   high-order 16 bit of a TOC relative relocation.
+
+   R_TOCL:
+   Lower TOC relative relocation. The value is the
+   low-order 16 bit of a TOC relative relocation.
 */
 
 bfd_boolean
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 55bb141626..4f74c339de 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -228,8 +228,8 @@ xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
   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_reloc_type_toc, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_toc, /* R_TOCL    (0x31) */
 };
 
 /* coffcode.h needs these to be defined.  */
@@ -1156,11 +1156,34 @@ reloc_howto_type xcoff64_howto_table[] =
   EMPTY_HOWTO(0x2e),
   EMPTY_HOWTO(0x2f),
 
-  /* 0x30: High-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCU),
+  HOWTO (R_TOCU,		/* type */
+	 16,			/* 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_TOCU",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
   /* 0x31: Low-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCL),
+  HOWTO (R_TOCL,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffff,		/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
 };
 
@@ -1215,6 +1238,10 @@ xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff64_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
       return &xcoff64_howto_table[3];
+    case BFD_RELOC_PPC_TOC16_HI:
+      return &xcoff64_howto_table[0x30];
+    case BFD_RELOC_PPC_TOC16_LO:
+      return &xcoff64_howto_table[0x31];
     case BFD_RELOC_16:
       /* Note that this relocation is only internally used by gas.  */
       return &xcoff64_howto_table[0xc];
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 7271a2ad5a..791e234058 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1460,6 +1460,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_PPC_B26",
   "BFD_RELOC_PPC_BA26",
   "BFD_RELOC_PPC_TOC16",
+  "BFD_RELOC_PPC_TOC16_HI",
+  "BFD_RELOC_PPC_TOC16_LO",
   "BFD_RELOC_PPC_B16",
   "BFD_RELOC_PPC_B16_BRTAKEN",
   "BFD_RELOC_PPC_B16_BRNTAKEN",
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 95000fd28a..2bc49237a2 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -2646,6 +2646,95 @@ ppc_elf_adjust_symtab (void)
     }
 }
 #endif /* OBJ_ELF */
+
+#ifdef OBJ_XCOFF
+/* Parse XCOFF relocations.  */
+static bfd_reloc_code_real_type
+ppc_xcoff_suffix (char **str_p)
+{
+  struct map_bfd {
+    const char *string;
+    unsigned int length : 8;
+    unsigned int valid32 : 1;
+    unsigned int valid64 : 1;
+    unsigned int reloc;
+  };
+
+  char ident[20];
+  char *str = *str_p;
+  char *str2;
+  int ch;
+  int len;
+  const struct map_bfd *ptr;
+
+#define MAP(str, reloc)   { str, sizeof (str) - 1, 1, 1, reloc }
+#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
+#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
+
+  static const struct map_bfd mapping[] = {
+    MAP ("l",			BFD_RELOC_PPC_TOC16_LO),
+    MAP ("u",			BFD_RELOC_PPC_TOC16_HI),
+  };
+
+  if (*str++ != '@')
+    return BFD_RELOC_NONE;
+
+  for (ch = *str, str2 = ident;
+       (str2 < ident + sizeof (ident) - 1
+	&& (ISALNUM (ch) || ch == '@'));
+       ch = *++str)
+    {
+      *str2++ = TOLOWER (ch);
+    }
+
+  *str2 = '\0';
+  len = str2 - ident;
+
+  ch = ident[0];
+  for (ptr = &mapping[0]; ptr->length > 0; ptr++)
+    if (ch == ptr->string[0]
+	&& len == ptr->length
+	&& memcmp (ident, ptr->string, ptr->length) == 0
+	&& (ppc_obj64 ? ptr->valid64 : ptr->valid32))
+      {
+	*str_p = str;
+	return (bfd_reloc_code_real_type) ptr->reloc;
+      }
+
+  return BFD_RELOC_NONE;
+}
+
+/* Restore XCOFF addis instruction to ELF format.
+   AIX often generates addis instructions using "addis RT, D(RA)"
+   format instead of the ELF "addis RT, RA, SI" one.  */
+static void
+ppc_xcoff_fixup_addis (char **str_p)
+{
+  char* d_e = strchr (*str_p, '(');
+  char *rt_e = strchr (*str_p, ',');
+  char *ra_e = strchr (*str_p, ')');
+  int rt_size =  rt_e - *str_p;
+  int d_size = d_e - rt_e - 1 /* ',' after RT */;
+  int ra_size = ra_e - d_e - 1 /* '(' after D */;
+
+  char *str2 = malloc (strlen (*str_p));
+
+  /* copy RT */
+  memcpy (str2, *str_p, rt_size);
+  str2[rt_size] = ',';
+
+  /* copy RA */
+  memcpy (str2 + rt_size + 1, d_e + 1, ra_size);
+  str2[rt_size + ra_size + 1] = ',';
+
+  /* copy D */
+  memcpy (str2 + rt_size + ra_size + 2, rt_e + 1, d_size);
+
+  strcpy (*str_p, str2);
+  free (str2);
+}
+
+#endif /* OBJ_XCOFF */
 \f
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
 /* See whether a symbol is in the TOC section.  */
@@ -2655,6 +2744,7 @@ ppc_is_toc_sym (symbolS *sym)
 {
 #ifdef OBJ_XCOFF
   return (symbol_get_tc (sym)->symbol_class == XMC_TC
+	  || symbol_get_tc (sym)->symbol_class == XMC_TE
 	  || symbol_get_tc (sym)->symbol_class == XMC_TC0);
 #endif
 #ifdef OBJ_ELF
@@ -2920,6 +3010,8 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
     case BFD_RELOC_PPC_GOT_TPREL16_HI:
     case BFD_RELOC_PPC_GOT_TPREL16_LO:
     case BFD_RELOC_PPC_TOC16:
+    case BFD_RELOC_PPC_TOC16_HI:
+    case BFD_RELOC_PPC_TOC16_LO:
     case BFD_RELOC_PPC_TPREL16:
     case BFD_RELOC_PPC_TPREL16_HA:
     case BFD_RELOC_PPC_TPREL16_HI:
@@ -3162,6 +3254,15 @@ md_assemble (char *str)
   while (ISSPACE (*str))
     ++str;
 
+#ifdef OBJ_XCOFF
+  /* AIX often generates addis instructions using "addis RT, D(RA)"
+     format instead of the classic "addis RT, RA, SI" one.
+     Restore it to the default format as it's the one encoded
+     in ppc opcodes.  */
+  if (!strcmp (opcode->name, "addis") && strchr (str, '(') != NULL)
+    ppc_xcoff_fixup_addis (&str);
+#endif
+
   /* PowerPC operands are just expressions.  The only real issue is
      that a few operand types are optional.  If an instruction has
      multiple optional operands and one is omitted, then all optional
@@ -3558,6 +3659,9 @@ md_assemble (char *str)
 		}
 	    }
 #endif /* OBJ_ELF */
+#ifdef OBJ_XCOFF
+	  reloc = ppc_xcoff_suffix (&str);
+#endif /* OBJ_XCOFF */
 
 	  if (reloc != BFD_RELOC_NONE)
 	    ;
@@ -4336,6 +4440,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
 	case XMC_RW:
 	case XMC_TC0:
 	case XMC_TC:
+	case XMC_TE:
 	case XMC_DS:
 	case XMC_UA:
 	case XMC_BS:
@@ -5383,7 +5488,21 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
     S_SET_SEGMENT (sym, now_seg);
     symbol_set_frag (sym, frag_now);
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
-    symbol_get_tc (sym)->symbol_class = XMC_TC;
+
+    /* AIX assembler seems to allow any storage class to be set in .tc.
+       But for now, only XMC_TC and XMC_TE are supported by us.  */
+    switch (symbol_get_tc (sym)->symbol_class)
+      {
+      case XMC_TC:
+      case XMC_TE:
+	break;
+
+      default:
+	as_bad (_(".tc with storage class %d not yet supported"),
+		symbol_get_tc (sym)->symbol_class);
+	ignore_rest_of_line ();
+	return;
+      }
     symbol_get_tc (sym)->output = 1;
 
     ppc_frob_label (sym);
@@ -5585,6 +5704,8 @@ ppc_symbol_new_hook (symbolS *sym)
 	tc->symbol_class = XMC_TB;
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
 	tc->symbol_class = XMC_TC0;
+      else if (strcmp (s, "TE]") == 0)
+	tc->symbol_class = XMC_TE;
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
@@ -5757,7 +5878,7 @@ ppc_frob_symbol (symbolS *sym)
 	  a->x_csect.x_scnlen.l = 0;
 	  a->x_csect.x_smtyp = XTY_ER;
 	}
-      else if (symbol_get_tc (sym)->symbol_class == XMC_TC)
+      else if (ppc_is_toc_sym (sym))
 	{
 	  symbolS *next;
 
@@ -5767,7 +5888,7 @@ ppc_frob_symbol (symbolS *sym)
 	  while (symbol_get_tc (next)->symbol_class == XMC_TC0)
 	    next = symbol_next (next);
 	  if (next == (symbolS *) NULL
-	      || symbol_get_tc (next)->symbol_class != XMC_TC)
+	      || (!ppc_is_toc_sym (next)))
 	    {
 	      if (ppc_after_toc_frag == (fragS *) NULL)
 		a->x_csect.x_scnlen.l = (bfd_section_size (data_section)
@@ -6053,7 +6174,8 @@ ppc_fix_adjustable (fixS *fix)
 
 	  if (sy_tc->symbol_class == XMC_TC0)
 	    continue;
-	  if (sy_tc->symbol_class != XMC_TC)
+	  if (sy_tc->symbol_class != XMC_TC
+	      && sy_tc->symbol_class != XMC_TE)
 	    break;
 	  if (val == resolve_symbol_value (sy))
 	    {
@@ -6072,6 +6194,7 @@ ppc_fix_adjustable (fixS *fix)
   if (tc->subseg == 0
       && tc->symbol_class != XMC_TC0
       && tc->symbol_class != XMC_TC
+      && tc->symbol_class != XMC_TE
       && symseg != bss_section
       /* Don't adjust if this is a reloc in the toc section.  */
       && (symseg != data_section
@@ -6516,8 +6639,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	  && (operand->insert == NULL || ppc_obj64)
 	  && fixP->fx_addsy != NULL
 	  && symbol_get_tc (fixP->fx_addsy)->subseg != 0
-	  && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC
-	  && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC0
+	  && !ppc_is_toc_sym (fixP->fx_addsy)
 	  && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
 	{
 	  value = fixP->fx_offset;
@@ -6531,7 +6653,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
        if (fixP->fx_r_type == BFD_RELOC_16
            && fixP->fx_addsy != NULL
            && ppc_is_toc_sym (fixP->fx_addsy))
-         fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+	 fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
 #endif
     }
 
@@ -6984,6 +7106,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	case BFD_RELOC_PPC_EMB_RELSDA:
 	case BFD_RELOC_PPC64_TOC:
 	case BFD_RELOC_PPC_TOC16:
+	case BFD_RELOC_PPC_TOC16_LO:
+	case BFD_RELOC_PPC_TOC16_HI:
 	case BFD_RELOC_PPC64_TOC16_LO:
 	case BFD_RELOC_PPC64_TOC16_HI:
 	case BFD_RELOC_PPC64_TOC16_HA:
@@ -7061,7 +7185,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	symbol_get_bfdsym (fixP->fx_addsy)->flags |= BSF_KEEP;
     }
 #else
-  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
+  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16
+      && fixP->fx_r_type != BFD_RELOC_PPC_TOC16_HI
+      && fixP->fx_r_type != BFD_RELOC_PPC_TOC16_LO)
     fixP->fx_addnumber = 0;
   else
     {
diff --git a/ld/scripttempl/aix.sc b/ld/scripttempl/aix.sc
index abf15fcb13..aa129d98fb 100644
--- a/ld/scripttempl/aix.sc
+++ b/ld/scripttempl/aix.sc
@@ -52,6 +52,7 @@ SECTIONS
     *(.tc0)
     *(.tc)
     *(.td)
+    *(.te)
     ${RELOCATING+PROVIDE (_edata = .);}
   }
   .bss : {
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d b/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
new file mode 100644
index 0000000000..8ab2e77cbd
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
@@ -0,0 +1,20 @@
+#source: aix-largetoc-1.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-largetoc-1.ex
+#objdump: -dr
+#target: powerpc*-*-aix*
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*:	3d 22 00 00 	cau     r9,r2,0
+.*: R_TOCU	a-.*
+.*:	39 29 00 00 	cal     r9,0\(r9\)
+.*: R_TOCL	a-.*
+.*:	3d 22 00 00 	cau     r9,r2,0
+.*: R_TOCU	b-.*
+.*:	39 29 00 04 	cal     r9,4\(r9\)
+.*: R_TOCL	b-.*
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d b/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
new file mode 100644
index 0000000000..247411a46b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
@@ -0,0 +1,20 @@
+#source: aix-largetoc-1.s
+#as: -a64
+#ld: -b64 -shared -bE:aix-largetoc-1.ex
+#objdump: -dr
+#target: powerpc*-*-aix*
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*:	3d 22 00 00 	addis   r9,r2,0
+.*: R_TOCU	a-.*
+.*:	39 29 00 00 	addi    r9,r9,0
+.*: R_TOCL	a-.*
+.*:	3d 22 00 00 	addis   r9,r2,0
+.*: R_TOCU	b-.*
+.*:	39 29 00 08 	addi    r9,r9,8
+.*: R_TOCL	b-.*
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1.ex b/ld/testsuite/ld-powerpc/aix-largetoc-1.ex
new file mode 100644
index 0000000000..257cc5642c
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1.ex
@@ -0,0 +1 @@
+foo
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1.s b/ld/testsuite/ld-powerpc/aix-largetoc-1.s
new file mode 100644
index 0000000000..278390300c
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1.s
@@ -0,0 +1,25 @@
+	.globl a
+	.csect .data[RW]
+a:
+	.long	1
+	.toc
+	.tc a[TE],a
+	.tc b[TE],a
+
+	.globl foo
+	.globl .foo
+	.csect foo[DS],3
+foo:
+	.if size == 32
+	.long .foo, TOC[tc0], 0
+	.else
+	.llong .foo, TOC[tc0], 0
+	.endif
+
+	.csect .text[PR]
+.foo:
+	addis 9,a[TE]@u(2)
+	la 9,a[TE]@l(9)
+
+	addis 9,b[TE]@u(2)
+	la 9,b[TE]@l(9)
diff --git a/ld/testsuite/ld-powerpc/aix52.exp b/ld/testsuite/ld-powerpc/aix52.exp
index d5e8b2f8af..ace006dac6 100644
--- a/ld/testsuite/ld-powerpc/aix52.exp
+++ b/ld/testsuite/ld-powerpc/aix52.exp
@@ -266,3 +266,24 @@ run_dump_test "aix-glink-3-32"
 run_dump_test "aix-glink-3-64"
 run_dump_test "aix-weak-3-32"
 run_dump_test "aix-weak-3-64"
+
+
+# Tests added for features in AIX 7+.
+
+if { ![istarget "*-*-aix\[7-9\]*"] } {
+    return
+}
+
+set aix7tests {
+    {"Large TOC test 1" "-shared -bE:aix-largetoc-1.ex"
+	"" {aix-largetoc-1.s}
+	{{objdump -dr aix-largetoc-1-SIZE.d}}
+	"aix-largetoc-1.so"}
+}
+
+foreach test $aix7tests {
+    foreach { name ldopts asopts sources tools output } $test {
+	run_aix_test 32 $name $ldopts $asopts $sources $tools $output
+	run_aix_test 64 $name $ldopts $asopts $sources $tools $output
+    }
+}
-- 
2.25.1


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

* Re: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
  2021-02-16  9:58 [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations CHIGOT, CLEMENT
@ 2021-02-22  8:23 ` Alan Modra
  2021-03-01  9:20   ` CHIGOT, CLEMENT
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Modra @ 2021-02-22  8:23 UTC (permalink / raw)
  To: CHIGOT, CLEMENT; +Cc: binutils

On Tue, Feb 16, 2021 at 09:58:55AM +0000, CHIGOT, CLEMENT wrote:
> Implement support for largetoc on XCOFF.
> R_TOCU and R_TOCL are referenced by the new BFD defines:
> BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
> A new toc storage class is added XMC_TE.
> 
> In gas, add a function to transform addis format used by AIX
> "addis RT, D(RA)" into the ELF format "addis RT, RA, SI".
> 
> bfd/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * bfd-in2.h (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
>         New defines
>         * coff-rs6000.c (xcoff_calculate_relocation): Call
>         xcoff_reloc_type_¨toc for R_TOCU and R_TOCL.
>         (xcoff_howto_table): Add R_TOCU and R_TOCL howtos.
>         (_bfd_xcoff_reloc_type_lookup): Add cases for
>         BFD_RELOC_PPC_TOC16_{HI, LO}.
>         (xcoff_reloc_type_toc): Implement R_TOCU and R_TOCL.
>         * coff64-rs6000.c (xcoff64_calculate_relocation): Call
>         xcoff_reloc_type_toc for R_TOCU and R_TOCL.
>         (xcoff64_howto_table): Add R_TOCU and R_TOCL howtos.
>         (xcoff64_reloc_type_lookup): Add cases for
>         BFD_RELOC_PPC_TOC16_{HI, LO}.
>         (xcoff64_reloc_type_toc): Implement R_TOCU and R_TOCL.
>         * libbfd.h (bfd_reloc_code_real_names): Add
>         BFD_RELOC_PPC_TOC16_{HI, LO}.
> 
> gas/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * config/tc-ppc.c (ppc_xcoff_suffix): New function.
>         (MAP, MAP32, MAP64): New macros for XCOFF.
>         (ppc_xcoff_fixup_addis): New function.
>         (ppc_is_toc_sym): Handle XMC_TE.
>         (fixup_size): Add cases for BFD_RELOC_PPC_TOC16_{HI,LO}.
>         (md_assemble): Call ppc_xcoff_fixup_addis for XCOFF.
>         (ppc_change_csect): Handle XMC_TE.
>         (ppc_tc): Enable .tc symbols to have only a XMC_TC or XMC_TE
>         storage class.
>         (ppc_symbol_new_hook): Handle XMC_TE.
>         (ppc_frob_symbol): Likewise.
>         (ppc_fix_adjustable): Likewise.
>         (md_apply_fix): Handle BFD_RELOC_PPC_TOC16_{HI,LO}.
> 
> ld/ChangeLog:
> 2020-11-20  Clément Chigot  <clement.chigot@atos.net>
> 
>         * scripttempl/aix.sc: Add .te to .data section.
>         * testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
>         Add aix-largetoc-1 test.
>         * testsuite/ld-powerpc/aix-largetoc-1-32.d: New test.
>         * testsuite/ld-powerpc/aix-largetoc-1-64.d: New test.
>         * testsuite/ld-powerpc/aix-largetoc-1.ex: New test.
>         * testsuite/ld-powerpc/aix-largetoc-1.s: New test.


+  if (rel->r_type == R_TOCU)
+    *relocation = (*relocation & 0xffff0000) >> 16 ;

Please double-check this.  The doc might say "the high-order 16 bits
of the displacement" but I suspect that isn't 100% correct.  If the
code in your testcases is proper usage, and I expect it is, then the
high 16 bits needs to be adjusted for the low 16 bits being signed.

You probably want:
   *relocation = ((*relocation + 0x8000) >> 16) & 0xffff;

+#ifdef OBJ_XCOFF
+  /* AIX often generates addis instructions using "addis RT, D(RA)"
+     format instead of the classic "addis RT, RA, SI" one.
+     Restore it to the default format as it's the one encoded
+     in ppc opcodes.  */
+  if (!strcmp (opcode->name, "addis") && strchr (str, '(') != NULL)
+    ppc_xcoff_fixup_addis (&str);
+#endif
+

Yikes, can't you tell people to fix their code?  I see so many ways
for this to go wrong, for example, if an expression calculating an
offset happened to use parentheses.  Also, ppc_xcoff_fixup_addis does
no sanity checking and can easily cause buffer overflows.

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
  2021-02-22  8:23 ` Alan Modra
@ 2021-03-01  9:20   ` CHIGOT, CLEMENT
  2021-03-01 11:33     ` Alan Modra
  0 siblings, 1 reply; 6+ messages in thread
From: CHIGOT, CLEMENT @ 2021-03-01  9:20 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

> +  if (rel->r_type == R_TOCU)
> +    *relocation = (*relocation & 0xffff0000) >> 16 ;
> 
> Please double-check this.  The doc might say "the high-order 16 bits
> of the displacement" but I suspect that isn't 100% correct.  If the
> code in your testcases is proper usage, and I expect it is, then the
> high 16 bits needs to be adjusted for the low 16 bits being signed.
> 
> You probably want:
>    *relocation = ((*relocation + 0x8000) >> 16) & 0xffff;

Yes, you're right. I wasn't aware of that. 

> +#ifdef OBJ_XCOFF
> +  /* AIX often generates addis instructions using "addis RT, D(RA)"
> +     format instead of the classic "addis RT, RA, SI" one.
> +     Restore it to the default format as it's the one encoded
> +     in ppc opcodes.  */
> +  if (!strcmp (opcode->name, "addis") && strchr (str, '(') != NULL)
> +    ppc_xcoff_fixup_addis (&str);
> +#endif
> +
> 
> Yikes, can't you tell people to fix their code?  I see so many ways
> for this to go wrong, for example, if an expression calculating an
> offset happened to use parentheses.  Also, ppc_xcoff_fixup_addis does
> no sanity checking and can easily cause buffer overflows.

Sadly no... AIX assembler wants the 3rd argument of an addis to be absolute. 
Thus, it's using a different syntax when it's not. 
To be precise, "addis RT, RA, SI" is allowed only if SI is an absolute and
"addis RT, D(RA)" is allowed only if D is a label/symbol having a relocation. 
Thus, I need to find a way to allow both in GNU as. 
I agree that my solution isn't the best one, but I didn't find any way to 
add an opcode in ppc-opc.c. 
If you have any idea how to do it properly, I would be glad. Otherwise, 
I will have to use this approach.. 

Clément  

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

* Re: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
  2021-03-01  9:20   ` CHIGOT, CLEMENT
@ 2021-03-01 11:33     ` Alan Modra
  2021-03-02  7:33       ` CHIGOT, CLEMENT
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Modra @ 2021-03-01 11:33 UTC (permalink / raw)
  To: CHIGOT, CLEMENT; +Cc: binutils

On Mon, Mar 01, 2021 at 09:20:26AM +0000, CHIGOT, CLEMENT wrote:
> > +  if (rel->r_type == R_TOCU)
> > +    *relocation = (*relocation & 0xffff0000) >> 16 ;
> > 
> > Please double-check this.  The doc might say "the high-order 16 bits
> > of the displacement" but I suspect that isn't 100% correct.  If the
> > code in your testcases is proper usage, and I expect it is, then the
> > high 16 bits needs to be adjusted for the low 16 bits being signed.
> > 
> > You probably want:
> >    *relocation = ((*relocation + 0x8000) >> 16) & 0xffff;
> 
> Yes, you're right. I wasn't aware of that. 
> 
> > +#ifdef OBJ_XCOFF
> > +  /* AIX often generates addis instructions using "addis RT, D(RA)"
> > +     format instead of the classic "addis RT, RA, SI" one.
> > +     Restore it to the default format as it's the one encoded
> > +     in ppc opcodes.  */
> > +  if (!strcmp (opcode->name, "addis") && strchr (str, '(') != NULL)
> > +    ppc_xcoff_fixup_addis (&str);
> > +#endif
> > +
> > 
> > Yikes, can't you tell people to fix their code?  I see so many ways
> > for this to go wrong, for example, if an expression calculating an
> > offset happened to use parentheses.  Also, ppc_xcoff_fixup_addis does
> > no sanity checking and can easily cause buffer overflows.
> 
> Sadly no... AIX assembler wants the 3rd argument of an addis to be absolute. 
> Thus, it's using a different syntax when it's not. 
> To be precise, "addis RT, RA, SI" is allowed only if SI is an absolute and
> "addis RT, D(RA)" is allowed only if D is a label/symbol having a relocation. 
> Thus, I need to find a way to allow both in GNU as. 
> I agree that my solution isn't the best one, but I didn't find any way to 
> add an opcode in ppc-opc.c. 
> If you have any idea how to do it properly, I would be glad. Otherwise, 
> I will have to use this approach.. 

The operand scanning isn't designed to support alternate operand
syntax like this, so you are correct that transforming the input is
likely the easiest way to support an ancient syntax not even mentioned
in current powerpc architecture books.  However, I'd like to see
better syntax checking before attempting the transform.  Something
like the following, perhaps.  Note the check for no comma past the
first one found, use of strrchr, and checks for empty strings.  Do you
need to treat "subis" the same way?

  if (strcmp (opcode->name, "addis") == 0)
    {
      char *rt_e = strchr (str, ',');
      if (rt_e != NULL
	  && strchr (rt_e + 1, ',') == NULL)
	{
	  char *d_e = strchr (rt_e + 1, '(');
	  if (d_e != NULL && d_e != rt_e + 1)
	    {
	      char *ra_e = strrchr (d_e + 1, ')');
	      if (ra_e != NULL && ra_e != d_e + 1)
		ppc_xcoff_fixup_addis (str, rt_e, d_e, ra_e);
	    }
	}
    }


-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
  2021-03-01 11:33     ` Alan Modra
@ 2021-03-02  7:33       ` CHIGOT, CLEMENT
  0 siblings, 0 replies; 6+ messages in thread
From: CHIGOT, CLEMENT @ 2021-03-02  7:33 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

> >  > +  if (rel->r_type == R_TOCU)
> > > +    *relocation = (*relocation & 0xffff0000) >> 16 ;
> > >
> > > Please double-check this.  The doc might say "the high-order 16 bits
> > > of the displacement" but I suspect that isn't 100% correct.  If the
> > > code in your testcases is proper usage, and I expect it is, then the
> > > high 16 bits needs to be adjusted for the low 16 bits being signed.
> > >
> > > You probably want:
> > >    *relocation = ((*relocation + 0x8000) >> 16) & 0xffff;
> >
> > Yes, you're right. I wasn't aware of that.
> >
> > > +#ifdef OBJ_XCOFF
> > > +  /* AIX often generates addis instructions using "addis RT, D(RA)"
> > > +     format instead of the classic "addis RT, RA, SI" one.
> > > +     Restore it to the default format as it's the one encoded
> > > +     in ppc opcodes.  */
> > > +  if (!strcmp (opcode->name, "addis") && strchr (str, '(') != NULL)
> > > +    ppc_xcoff_fixup_addis (&str);
> > > +#endif
> > > +
> > >
> > > Yikes, can't you tell people to fix their code?  I see so many ways
> > > for this to go wrong, for example, if an expression calculating an
> > > offset happened to use parentheses.  Also, ppc_xcoff_fixup_addis does
> > > no sanity checking and can easily cause buffer overflows.
> >
> > Sadly no... AIX assembler wants the 3rd argument of an addis to be absolute.
> > Thus, it's using a different syntax when it's not.
> > To be precise, "addis RT, RA, SI" is allowed only if SI is an absolute and
> > "addis RT, D(RA)" is allowed only if D is a label/symbol having a relocation.
> > Thus, I need to find a way to allow both in GNU as.
> > I agree that my solution isn't the best one, but I didn't find any way to
> > add an opcode in ppc-opc.c.
> > If you have any idea how to do it properly, I would be glad. Otherwise,
> > I will have to use this approach..
>
> The operand scanning isn't designed to support alternate operand
> syntax like this, so you are correct that transforming the input is
> likely the easiest way to support an ancient syntax not even mentioned
> in current powerpc architecture books.  However, I'd like to see
> better syntax checking before attempting the transform.  Something
> like the following, perhaps.  Note the check for no comma past the
> first one found, use of strrchr, and checks for empty strings.  Do you
> need to treat "subis" the same way?
>
>   if (strcmp (opcode->name, "addis") == 0)
>     {
>       char *rt_e = strchr (str, ',');
>       if (rt_e != NULL
>           && strchr (rt_e + 1, ',') == NULL)
>         {
>           char *d_e = strchr (rt_e + 1, '(');
>           if (d_e != NULL && d_e != rt_e + 1)
>             {
>               char *ra_e = strrchr (d_e + 1, ')');
>               if (ra_e != NULL && ra_e != d_e + 1)
>                 ppc_xcoff_fixup_addis (str, rt_e, d_e, ra_e);
>             }
>         }
>     }

AFAIK only addis as this strange syntax. By the way, in IBM website, they 
describe this syntax (https://www.ibm.com/support/knowledgecenter/ssw_aix_72/assembler/idalangref_add_imm_shift_inst.html) 
"The addis instruction has two syntax forms; however, the second form
is only valid when the R_TOCU relocation type is used in the D expression. "

Clément

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

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

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

Implement support for largetoc on XCOFF.
R_TOCU and R_TOCL are referenced by the new BFD defines:
BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
A new toc storage class is added XMC_TE.

In order to correctly handle R_TOCU, the logic behind
xcoff_reloc_type_toc is changed to compute the whole TOC offset
instead of just the difference between the "link" offset and the
"assembly" offset.

In gas, add a function to transform addis format used by AIX
"addis RT, D(RA)" into the ELF format "addis RT, RA, SI".

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

	* reloc.c (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
	New relocations.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
	* coff-rs6000.c (xcoff_calculate_relocation): Call
	xcoff_reloc_type_¨toc for R_TOCU and R_TOCL.
	(xcoff_howto_table): Remove src_mask for TOC relocations.
	Add R_TOCU and R_TOCL howtos.
	(_bfd_xcoff_reloc_type_lookup): Add cases for
	BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
	(xcoff_reloc_type_toc): Compute the whole offset.
	Implement R_TOCU and R_TOCL.
	* coff64-rs6000.c (xcoff64_calculate_relocation):
	Likewise.
	(xcoff64_howto_table): Likewise.
	(xcoff64_reloc_type_lookup): Likewise.

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

	* config/tc-ppc.c (ppc_xcoff_suffix): New function.
	(MAP, MAP32, MAP64): New macros for XCOFF.
	(ppc_xcoff_fixup_addis): New function.
	(ppc_is_toc_sym): Handle XMC_TE.
	(fixup_size): Add cases for BFD_RELOC_PPC_TOC16_HI and
	BFD_RELOC_PPC_TOC16_LO.
	(md_assemble): Call ppc_xcoff_fixup_addis for XCOFF.
	(ppc_change_csect): Handle XMC_TE.
	(ppc_tc): Enable .tc symbols to have only a XMC_TC or XMC_TE
	storage class.
	(ppc_symbol_new_hook): Handle XMC_TE.
	(ppc_frob_symbol): Likewise.
	(ppc_fix_adjustable): Likewise.
	(md_apply_fix): Handle BFD_RELOC_PPC_TOC16_HI and
	BFD_RELOC_PPC_TOC16_LO.

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

	* scripttempl/aix.sc: Add .te to .data section.
	* testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
	Add aix-largetoc-1 test.
	* testsuite/ld-powerpc/aix-largetoc-1-32.d: New test.
	* testsuite/ld-powerpc/aix-largetoc-1-64.d: New test.
	* testsuite/ld-powerpc/aix-largetoc-1.ex: New test.
	* testsuite/ld-powerpc/aix-largetoc-1.s: New test.


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


[-- Attachment #2: 0005-aix-implement-R_TOCU-and-R_TOCL-relocations.patch --]
[-- Type: application/octet-stream, Size: 24989 bytes --]

From 2a770ce09f25d40721a669721533b8218f65ddfd 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:19 +0100
Subject: [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Implement support for largetoc on XCOFF.
R_TOCU and R_TOCL are referenced by the new BFD defines:
BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
A new toc storage class is added XMC_TE.

In order to correctly handle R_TOCU, the logic behind
xcoff_reloc_type_toc is changed to compute the whole TOC offset
instead of just the difference between the "link" offset and the
"assembly" offset.

In gas, add a function to transform addis format used by AIX
"addis RT, D(RA)" into the ELF format "addis RT, RA, SI".

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

	* reloc.c (BFD_RELOC_PPC_TOC16_HI, BFD_RELOC_PPC_TOC16_LO):
	New relocations.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
	* coff-rs6000.c (xcoff_calculate_relocation): Call
	xcoff_reloc_type_¨toc for R_TOCU and R_TOCL.
	(xcoff_howto_table): Remove src_mask for TOC relocations.
	Add R_TOCU and R_TOCL howtos.
	(_bfd_xcoff_reloc_type_lookup): Add cases for
	BFD_RELOC_PPC_TOC16_HI and BFD_RELOC_PPC_TOC16_LO.
	(xcoff_reloc_type_toc): Compute the whole offset.
	Implement R_TOCU and R_TOCL.
	* coff64-rs6000.c (xcoff64_calculate_relocation):
	Likewise.
	(xcoff64_howto_table): Likewise.
	(xcoff64_reloc_type_lookup): Likewise.

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

	* config/tc-ppc.c (ppc_xcoff_suffix): New function.
	(MAP, MAP32, MAP64): New macros for XCOFF.
	(ppc_xcoff_fixup_addis): New function.
	(ppc_is_toc_sym): Handle XMC_TE.
	(fixup_size): Add cases for BFD_RELOC_PPC_TOC16_HI and
	BFD_RELOC_PPC_TOC16_LO.
	(md_assemble): Call ppc_xcoff_fixup_addis for XCOFF.
	(ppc_change_csect): Handle XMC_TE.
	(ppc_tc): Enable .tc symbols to have only a XMC_TC or XMC_TE
	storage class.
	(ppc_symbol_new_hook): Handle XMC_TE.
	(ppc_frob_symbol): Likewise.
	(ppc_fix_adjustable): Likewise.
	(md_apply_fix): Handle BFD_RELOC_PPC_TOC16_HI and
	BFD_RELOC_PPC_TOC16_LO.

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

	* scripttempl/aix.sc: Add .te to .data section.
	* testsuite/ld-powerpc/aix52.exp: Add test structure for AIX7+.
	Add aix-largetoc-1 test.
	* testsuite/ld-powerpc/aix-largetoc-1-32.d: New test.
	* testsuite/ld-powerpc/aix-largetoc-1-64.d: New test.
	* testsuite/ld-powerpc/aix-largetoc-1.ex: New test.
	* testsuite/ld-powerpc/aix-largetoc-1.s: New test.
---
 bfd/bfd-in2.h                               |   2 +
 bfd/coff-rs6000.c                           |  70 +++++++--
 bfd/coff64-rs6000.c                         |  45 ++++--
 bfd/libbfd.h                                |   2 +
 bfd/reloc.c                                 |   4 +
 gas/config/tc-ppc.c                         | 160 +++++++++++++++++++-
 ld/scripttempl/aix.sc                       |   1 +
 ld/testsuite/ld-powerpc/aix-largetoc-1-32.d |  20 +++
 ld/testsuite/ld-powerpc/aix-largetoc-1-64.d |  20 +++
 ld/testsuite/ld-powerpc/aix-largetoc-1.ex   |   1 +
 ld/testsuite/ld-powerpc/aix-largetoc-1.s    |  25 +++
 ld/testsuite/ld-powerpc/aix52.exp           |  21 +++
 12 files changed, 340 insertions(+), 31 deletions(-)
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1.ex
 create mode 100644 ld/testsuite/ld-powerpc/aix-largetoc-1.s

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index d142bb52213..9bd61b10e70 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2899,6 +2899,8 @@ instruction.  */
   BFD_RELOC_PPC_B26,
   BFD_RELOC_PPC_BA26,
   BFD_RELOC_PPC_TOC16,
+  BFD_RELOC_PPC_TOC16_LO,
+  BFD_RELOC_PPC_TOC16_HI,
   BFD_RELOC_PPC_B16,
   BFD_RELOC_PPC_B16_BRTAKEN,
   BFD_RELOC_PPC_B16_BRNTAKEN,
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 45116984fd4..f6b17a8e916 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -206,8 +206,8 @@ xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
   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_reloc_type_toc,  /* R_TOCU    (0x30) */
+  xcoff_reloc_type_toc,  /* R_TOCL    (0x31) */
 };
 
 xcoff_complain_function *const
@@ -745,7 +745,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 0,			/* special_function */
 	 "R_TOC",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -760,7 +760,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 0,			/* special_function */
 	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -775,7 +775,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 0,			/* special_function */
 	 "R_GL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -790,7 +790,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 0,			/* special_function */
 	 "R_TCL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -892,7 +892,7 @@ reloc_howto_type xcoff_howto_table[] =
 	 0,			/* special_function */
 	 "R_TRLA",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -1093,10 +1093,34 @@ reloc_howto_type xcoff_howto_table[] =
   EMPTY_HOWTO(0x2f),
 
   /* 0x30: High-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCU),
+  HOWTO (R_TOCU,		/* type */
+	 16,			/* 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_TOCU",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
   /* 0x31: Low-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCL),
+  HOWTO (R_TOCL,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
 };
 
@@ -1145,6 +1169,10 @@ _bfd_xcoff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
       return &xcoff_howto_table[3];
+    case BFD_RELOC_PPC_TOC16_HI:
+      return &xcoff_howto_table[0x30];
+    case BFD_RELOC_PPC_TOC16_LO:
+      return &xcoff_howto_table[0x31];
     case BFD_RELOC_PPC_B16:
       return &xcoff_howto_table[0x1d];
     case BFD_RELOC_32:
@@ -2904,7 +2932,7 @@ xcoff_reloc_type_toc (bfd *input_bfd,
 		      asection *input_section ATTRIBUTE_UNUSED,
 		      bfd *output_bfd,
 		      struct internal_reloc *rel,
-		      struct internal_syment *sym,
+		      struct internal_syment *sym ATTRIBUTE_UNUSED,
 		      struct reloc_howto_struct *howto ATTRIBUTE_UNUSED,
 		      bfd_vma val,
 		      bfd_vma addend ATTRIBUTE_UNUSED,
@@ -2935,8 +2963,16 @@ xcoff_reloc_type_toc (bfd *input_bfd,
 	      + h->toc_section->output_offset);
     }
 
-  *relocation = ((val - xcoff_data (output_bfd)->toc)
-		 - (sym->n_value - xcoff_data (input_bfd)->toc));
+  /* We can't use the preexisting value written down by the
+     assembly, as R_TOCU needs to be adjusted when the final
+     R_TOCL value is signed.  */
+  *relocation = val - xcoff_data (output_bfd)->toc;
+
+  if (rel->r_type == R_TOCU)
+    *relocation = ((*relocation + 0x8000) >> 16) & 0xffff;
+  if (rel->r_type == R_TOCL)
+    *relocation = *relocation & 0x0000ffff;
+
   return TRUE;
 }
 
@@ -3299,8 +3335,6 @@ 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
@@ -3402,6 +3436,14 @@ 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_TOCU:
+   Upper TOC relative relocation. The value is the
+   high-order 16 bit of a TOC relative relocation.
+
+   R_TOCL:
+   Lower TOC relative relocation. The value is the
+   low-order 16 bit of a TOC relative relocation.
 */
 
 bfd_boolean
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index 4ea422c3258..0f68faf14bc 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -228,8 +228,8 @@ xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] =
   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_reloc_type_toc, /* R_TOCU    (0x30) */
+  xcoff_reloc_type_toc, /* R_TOCL    (0x31) */
 };
 
 /* coffcode.h needs these to be defined.  */
@@ -899,7 +899,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* special_function */
 	 "R_TOC",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -914,7 +914,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* special_function */
 	 "R_TRL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -929,7 +929,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* special_function */
 	 "R_GL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -944,7 +944,7 @@ reloc_howto_type xcoff64_howto_table[] =
 	 0,			/* special_function */
 	 "R_TCL",		/* name */
 	 TRUE,			/* partial_inplace */
-	 0xffff,		/* src_mask */
+	 0,			/* src_mask */
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
@@ -1260,11 +1260,34 @@ reloc_howto_type xcoff64_howto_table[] =
   EMPTY_HOWTO(0x2e),
   EMPTY_HOWTO(0x2f),
 
-  /* 0x30: High-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCU),
+  HOWTO (R_TOCU,		/* type */
+	 16,			/* 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_TOCU",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
   /* 0x31: Low-order 16 bit TOC relative relocation.  */
-  EMPTY_HOWTO (R_TOCL),
+  HOWTO (R_TOCL,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 0,			/* special_function */
+	 "R_TOCL",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0xffff,		/* dst_mask */
+	 FALSE),		/* pcrel_offset */
 
 };
 
@@ -1319,6 +1342,10 @@ xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff64_howto_table[8];
     case BFD_RELOC_PPC_TOC16:
       return &xcoff64_howto_table[3];
+    case BFD_RELOC_PPC_TOC16_HI:
+      return &xcoff64_howto_table[0x30];
+    case BFD_RELOC_PPC_TOC16_LO:
+      return &xcoff64_howto_table[0x31];
     case BFD_RELOC_PPC_B16:
       return &xcoff64_howto_table[0x1e];
     case BFD_RELOC_32:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 3a481ea468f..62b6bf82c50 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1462,6 +1462,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_PPC_B26",
   "BFD_RELOC_PPC_BA26",
   "BFD_RELOC_PPC_TOC16",
+  "BFD_RELOC_PPC_TOC16_LO",
+  "BFD_RELOC_PPC_TOC16_HI",
   "BFD_RELOC_PPC_B16",
   "BFD_RELOC_PPC_B16_BRTAKEN",
   "BFD_RELOC_PPC_B16_BRNTAKEN",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 5ed7bb8e596..68645216c9d 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2736,6 +2736,10 @@ ENUMX
   BFD_RELOC_PPC_BA26
 ENUMX
   BFD_RELOC_PPC_TOC16
+ENUMX
+  BFD_RELOC_PPC_TOC16_LO
+ENUMX
+  BFD_RELOC_PPC_TOC16_HI
 ENUMX
   BFD_RELOC_PPC_B16
 ENUMX
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index 95000fd28a9..8475baf338d 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -2646,6 +2646,94 @@ ppc_elf_adjust_symtab (void)
     }
 }
 #endif /* OBJ_ELF */
+
+#ifdef OBJ_XCOFF
+/* Parse XCOFF relocations.  */
+static bfd_reloc_code_real_type
+ppc_xcoff_suffix (char **str_p)
+{
+  struct map_bfd {
+    const char *string;
+    unsigned int length : 8;
+    unsigned int valid32 : 1;
+    unsigned int valid64 : 1;
+    unsigned int reloc;
+  };
+
+  char ident[20];
+  char *str = *str_p;
+  char *str2;
+  int ch;
+  int len;
+  const struct map_bfd *ptr;
+
+#define MAP(str, reloc)   { str, sizeof (str) - 1, 1, 1, reloc }
+#define MAP32(str, reloc) { str, sizeof (str) - 1, 1, 0, reloc }
+#define MAP64(str, reloc) { str, sizeof (str) - 1, 0, 1, reloc }
+
+  static const struct map_bfd mapping[] = {
+    MAP ("l",			BFD_RELOC_PPC_TOC16_LO),
+    MAP ("u",			BFD_RELOC_PPC_TOC16_HI),
+  };
+
+  if (*str++ != '@')
+    return BFD_RELOC_NONE;
+
+  for (ch = *str, str2 = ident;
+       (str2 < ident + sizeof (ident) - 1
+	&& (ISALNUM (ch) || ch == '@'));
+       ch = *++str)
+    {
+      *str2++ = TOLOWER (ch);
+    }
+
+  *str2 = '\0';
+  len = str2 - ident;
+
+  ch = ident[0];
+  for (ptr = &mapping[0]; ptr->length > 0; ptr++)
+    if (ch == ptr->string[0]
+	&& len == ptr->length
+	&& memcmp (ident, ptr->string, ptr->length) == 0
+	&& (ppc_obj64 ? ptr->valid64 : ptr->valid32))
+      {
+	*str_p = str;
+	return (bfd_reloc_code_real_type) ptr->reloc;
+      }
+
+  return BFD_RELOC_NONE;
+}
+
+/* Restore XCOFF addis instruction to ELF format.
+   AIX often generates addis instructions using "addis RT, D(RA)"
+   format instead of the ELF "addis RT, RA, SI" one.  */
+static void
+ppc_xcoff_fixup_addis (char **str_p, char* rt_e, char *d_e, char* ra_e)
+{
+  int rt_size =  rt_e - *str_p;
+  int d_size = d_e - rt_e - 1 /* ',' after RT */;
+  int ra_size = ra_e - d_e - 1 /* '(' after D */;
+
+  char *str2 = xmalloc (strlen (*str_p) - 1);
+
+  /* copy RT */
+  memcpy (str2, *str_p, rt_size);
+  str2[rt_size] = ',';
+
+  /* copy RA */
+  memcpy (str2 + rt_size + 1, d_e + 1, ra_size);
+  str2[rt_size + ra_size + 1] = ',';
+
+  /* copy D */
+  memcpy (str2 + rt_size + ra_size + 2, rt_e + 1, d_size);
+
+  str2[strlen(*str_p)-1] = '\0';
+
+  strcpy (*str_p, str2);
+  free (str2);
+}
+
+#endif /* OBJ_XCOFF */
 \f
 #if defined (OBJ_XCOFF) || defined (OBJ_ELF)
 /* See whether a symbol is in the TOC section.  */
@@ -2655,6 +2743,7 @@ ppc_is_toc_sym (symbolS *sym)
 {
 #ifdef OBJ_XCOFF
   return (symbol_get_tc (sym)->symbol_class == XMC_TC
+	  || symbol_get_tc (sym)->symbol_class == XMC_TE
 	  || symbol_get_tc (sym)->symbol_class == XMC_TC0);
 #endif
 #ifdef OBJ_ELF
@@ -2920,6 +3009,8 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative)
     case BFD_RELOC_PPC_GOT_TPREL16_HI:
     case BFD_RELOC_PPC_GOT_TPREL16_LO:
     case BFD_RELOC_PPC_TOC16:
+    case BFD_RELOC_PPC_TOC16_HI:
+    case BFD_RELOC_PPC_TOC16_LO:
     case BFD_RELOC_PPC_TPREL16:
     case BFD_RELOC_PPC_TPREL16_HA:
     case BFD_RELOC_PPC_TPREL16_HI:
@@ -3162,6 +3253,28 @@ md_assemble (char *str)
   while (ISSPACE (*str))
     ++str;
 
+#ifdef OBJ_XCOFF
+  /* AIX often generates addis instructions using "addis RT, D(RA)"
+     format instead of the classic "addis RT, RA, SI" one.
+     Restore it to the default format as it's the one encoded
+     in ppc opcodes.  */
+    if (!strcmp (opcode->name, "addis"))
+    {
+      char *rt_e = strchr (str, ',');
+      if (rt_e != NULL
+          && strchr (rt_e + 1, ',') == NULL)
+        {
+          char *d_e = strchr (rt_e + 1, '(');
+          if (d_e != NULL && d_e != rt_e + 1)
+            {
+              char *ra_e = strrchr (d_e + 1, ')');
+              if (ra_e != NULL && ra_e != d_e + 1)
+                ppc_xcoff_fixup_addis (&str, rt_e, d_e, ra_e);
+            }
+        }
+    }
+#endif
+
   /* PowerPC operands are just expressions.  The only real issue is
      that a few operand types are optional.  If an instruction has
      multiple optional operands and one is omitted, then all optional
@@ -3558,6 +3671,9 @@ md_assemble (char *str)
 		}
 	    }
 #endif /* OBJ_ELF */
+#ifdef OBJ_XCOFF
+	  reloc = ppc_xcoff_suffix (&str);
+#endif /* OBJ_XCOFF */
 
 	  if (reloc != BFD_RELOC_NONE)
 	    ;
@@ -4336,6 +4452,7 @@ ppc_change_csect (symbolS *sym, offsetT align)
 	case XMC_RW:
 	case XMC_TC0:
 	case XMC_TC:
+	case XMC_TE:
 	case XMC_DS:
 	case XMC_UA:
 	case XMC_BS:
@@ -5383,7 +5500,21 @@ ppc_tc (int ignore ATTRIBUTE_UNUSED)
     S_SET_SEGMENT (sym, now_seg);
     symbol_set_frag (sym, frag_now);
     S_SET_VALUE (sym, (valueT) frag_now_fix ());
-    symbol_get_tc (sym)->symbol_class = XMC_TC;
+
+    /* AIX assembler seems to allow any storage class to be set in .tc.
+       But for now, only XMC_TC and XMC_TE are supported by us.  */
+    switch (symbol_get_tc (sym)->symbol_class)
+      {
+      case XMC_TC:
+      case XMC_TE:
+	break;
+
+      default:
+	as_bad (_(".tc with storage class %d not yet supported"),
+		symbol_get_tc (sym)->symbol_class);
+	ignore_rest_of_line ();
+	return;
+      }
     symbol_get_tc (sym)->output = 1;
 
     ppc_frob_label (sym);
@@ -5585,6 +5716,8 @@ ppc_symbol_new_hook (symbolS *sym)
 	tc->symbol_class = XMC_TB;
       else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0)
 	tc->symbol_class = XMC_TC0;
+      else if (strcmp (s, "TE]") == 0)
+	tc->symbol_class = XMC_TE;
       break;
     case 'U':
       if (strcmp (s, "UA]") == 0)
@@ -5757,7 +5890,7 @@ ppc_frob_symbol (symbolS *sym)
 	  a->x_csect.x_scnlen.l = 0;
 	  a->x_csect.x_smtyp = XTY_ER;
 	}
-      else if (symbol_get_tc (sym)->symbol_class == XMC_TC)
+      else if (ppc_is_toc_sym (sym))
 	{
 	  symbolS *next;
 
@@ -5767,7 +5900,7 @@ ppc_frob_symbol (symbolS *sym)
 	  while (symbol_get_tc (next)->symbol_class == XMC_TC0)
 	    next = symbol_next (next);
 	  if (next == (symbolS *) NULL
-	      || symbol_get_tc (next)->symbol_class != XMC_TC)
+	      || (!ppc_is_toc_sym (next)))
 	    {
 	      if (ppc_after_toc_frag == (fragS *) NULL)
 		a->x_csect.x_scnlen.l = (bfd_section_size (data_section)
@@ -6053,7 +6186,8 @@ ppc_fix_adjustable (fixS *fix)
 
 	  if (sy_tc->symbol_class == XMC_TC0)
 	    continue;
-	  if (sy_tc->symbol_class != XMC_TC)
+	  if (sy_tc->symbol_class != XMC_TC
+	      && sy_tc->symbol_class != XMC_TE)
 	    break;
 	  if (val == resolve_symbol_value (sy))
 	    {
@@ -6072,6 +6206,7 @@ ppc_fix_adjustable (fixS *fix)
   if (tc->subseg == 0
       && tc->symbol_class != XMC_TC0
       && tc->symbol_class != XMC_TC
+      && tc->symbol_class != XMC_TE
       && symseg != bss_section
       /* Don't adjust if this is a reloc in the toc section.  */
       && (symseg != data_section
@@ -6516,8 +6651,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	  && (operand->insert == NULL || ppc_obj64)
 	  && fixP->fx_addsy != NULL
 	  && symbol_get_tc (fixP->fx_addsy)->subseg != 0
-	  && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC
-	  && symbol_get_tc (fixP->fx_addsy)->symbol_class != XMC_TC0
+	  && !ppc_is_toc_sym (fixP->fx_addsy)
 	  && S_GET_SEGMENT (fixP->fx_addsy) != bss_section)
 	{
 	  value = fixP->fx_offset;
@@ -6531,7 +6665,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
        if (fixP->fx_r_type == BFD_RELOC_16
            && fixP->fx_addsy != NULL
            && ppc_is_toc_sym (fixP->fx_addsy))
-         fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
+	 fixP->fx_r_type = BFD_RELOC_PPC_TOC16;
 #endif
     }
 
@@ -6984,6 +7118,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	case BFD_RELOC_PPC_EMB_RELSDA:
 	case BFD_RELOC_PPC64_TOC:
 	case BFD_RELOC_PPC_TOC16:
+	case BFD_RELOC_PPC_TOC16_LO:
+	case BFD_RELOC_PPC_TOC16_HI:
 	case BFD_RELOC_PPC64_TOC16_LO:
 	case BFD_RELOC_PPC64_TOC16_HI:
 	case BFD_RELOC_PPC64_TOC16_HA:
@@ -7061,7 +7197,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	symbol_get_bfdsym (fixP->fx_addsy)->flags |= BSF_KEEP;
     }
 #else
-  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
+  if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16
+      && fixP->fx_r_type != BFD_RELOC_PPC_TOC16_HI
+      && fixP->fx_r_type != BFD_RELOC_PPC_TOC16_LO)
     fixP->fx_addnumber = 0;
   else
     {
@@ -7069,6 +7207,12 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 	 of the symbol.  */
       fixP->fx_addnumber = (- bfd_section_vma (S_GET_SEGMENT (fixP->fx_addsy))
 			    - S_GET_VALUE (ppc_toc_csect));
+
+      /* The high bits must be adjusted for the low bits being signed.  */
+      if (fixP->fx_r_type == BFD_RELOC_PPC_TOC16_HI) {
+	fixP->fx_addnumber += 0x8000;
+      }
+
       /* Set *valP to avoid errors.  */
       *valP = value;
     }
diff --git a/ld/scripttempl/aix.sc b/ld/scripttempl/aix.sc
index abf15fcb13b..aa129d98fb5 100644
--- a/ld/scripttempl/aix.sc
+++ b/ld/scripttempl/aix.sc
@@ -52,6 +52,7 @@ SECTIONS
     *(.tc0)
     *(.tc)
     *(.td)
+    *(.te)
     ${RELOCATING+PROVIDE (_edata = .);}
   }
   .bss : {
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d b/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
new file mode 100644
index 00000000000..8ab2e77cbd1
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1-32.d
@@ -0,0 +1,20 @@
+#source: aix-largetoc-1.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-largetoc-1.ex
+#objdump: -dr
+#target: powerpc*-*-aix*
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*:	3d 22 00 00 	cau     r9,r2,0
+.*: R_TOCU	a-.*
+.*:	39 29 00 00 	cal     r9,0\(r9\)
+.*: R_TOCL	a-.*
+.*:	3d 22 00 00 	cau     r9,r2,0
+.*: R_TOCU	b-.*
+.*:	39 29 00 04 	cal     r9,4\(r9\)
+.*: R_TOCL	b-.*
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d b/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
new file mode 100644
index 00000000000..247411a46b6
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1-64.d
@@ -0,0 +1,20 @@
+#source: aix-largetoc-1.s
+#as: -a64
+#ld: -b64 -shared -bE:aix-largetoc-1.ex
+#objdump: -dr
+#target: powerpc*-*-aix*
+
+.*
+
+Disassembly of section \.text:
+
+.* <\.foo>:
+.*:	3d 22 00 00 	addis   r9,r2,0
+.*: R_TOCU	a-.*
+.*:	39 29 00 00 	addi    r9,r9,0
+.*: R_TOCL	a-.*
+.*:	3d 22 00 00 	addis   r9,r2,0
+.*: R_TOCU	b-.*
+.*:	39 29 00 08 	addi    r9,r9,8
+.*: R_TOCL	b-.*
+#...
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1.ex b/ld/testsuite/ld-powerpc/aix-largetoc-1.ex
new file mode 100644
index 00000000000..257cc5642cb
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1.ex
@@ -0,0 +1 @@
+foo
diff --git a/ld/testsuite/ld-powerpc/aix-largetoc-1.s b/ld/testsuite/ld-powerpc/aix-largetoc-1.s
new file mode 100644
index 00000000000..278390300c2
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-largetoc-1.s
@@ -0,0 +1,25 @@
+	.globl a
+	.csect .data[RW]
+a:
+	.long	1
+	.toc
+	.tc a[TE],a
+	.tc b[TE],a
+
+	.globl foo
+	.globl .foo
+	.csect foo[DS],3
+foo:
+	.if size == 32
+	.long .foo, TOC[tc0], 0
+	.else
+	.llong .foo, TOC[tc0], 0
+	.endif
+
+	.csect .text[PR]
+.foo:
+	addis 9,a[TE]@u(2)
+	la 9,a[TE]@l(9)
+
+	addis 9,b[TE]@u(2)
+	la 9,b[TE]@l(9)
diff --git a/ld/testsuite/ld-powerpc/aix52.exp b/ld/testsuite/ld-powerpc/aix52.exp
index d5e8b2f8afd..ace006dac60 100644
--- a/ld/testsuite/ld-powerpc/aix52.exp
+++ b/ld/testsuite/ld-powerpc/aix52.exp
@@ -266,3 +266,24 @@ run_dump_test "aix-glink-3-32"
 run_dump_test "aix-glink-3-64"
 run_dump_test "aix-weak-3-32"
 run_dump_test "aix-weak-3-64"
+
+
+# Tests added for features in AIX 7+.
+
+if { ![istarget "*-*-aix\[7-9\]*"] } {
+    return
+}
+
+set aix7tests {
+    {"Large TOC test 1" "-shared -bE:aix-largetoc-1.ex"
+	"" {aix-largetoc-1.s}
+	{{objdump -dr aix-largetoc-1-SIZE.d}}
+	"aix-largetoc-1.so"}
+}
+
+foreach test $aix7tests {
+    foreach { name ldopts asopts sources tools output } $test {
+	run_aix_test 32 $name $ldopts $asopts $sources $tools $output
+	run_aix_test 64 $name $ldopts $asopts $sources $tools $output
+    }
+}
-- 
2.25.0


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

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

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-16  9:58 [PATCH 5/6] aix: implement R_TOCU and R_TOCL relocations CHIGOT, CLEMENT
2021-02-22  8:23 ` Alan Modra
2021-03-01  9:20   ` CHIGOT, CLEMENT
2021-03-01 11:33     ` Alan Modra
2021-03-02  7:33       ` CHIGOT, CLEMENT
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).