From c5df7e442e6cdc9303b7373842370d6ee8f67ea5 Mon Sep 17 00:00:00 2001 From: Cl?ment Chigot Date: Tue, 20 Apr 2021 14:40:43 +0100 Subject: [PATCH] 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. --- bfd/ChangeLog | 18 ++++ bfd/bfd-in2.h | 1 + bfd/coff-rs6000.c | 4 +- bfd/coff64-rs6000.c | 21 ++++- bfd/libbfd.h | 1 + bfd/reloc.c | 2 + bfd/xcofflink.c | 14 ++- gas/ChangeLog | 14 +++ gas/config/tc-ppc.c | 102 +++++++++++++++------ gas/config/tc-ppc.h | 19 +++- ld/ChangeLog | 9 ++ ld/testsuite/ld-powerpc/aix-neg-reloc-32.d | 23 +++++ ld/testsuite/ld-powerpc/aix-neg-reloc-64.d | 23 +++++ ld/testsuite/ld-powerpc/aix-neg-reloc.ex | 1 + ld/testsuite/ld-powerpc/aix-neg-reloc.s | 30 ++++++ ld/testsuite/ld-powerpc/aix52.exp | 6 ++ 16 files changed, 255 insertions(+), 33 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/aix-neg-reloc-32.d create mode 100644 ld/testsuite/ld-powerpc/aix-neg-reloc-64.d create mode 100644 ld/testsuite/ld-powerpc/aix-neg-reloc.ex create mode 100644 ld/testsuite/ld-powerpc/aix-neg-reloc.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 513d6e9d3f3..972311bce48 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2021-04-20 Clément Chigot + + 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 PR 27567 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index cdfb933e30d..d5780e46873 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 237c7ed6d66..7cfe4040fb7 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 cc671b26b6a..889534088f0 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 f1d25d0ab1f..bee1a1f8e59 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 2eb0758a82c..674b075a6b8 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -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 diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index f0e0fe7aafc..1607cd57d44 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 5111ace21d0..c8ef5f3b54c 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2021-04-20 Clément Chigot + + 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 * 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 c719b408b0e..7715fc53d07 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 d38c7d47080..790994e1314 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 663c06cf52a..a6be046bee4 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2021-04-20 Clément Chigot + + 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 * 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 00000000000..4e980f0cd35 --- /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 00000000000..9cf16d0c4b1 --- /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 00000000000..257cc5642cb --- /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 00000000000..20b48bd224c --- /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 0e68b6a4a78..51d31325f7f 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 { -- 2.39.5