Rework the R_NEG support on both gas and ld for the PowerPC AIX targets, in order...
authorCl?ment Chigot <clement.chigot@atos.net>
Tue, 20 Apr 2021 13:40:43 +0000 (14:40 +0100)
committerNick Clifton <nickc@redhat.com>
Tue, 20 Apr 2021 13:40:43 +0000 (14:40 +0100)
bfd PR binutils/21700
* reloc.c (BFD_RELOC_PPC_NEG): New relocation.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.
* coff-rs6000.c (_bfd_xcoff_reloc_type_lookup): Add
BFD_RELOC_PPC_NEG handler.
(xcoff_reloc_type_neg): Correctly substract addend.
* coff64-rs6000.c (xcoff64_howto_table): Add R_NEG_32
howto.
(xcoff64_rtype2howto): Add handler for R_NEG_32.
(xcoff64_reloc_type_lookup): Add BFD_RELOC_PPC_NEG handler.
* xcofflink.c (xcoff_need_ldrel_p): Check output section
for R_POS-like relocations. New argument added.
(xcoff_mark): Adapt to new xcoff_need_ldrel_p argument.
(xcoff_link_input_bfd): Likewise.

gas * config/tc-ppc.c (ppc_get_csect_to_adjust): New function.
(ppc_fix_adjustable): Manage fx_subsy part.
(tc_gen_reloc): Create second relocation when both
fx_addsy and fx_subsy are provided.
* config/tc-ppc.h (RELOC_EXPANSION_POSSIBLE): New define.
(MAX_RELOC_EXPANSION): Likewise.
(TC_FORCE_RELOCATION_SUB_SAME): Likewise
(UNDEFINED_DIFFERENCE_OK): Likewise
* testsuite/gas/all/gas.exp: Skip difference between two
undefined symbols test.

ld * testsuite/ld-powerpc/aix52.exp: Add new test.
* testsuite/ld-powerpc/aix-neg-reloc-32.d: New test.
* testsuite/ld-powerpc/aix-neg-reloc-64.d: New test.
* testsuite/ld-powerpc/aix-neg-reloc.ex: New test.
* testsuite/ld-powerpc/aix-neg-reloc.s: New test.

16 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/coff-rs6000.c
bfd/coff64-rs6000.c
bfd/libbfd.h
bfd/reloc.c
bfd/xcofflink.c
gas/ChangeLog
gas/config/tc-ppc.c
gas/config/tc-ppc.h
ld/ChangeLog
ld/testsuite/ld-powerpc/aix-neg-reloc-32.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-neg-reloc-64.d [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-neg-reloc.ex [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix-neg-reloc.s [new file with mode: 0644]
ld/testsuite/ld-powerpc/aix52.exp

index 513d6e9d3f3a06aa176b62d35a8cd51157951758..972311bce482da3a013044e848b1e4a6df2408cd 100644 (file)
@@ -1,3 +1,21 @@
+2021-04-20  Clément Chigot  <clement.chigot@atos.net>
+
+       PR binutils/21700
+       * reloc.c (BFD_RELOC_PPC_NEG): New relocation.
+       * bfd-in2.h: Regenerate.
+       * libbfd.h: Regenerate.
+       * coff-rs6000.c (_bfd_xcoff_reloc_type_lookup): Add
+       BFD_RELOC_PPC_NEG handler.
+       (xcoff_reloc_type_neg): Correctly substract addend.
+       * coff64-rs6000.c (xcoff64_howto_table): Add R_NEG_32
+       howto.
+       (xcoff64_rtype2howto): Add handler for R_NEG_32.
+       (xcoff64_reloc_type_lookup): Add BFD_RELOC_PPC_NEG handler.
+       * xcofflink.c (xcoff_need_ldrel_p): Check output section
+       for R_POS-like relocations. New argument added.
+       (xcoff_mark): Adapt to new xcoff_need_ldrel_p argument.
+       (xcoff_link_input_bfd): Likewise.
+
 2021-04-16  Alan Modra  <amodra@gmail.com>
 
        PR 27567
index cdfb933e30d7a101d80f520e72a29acfcb73d2f3..d5780e46873c39979ccf229cb2897e0abf0459fa 100644 (file)
@@ -2921,6 +2921,7 @@ instruction.  */
   BFD_RELOC_PPC_VLE_SDAREL_HA16D,
   BFD_RELOC_PPC_16DX_HA,
   BFD_RELOC_PPC_REL16DX_HA,
+  BFD_RELOC_PPC_NEG,
   BFD_RELOC_PPC64_HIGHER,
   BFD_RELOC_PPC64_HIGHER_S,
   BFD_RELOC_PPC64_HIGHEST,
index 237c7ed6d66ff10de392ce2fa1dda4a281990fe3..7cfe4040fb790d0cea9928958c68b8b12968220b 100644 (file)
@@ -1253,6 +1253,8 @@ _bfd_xcoff_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff_howto_table[0];
     case BFD_RELOC_NONE:
       return &xcoff_howto_table[0xf];
+    case BFD_RELOC_PPC_NEG:
+      return &xcoff_howto_table[0x1];
     case BFD_RELOC_PPC_TLSGD:
       return &xcoff_howto_table[0x20];
     case BFD_RELOC_PPC_TLSIE:
@@ -2985,7 +2987,7 @@ xcoff_reloc_type_neg (bfd *input_bfd ATTRIBUTE_UNUSED,
                      bfd_vma *relocation,
                      bfd_byte *contents ATTRIBUTE_UNUSED)
 {
-  *relocation = addend - val;
+  *relocation = - val - addend;
   return true;
 }
 
index cc671b26b6a3b31dd0e5436cc3278db278d5bf8d..889534088f0d21d33b41087cfb2c005f7942394e 100644 (file)
@@ -1320,7 +1320,21 @@ reloc_howto_type xcoff64_howto_table[] =
         MINUS_ONE,             /* dst_mask */
         false),                /* pcrel_offset */
 
-  EMPTY_HOWTO(0x26),
+  /* 0x26: 32 bit relocation, but store negative value.  */
+  HOWTO (R_NEG,                        /* 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_NEG_32",            /* name */
+        true,                  /* partial_inplace */
+        MINUS_ONE,             /* src_mask */
+        MINUS_ONE,             /* dst_mask */
+        false),                /* pcrel_offset */
+
   EMPTY_HOWTO(0x27),
   EMPTY_HOWTO(0x28),
   EMPTY_HOWTO(0x29),
@@ -1386,6 +1400,9 @@ xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal)
     {
       if (R_POS == internal->r_type)
        relent->howto = &xcoff64_howto_table[0x1c];
+
+      if (R_NEG == internal->r_type)
+       relent->howto = &xcoff64_howto_table[0x26];
     }
 
   /* The r_size field of an XCOFF reloc encodes the bitsize of the
@@ -1426,6 +1443,8 @@ xcoff64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       return &xcoff64_howto_table[0];
     case BFD_RELOC_NONE:
       return &xcoff64_howto_table[0xf];
+    case BFD_RELOC_PPC_NEG:
+      return &xcoff64_howto_table[0x1];
     case BFD_RELOC_PPC64_TLSGD:
       return &xcoff64_howto_table[0x20];
     case BFD_RELOC_PPC64_TLSIE:
index f1d25d0ab1feb136d3e016d66ff006383a107b22..bee1a1f8e592e2b3d3f6fb410b3337bcc30aaa08 100644 (file)
@@ -1510,6 +1510,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_PPC_VLE_SDAREL_HA16D",
   "BFD_RELOC_PPC_16DX_HA",
   "BFD_RELOC_PPC_REL16DX_HA",
+  "BFD_RELOC_PPC_NEG",
   "BFD_RELOC_PPC64_HIGHER",
   "BFD_RELOC_PPC64_HIGHER_S",
   "BFD_RELOC_PPC64_HIGHEST",
index 2eb0758a82c9f63ddf2e0d62c2e14ccd887ad380..674b075a6b860f050b57036e9961dcc00543c8db 100644 (file)
@@ -2832,6 +2832,8 @@ ENUMX
   BFD_RELOC_PPC_16DX_HA
 ENUMX
   BFD_RELOC_PPC_REL16DX_HA
+ENUMX
+  BFD_RELOC_PPC_NEG
 ENUMX
   BFD_RELOC_PPC64_HIGHER
 ENUMX
index f0e0fe7aafc9e3991869b618289f838d91a1be4d..1607cd57d448b9b20fe7ee5db7c177e3bfc731d7 100644 (file)
@@ -2653,7 +2653,7 @@ xcoff_auto_export_p (struct bfd_link_info *info,
 
 static bool
 xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
-                   struct xcoff_link_hash_entry *h)
+                   struct xcoff_link_hash_entry *h, asection *ssec)
 {
   if (!xcoff_hash_table (info)->loader_section)
     return false;
@@ -2701,6 +2701,14 @@ xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel,
                  && bfd_is_abs_section (sec->output_section)))
            return false;
        }
+
+      /* Absolute relocations from read-only sections are forbidden
+        by AIX loader. However, they can appear in their section's
+         relocations.  */
+      if (ssec != NULL
+         && (ssec->output_section->flags & SEC_READONLY) != 0)
+       return false;
+
       return true;
 
     case R_TLS:
@@ -2989,7 +2997,7 @@ xcoff_mark (struct bfd_link_info *info, asection *sec)
 
              /* See if this reloc needs to be copied into the .loader
                 section.  */
-             if (xcoff_need_ldrel_p (info, rel, h))
+             if (xcoff_need_ldrel_p (info, rel, h, sec))
                {
                  ++xcoff_hash_table (info)->ldrel_count;
                  if (h != NULL)
@@ -4982,7 +4990,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *flinfo,
                }
 
              if ((o->flags & SEC_DEBUGGING) == 0
-                 && xcoff_need_ldrel_p (flinfo->info, irel, h))
+                 && xcoff_need_ldrel_p (flinfo->info, irel, h, o))
                {
                  asection *sec;
 
index 5111ace21d0d604ae76d0bb117bad0815c1a7fc3..c8ef5f3b54c1cebcb3246ae9309e9ad078c709c9 100644 (file)
@@ -1,3 +1,17 @@
+2021-04-20  Clément Chigot  <clement.chigot@atos.net>
+
+       PR binutils/21700
+       * config/tc-ppc.c (ppc_get_csect_to_adjust): New function.
+       (ppc_fix_adjustable): Manage fx_subsy part.
+       (tc_gen_reloc): Create second relocation when both
+       fx_addsy and fx_subsy are provided.
+       * config/tc-ppc.h (RELOC_EXPANSION_POSSIBLE): New define.
+       (MAX_RELOC_EXPANSION): Likewise.
+       (TC_FORCE_RELOCATION_SUB_SAME): Likewise
+       (UNDEFINED_DIFFERENCE_OK): Likewise
+       * testsuite/gas/all/gas.exp: Skip difference between two
+       undefined symbols test.
+
 2021-04-19  Nick Clifton  <nickc@redhat.com>
 
        * testsuite/gas/all/gas.exp: Add rs6000*-*-aix* to the list of
index c719b408b0eb59357f6d7e7022a9d041e181c318..7715fc53d0706f7312469805e82bf30ca022e63d 100644 (file)
@@ -6264,6 +6264,45 @@ md_pcrel_from_section (fixS *fixp, segT sec ATTRIBUTE_UNUSED)
 
 #ifdef OBJ_XCOFF
 
+/* Return the surrending csect for sym when possible.  */
+
+static symbolS*
+ppc_get_csect_to_adjust (symbolS *sym)
+{
+  if (sym == NULL)
+    return NULL;
+
+  valueT val = resolve_symbol_value (sym);
+  TC_SYMFIELD_TYPE *tc = symbol_get_tc (sym);
+  segT symseg = S_GET_SEGMENT (sym);
+
+  if (tc->subseg == 0
+      && tc->symbol_class != XMC_TC0
+      && tc->symbol_class != XMC_TC
+      && tc->symbol_class != XMC_TE
+      && symseg != bss_section
+      && symseg != ppc_xcoff_tbss_section.segment
+      /* Don't adjust if this is a reloc in the toc section.  */
+      && (symseg != data_section
+         || ppc_toc_csect == NULL
+         || val < ppc_toc_frag->fr_address
+         || (ppc_after_toc_frag != NULL
+             && val >= ppc_after_toc_frag->fr_address)))
+    {
+      symbolS* csect = tc->within;
+
+      /* If the symbol was not declared by a label (eg: a section symbol),
+         use the section instead of the csect.  This doesn't happen in
+         normal AIX assembly code.  */
+      if (csect == NULL)
+        csect = seg_info (symseg)->sym;
+
+      return csect;
+    }
+
+  return NULL;
+}
+
 /* This is called to see whether a fixup should be adjusted to use a
    section symbol.  We take the opportunity to change a fixup against
    a symbol in the TOC subsegment into a reloc against the
@@ -6274,7 +6313,7 @@ ppc_fix_adjustable (fixS *fix)
 {
   valueT val = resolve_symbol_value (fix->fx_addsy);
   segT symseg = S_GET_SEGMENT (fix->fx_addsy);
-  TC_SYMFIELD_TYPE *tc;
+  symbolS* csect;
 
   if (symseg == absolute_section)
     return 0;
@@ -6316,32 +6355,17 @@ ppc_fix_adjustable (fixS *fix)
     }
 
   /* Possibly adjust the reloc to be against the csect.  */
-  tc = symbol_get_tc (fix->fx_addsy);
-  if (tc->subseg == 0
-      && tc->symbol_class != XMC_TC0
-      && tc->symbol_class != XMC_TC
-      && tc->symbol_class != XMC_TE
-      && symseg != bss_section
-      && symseg != ppc_xcoff_tbss_section.segment
-      /* Don't adjust if this is a reloc in the toc section.  */
-      && (symseg != data_section
-         || ppc_toc_csect == NULL
-         || val < ppc_toc_frag->fr_address
-         || (ppc_after_toc_frag != NULL
-             && val >= ppc_after_toc_frag->fr_address)))
+  if ((csect = ppc_get_csect_to_adjust (fix->fx_addsy)) != NULL)
     {
-      symbolS *csect = tc->within;
-
-      /* If the symbol was not declared by a label (eg: a section symbol),
-         use the section instead of the csect.  This doesn't happen in
-         normal AIX assembly code.  */
-      if (csect == NULL)
-        csect = seg_info (symseg)->sym;
-
       fix->fx_offset += val - symbol_get_frag (csect)->fr_address;
       fix->fx_addsy = csect;
+    }
 
-      return 0;
+  if ((csect = ppc_get_csect_to_adjust (fix->fx_subsy)) != NULL)
+    {
+      fix->fx_offset -= resolve_symbol_value (fix->fx_subsy)
+       - symbol_get_frag (csect)->fr_address;
+      fix->fx_subsy = csect;
     }
 
   /* Adjust a reloc against a .lcomm symbol to be against the base
@@ -7367,12 +7391,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
 
 /* Generate a reloc for a fixup.  */
 
-arelent *
+arelent **
 tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
 {
+  static arelent *relocs[3];
   arelent *reloc;
 
-  reloc = XNEW (arelent);
+  relocs[0] = reloc = XNEW (arelent);
+  relocs[1] = NULL;
 
   reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
@@ -7386,11 +7412,33 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, fixS *fixp)
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
-      return NULL;
+      relocs[0] = NULL;
     }
   reloc->addend = fixp->fx_addnumber;
 
-  return reloc;
+  if (fixp->fx_subsy && fixp->fx_addsy)
+    {
+      relocs[1] = reloc = XNEW (arelent);
+      relocs[2] = NULL;
+
+      reloc->sym_ptr_ptr = XNEW (asymbol *);
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+      reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+
+      reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_PPC_NEG);
+      reloc->addend = fixp->fx_addnumber;
+
+      if (reloc->howto == (reloc_howto_type *) NULL)
+        {
+          as_bad_where (fixp->fx_file, fixp->fx_line,
+            _("reloc %d not supported by object file format"),
+            BFD_RELOC_PPC_NEG);
+         relocs[0] = NULL;
+        }
+    }
+
+
+  return relocs;
 }
 
 void
index d38c7d47080ace73838b9fea680880903c23c5e6..790994e1314c83f8789d63ec9bdddaedfe37d8bf 100644 (file)
@@ -284,10 +284,27 @@ extern int ppc_force_relocation (struct fix *);
      || (FIX)->fx_r_type == BFD_RELOC_PPC_16DX_HA              \
      || (FIX)->fx_r_type == BFD_RELOC_PPC64_D34                        \
      || (FIX)->fx_r_type == BFD_RELOC_PPC64_D28))
-#endif
 
 #define TC_VALIDATE_FIX_SUB(FIX, SEG) 0
 
+#endif /* OBJ_ELF */
+
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+
+#if defined (OBJ_XCOFF)
+/* Force a relocation when the fix is negative. */
+#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG)                         \
+  (GENERIC_FORCE_RELOCATION_SUB_SAME(FIX, SEG)                         \
+   || (((SEG)->flags & SEC_DEBUGGING) == 0                             \
+       && (FIX)->fx_addsy && (FIX)->fx_subsy                           \
+       && (S_GET_VALUE (fixP->fx_addsy) < S_GET_VALUE (fixP->fx_subsy))))
+
+/* XCOFF allows undefined differences which will be encoded with
+   R_NEG relocations.  */
+#define UNDEFINED_DIFFERENCE_OK
+#endif /* OBJ_XCOFF */
+
 /* Various frobbings of labels and their addresses.  */
 #define md_start_line_hook() ppc_start_line_hook ()
 extern void ppc_start_line_hook (void);
index 663c06cf52aef214dc56679608ee918002d1691c..a6be046bee4c14f9fb69c5675dc53f2f496149de 100644 (file)
@@ -1,3 +1,12 @@
+2021-04-20  Clément Chigot  <clement.chigot@atos.net>
+
+       PR binutils/21700
+       * testsuite/ld-powerpc/aix52.exp: Add new test.
+       * testsuite/ld-powerpc/aix-neg-reloc-32.d: New test.
+       * testsuite/ld-powerpc/aix-neg-reloc-64.d: New test.
+       * testsuite/ld-powerpc/aix-neg-reloc.ex: New test.
+       * testsuite/ld-powerpc/aix-neg-reloc.s: New test.
+
 2021-04-13  Nick Clifton  <nickc@redhat.com>
 
        * ld.texi (Options): Add note about the effect of --as-needed on
diff --git a/ld/testsuite/ld-powerpc/aix-neg-reloc-32.d b/ld/testsuite/ld-powerpc/aix-neg-reloc-32.d
new file mode 100644 (file)
index 0000000..4e980f0
--- /dev/null
@@ -0,0 +1,23 @@
+#source: aix-tls-reloc.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-tls-reloc.ex
+#objdump: -dr
+#target: [is_xcoff_format]
+
+.*
+
+Disassembly of section \.text:
+
+.* <.foo>:
+.*:    4e 80 00 20     br
+.*: R_REF      _foo.ro_-.*
+.*:    60 00 00 00     oril    r0,r0,0
+.*:    60 00 00 00     oril    r0,r0,0
+.*:    60 00 00 00     oril    r0,r0,0
+.* <_GLOBAL__F_foo>:
+.*:    ff ff ff f0     .long 0xfffffff0
+.*: R_POS      .text-.*
+.*: R_NEG      _foo.ro_-.*
+.*:    60 00 00 00     oril    r0,r0,0
+.*:    60 00 00 00     oril    r0,r0,0
+.*:    60 00 00 00     oril    r0,r0,0
diff --git a/ld/testsuite/ld-powerpc/aix-neg-reloc-64.d b/ld/testsuite/ld-powerpc/aix-neg-reloc-64.d
new file mode 100644 (file)
index 0000000..9cf16d0
--- /dev/null
@@ -0,0 +1,23 @@
+#source: aix-tls-reloc.s
+#as: -a32
+#ld: -b32 -shared -bE:aix-tls-reloc.ex
+#objdump: -dr
+#target: [is_xcoff_format]
+
+.*
+
+Disassembly of section \.text:
+
+.* <.foo>:
+.*:    4e 80 00 20     blr
+.*: R_REF      _foo.ro_-.*
+.*:    60 00 00 00     nop
+.*:    60 00 00 00     nop
+.*:    60 00 00 00     nop
+.* <_GLOBAL__F_foo>:
+.*:    ff ff ff ff     fnmadd. f31,f31,f31,f31
+.*: R_POS_64   .text-.*
+.*: R_NEG      _foo.ro_-.*
+.*:    ff ff ff f0     .long 0xfffffff0
+.*:    60 00 00 00     nop
+.*:    60 00 00 00     nop
diff --git a/ld/testsuite/ld-powerpc/aix-neg-reloc.ex b/ld/testsuite/ld-powerpc/aix-neg-reloc.ex
new file mode 100644 (file)
index 0000000..257cc56
--- /dev/null
@@ -0,0 +1 @@
+foo
diff --git a/ld/testsuite/ld-powerpc/aix-neg-reloc.s b/ld/testsuite/ld-powerpc/aix-neg-reloc.s
new file mode 100644 (file)
index 0000000..20b48bd
--- /dev/null
@@ -0,0 +1,30 @@
+  .toc
+  .csect .text[PR]
+  .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:
+LFB..0:
+  blr
+
+  .csect _foo.ro_[RO],4
+  .globl _GLOBAL__F_foo
+_GLOBAL__F_foo:
+  .if size == 32
+  .vbyte 4,LFB..0-$
+  .else
+  .vbyte 8,LFB..0-$
+  .endif
+
+# Make sure that .ref is also enough to keep _GLOBAL__F_foo
+# when exporting foo.
+  .csect .text[PR]
+  .ref _GLOBAL__F_foo
index 0e68b6a4a785da56ab05dbf2e79ca8dbe2aed9d9..51d31325f7fcd7a1ba4669774489e1b7eee0051c 100644 (file)
@@ -251,6 +251,12 @@ set aix52tests {
      "" {aix-toc-1a.s aix-toc-1b.s}
      {{objdump -dr aix-toc-1-SIZE.dd}}
      "aix-toc-1.so"}
+
+    {"Negative relocation test 1" "-shared -bE:aix-neg-reloc.ex"
+       "" {aix-neg-reloc.s}
+       {{objdump -dr aix-neg-reloc-SIZE.d}}
+       "aix-neg-reloc.so"}
+
 }
 
 foreach test $aix52tests {