aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCl?ment Chigot <clement.chigot@atos.net>2021-04-20 14:40:43 +0100
committerNick Clifton <nickc@redhat.com>2021-04-20 14:40:43 +0100
commitc5df7e442e6cdc9303b7373842370d6ee8f67ea5 (patch)
tree28e1442062fdbb13b5c46d98ceeba9c556e6f3b0
parentd549b029d6d622af531211ef4c7bc48cb5011d93 (diff)
downloadfsf-binutils-gdb-c5df7e442e6cdc9303b7373842370d6ee8f67ea5.zip
fsf-binutils-gdb-c5df7e442e6cdc9303b7373842370d6ee8f67ea5.tar.gz
fsf-binutils-gdb-c5df7e442e6cdc9303b7373842370d6ee8f67ea5.tar.bz2
Rework the R_NEG support on both gas and ld for the PowerPC AIX targets, in order to manage C++ exceptions built with GCC.
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.
-rw-r--r--bfd/ChangeLog18
-rw-r--r--bfd/bfd-in2.h1
-rw-r--r--bfd/coff-rs6000.c4
-rw-r--r--bfd/coff64-rs6000.c21
-rw-r--r--bfd/libbfd.h1
-rw-r--r--bfd/reloc.c2
-rw-r--r--bfd/xcofflink.c14
-rw-r--r--gas/ChangeLog14
-rw-r--r--gas/config/tc-ppc.c102
-rw-r--r--gas/config/tc-ppc.h19
-rw-r--r--ld/ChangeLog9
-rw-r--r--ld/testsuite/ld-powerpc/aix-neg-reloc-32.d23
-rw-r--r--ld/testsuite/ld-powerpc/aix-neg-reloc-64.d23
-rw-r--r--ld/testsuite/ld-powerpc/aix-neg-reloc.ex1
-rw-r--r--ld/testsuite/ld-powerpc/aix-neg-reloc.s30
-rw-r--r--ld/testsuite/ld-powerpc/aix52.exp6
16 files changed, 255 insertions, 33 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 513d6e9..972311b 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index cdfb933..d5780e4 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -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,
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 237c7ed..7cfe404 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -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;
}
diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c
index cc671b2..8895340 100644
--- a/bfd/coff64-rs6000.c
+++ b/bfd/coff64-rs6000.c
@@ -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:
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index f1d25d0..bee1a1f 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -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",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 2eb0758a..674b075 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2833,6 +2833,8 @@ ENUMX
ENUMX
BFD_RELOC_PPC_REL16DX_HA
ENUMX
+ BFD_RELOC_PPC_NEG
+ENUMX
BFD_RELOC_PPC64_HIGHER
ENUMX
BFD_RELOC_PPC64_HIGHER_S
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index f0e0fe7..1607cd5 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -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;
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 5111ace..c8ef5f3 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -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
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c
index c719b40..7715fc5 100644
--- a/gas/config/tc-ppc.c
+++ b/gas/config/tc-ppc.c
@@ -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
diff --git a/gas/config/tc-ppc.h b/gas/config/tc-ppc.h
index d38c7d4..790994e 100644
--- a/gas/config/tc-ppc.h
+++ b/gas/config/tc-ppc.h
@@ -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);
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 663c06c..a6be046 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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
index 0000000..4e980f0
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-neg-reloc-32.d
@@ -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
index 0000000..9cf16d0
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-neg-reloc-64.d
@@ -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
index 0000000..257cc56
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-neg-reloc.ex
@@ -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
index 0000000..20b48bd
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/aix-neg-reloc.s
@@ -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
diff --git a/ld/testsuite/ld-powerpc/aix52.exp b/ld/testsuite/ld-powerpc/aix52.exp
index 0e68b6a..51d3132 100644
--- a/ld/testsuite/ld-powerpc/aix52.exp
+++ b/ld/testsuite/ld-powerpc/aix52.exp
@@ -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 {