From 2a770ce09f25d40721a669721533b8218f65ddfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= 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 * 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 * 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 * 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 */ #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