From 05d0e962f08af24f18cc79b890a68176b42bcb78 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 3 Aug 2018 16:41:22 +0930 Subject: [PATCH] R_PPC64_REL24_NOTOC support R_PPC64_REL24_NOTOC is used on calls like "bl foo@notoc" to tell the linker that linkage stubs for PLT calls or long branches can't use r2 for pic addressing. Instead, new stubs that generate pc-relative addresses are used. One complication is that pc-relative offsets to the PLT may need to be 64-bit in large programs, in contrast to the toc-relative addressing used by older PLT linkage stubs where a 32-bit offset is sufficient until the PLT itself exceeds 2G in size. .eh_frame info to cover the _notoc stubs is yet to be implemented. bfd/ * elf64-ppc.c (ADDI_R12_R11, ADDI_R12_R12, LIS_R12), (ADDIS_R12_R11, ORIS_R12_R12_0, ORI_R12_R12_0), (SLDI_R12_R12_32, LDX_R12_R11_R12, ADD_R12_R11_R12): Define. (ppc64_elf_howto_raw): Add R_PPC64_REL24_NOTOC entry. (ppc64_elf_reloc_type_lookup): Support R_PPC64_REL24_NOTOC. (ppc_stub_type): Add ppc_stub_long_branch_notoc, ppc_stub_long_branch_both, ppc_stub_plt_branch_notoc, ppc_stub_plt_branch_both, ppc_stub_plt_call_notoc, and ppc_stub_plt_call_both. (is_branch_reloc): Add R_PPC64_REL24_NOTOC. (build_offset, size_offset): New functions. (plt_stub_size): Support plt_call_notoc and plt_call_both. (ppc_build_one_stub, ppc_size_one_stub): Support new stubs. (toc_adjusting_stub_needed): Handle R_PPC64_REL24_NOTOC. (ppc64_elf_size_stubs): Likewise, and new stubs. (ppc64_elf_build_stubs, ppc64_elf_relocate_section): Likewise. * reloc.c: Add BFD_RELOC_PPC64_REL24_NOTOC. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. gas/ * config/tc-ppc.c (ppc_elf_suffix): Support @notoc. (ppc_force_relocation, ppc_fix_adjustable): Handle REL24_NOTOC. ld/ * testsuite/ld-powerpc/ext.d, * testsuite/ld-powerpc/ext.s, * testsuite/ld-powerpc/ext.lnk, * testsuite/ld-powerpc/notoc.d, * testsuite/ld-powerpc/notoc.s: New tests. * testsuite/ld-powerpc/powerpc.exp: Run them. --- bfd/ChangeLog | 22 + bfd/bfd-in2.h | 1 + bfd/elf64-ppc.c | 690 +++++++++++++++++++++++----- bfd/libbfd.h | 1 + bfd/reloc.c | 2 + gas/ChangeLog | 5 + gas/config/tc-ppc.c | 3 + ld/ChangeLog | 9 + ld/testsuite/ld-powerpc/ext.d | 17 + ld/testsuite/ld-powerpc/ext.lnk | 6 + ld/testsuite/ld-powerpc/ext.s | 9 + ld/testsuite/ld-powerpc/notoc.d | 102 ++++ ld/testsuite/ld-powerpc/notoc.s | 56 +++ ld/testsuite/ld-powerpc/powerpc.exp | 2 + 14 files changed, 808 insertions(+), 117 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/ext.d create mode 100644 ld/testsuite/ld-powerpc/ext.lnk create mode 100644 ld/testsuite/ld-powerpc/ext.s create mode 100644 ld/testsuite/ld-powerpc/notoc.d create mode 100644 ld/testsuite/ld-powerpc/notoc.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index e23f7470e0a..95fe0eef071 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,25 @@ +2018-08-05 Alan Modra + + * elf64-ppc.c (ADDI_R12_R11, ADDI_R12_R12, LIS_R12), + (ADDIS_R12_R11, ORIS_R12_R12_0, ORI_R12_R12_0), + (SLDI_R12_R12_32, LDX_R12_R11_R12, ADD_R12_R11_R12): Define. + (ppc64_elf_howto_raw): Add R_PPC64_REL24_NOTOC entry. + (ppc64_elf_reloc_type_lookup): Support R_PPC64_REL24_NOTOC. + (ppc_stub_type): Add ppc_stub_long_branch_notoc, + ppc_stub_long_branch_both, ppc_stub_plt_branch_notoc, + ppc_stub_plt_branch_both, ppc_stub_plt_call_notoc, and + ppc_stub_plt_call_both. + (is_branch_reloc): Add R_PPC64_REL24_NOTOC. + (build_offset, size_offset): New functions. + (plt_stub_size): Support plt_call_notoc and plt_call_both. + (ppc_build_one_stub, ppc_size_one_stub): Support new stubs. + (toc_adjusting_stub_needed): Handle R_PPC64_REL24_NOTOC. + (ppc64_elf_size_stubs): Likewise, and new stubs. + (ppc64_elf_build_stubs, ppc64_elf_relocate_section): Likewise. + * reloc.c: Add BFD_RELOC_PPC64_REL24_NOTOC. + * bfd-in2.h: Regenerate. + * libbfd.h: Regenerate. + 2018-08-05 Alan Modra * elf64-ppc.c (ppc_build_one_stub): Lose "_r2off" in stub symbols. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 7105850ff55..58afff24c9f 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3457,6 +3457,7 @@ instruction. */ BFD_RELOC_PPC64_ADDR16_HIGHA, BFD_RELOC_PPC64_ADDR64_LOCAL, BFD_RELOC_PPC64_ENTRY, + BFD_RELOC_PPC64_REL24_NOTOC, /* PowerPC and PowerPC64 thread-local storage relocations. */ BFD_RELOC_PPC_TLS, diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 634e537e47e..008d352b242 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -164,6 +164,8 @@ static bfd_vma opd_entry_value #define BCTR 0x4e800420 /* bctr */ #define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */ +#define ADDI_R12_R11 0x398b0000 /* addi %r12,%r11,off@l */ +#define ADDI_R12_R12 0x398c0000 /* addi %r12,%r12,off@l */ #define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ #define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ @@ -184,10 +186,17 @@ static bfd_vma opd_entry_value #define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */ #define LIS_R2 0x3c400000 /* lis %r2,xxx@ha */ +#define LIS_R12 0x3d800000 /* lis %r12,xxx@ha */ #define ADDIS_R2_R12 0x3c4c0000 /* addis %r2,%r12,xxx@ha */ #define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ +#define ADDIS_R12_R11 0x3d8b0000 /* addis %r12,%r11,xxx@ha */ #define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ +#define ORIS_R12_R12_0 0x658c0000 /* oris %r12,%r12,xxx@hi */ +#define ORI_R12_R12_0 0x618c0000 /* ori %r12,%r12,xxx@l */ #define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ +#define SLDI_R12_R12_32 0x799c07c6 /* sldi %r12,%r12,32 */ +#define LDX_R12_R11_R12 0x7d8b602a /* ldx %r12,%r11,%r12 */ +#define ADD_R12_R11_R12 0x7d8b6214 /* add %r12,%r11,%r12 */ /* __glink_PLTresolve stub instructions. We enter with the index in R0. */ #define GLINK_PLTRESOLVE_SIZE(htab) \ @@ -446,6 +455,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = 0x03fffffc, /* dst_mask */ TRUE), /* pcrel_offset */ + /* A variant of R_PPC64_REL24, used when r2 is not the toc pointer. */ + HOWTO (R_PPC64_REL24_NOTOC, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 26, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc64_elf_branch_reloc, /* special_function */ + "R_PPC64_REL24_NOTOC", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x03fffffc, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* A relative 16 bit branch; the lower two bits must be zero. */ HOWTO (R_PPC64_REL14, /* type */ 0, /* rightshift */ @@ -2308,6 +2332,8 @@ ppc64_elf_reloc_type_lookup (bfd *abfd, break; case BFD_RELOC_PPC_B26: r = R_PPC64_REL24; break; + case BFD_RELOC_PPC64_REL24_NOTOC: r = R_PPC64_REL24_NOTOC; + break; case BFD_RELOC_PPC_B16: r = R_PPC64_REL14; break; case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC64_REL14_BRTAKEN; @@ -3954,7 +3980,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, Used to call a function in a shared library. If it so happens that the plt entry referenced crosses a 64k boundary, then an extra "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr". - . std %r2,40(%r1) + ppc_stub_plt_call_r2save starts with "std %r2,40(%r1)". . addis %r11,%r2,xxx@toc@ha . ld %r12,xxx+0@toc@l(%r11) . mtctr %r12 @@ -3979,18 +4005,98 @@ must_be_dyn_reloc (struct bfd_link_info *info, . mtctr %r12 . bctr - In cases where the "addis" instruction would add zero, the "addis" is - omitted and following instructions modified slightly in some cases. -*/ + All of the above stubs are shown as their ELFv1 variants. ELFv2 + variants exist too, simpler for plt calls since a new toc pointer + and static chain are not loaded by the stub. In addition, ELFv2 + has some more complex stubs to handle calls marked with NOTOC + relocs from functions where r2 is not a valid toc pointer. These + come in two flavours, the ones shown below, and _both variants that + start with "std %r2,24(%r1)" to save r2 in the unlikely event that + one call is from a function where r2 is used as the toc pointer but + needs a toc adjusting stub for small-model multi-toc, and another + call is from a function where r2 is not valid. + ppc_stub_long_branch_notoc: + . mflr %r12 + . bcl 20,31,1f + . 1: + . mflr %r11 + . mtlr %r12 + . lis %r12,xxx-1b@highest + . ori %r12,xxx-1b@higher + . sldi %r12,%r12,32 + . oris %r12,%r12,xxx-1b@hi + . ori %r12,%r12,xxx-1b@l + . add %r12,%r11,%r12 + . b dest + + ppc_stub_plt_branch_notoc: + . mflr %r12 + . bcl 20,31,1f + . 1: + . mflr %r11 + . mtlr %r12 + . lis %r12,xxx-1b@highest + . ori %r12,xxx-1b@higher + . sldi %r12,%r12,32 + . oris %r12,%r12,xxx-1b@hi + . ori %r12,%r12,xxx-1b@l + . add %r12,%r11,%r12 + . mtctr %r12 + . bctr + + ppc_stub_plt_call_notoc: + . mflr %r12 + . bcl 20,31,1f + . 1: + . mflr %r11 + . mtlr %r12 + . lis %r12,xxx-1b@highest + . ori %r12,xxx-1b@higher + . sldi %r12,%r12,32 + . oris %r12,%r12,xxx-1b@hi + . ori %r12,%r12,xxx-1b@l + . ldx %r12,%r11,%r12 + . mtctr %r12 + . bctr + + In cases where the high instructions would add zero, they are + omitted and following instructions modified in some cases. + + For a given stub group (a set of sections all using the same toc + pointer value) there will be just one stub type used for any + particular function symbol. For example, if printf is called from + code with the tocsave optimization (ie. r2 saved in function + prologue) and therefore calls use a ppc_stub_plt_call linkage stub, + and from other code without the tocsave optimization requiring a + ppc_stub_plt_call_r2save linkage stub, a single stub of the latter + type will be created. Calls with the tocsave optimization will + enter this stub after the instruction saving r2. A similar + situation exists when calls are marked with R_PPC64_REL24_NOTOC + relocations. These require a ppc_stub_plt_call_notoc linkage stub + to call an external function like printf. If other calls to printf + require a ppc_stub_plt_call linkage stub then a single + ppc_stub_plt_call_notoc linkage stub will be used for both types of + call. If other calls to printf require a ppc_stub_plt_call_r2save + linkage stub then a single ppc_stub_plt_call_both linkage stub will + be created and calls not requiring r2 to be saved will enter the + stub after the r2 save instruction. There is an analogous + hierarchy of long branch and plt branch stubs for local call + linkage. */ enum ppc_stub_type { ppc_stub_none, ppc_stub_long_branch, ppc_stub_long_branch_r2off, + ppc_stub_long_branch_notoc, + ppc_stub_long_branch_both, /* r2off and notoc variants both needed. */ ppc_stub_plt_branch, ppc_stub_plt_branch_r2off, + ppc_stub_plt_branch_notoc, + ppc_stub_plt_branch_both, ppc_stub_plt_call, ppc_stub_plt_call_r2save, + ppc_stub_plt_call_notoc, + ppc_stub_plt_call_both, ppc_stub_global_entry, ppc_stub_save_res }; @@ -5478,6 +5584,7 @@ static bfd_boolean is_branch_reloc (enum elf_ppc64_reloc_type r_type) { return (r_type == R_PPC64_REL24 + || r_type == R_PPC64_REL24_NOTOC || r_type == R_PPC64_REL14 || r_type == R_PPC64_REL14_BRTAKEN || r_type == R_PPC64_REL14_BRNTAKEN @@ -5848,6 +5955,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Fall through. */ case R_PPC64_REL24: + case R_PPC64_REL24_NOTOC: rel24: plt_list = ifunc; if (h != NULL) @@ -10757,6 +10865,106 @@ ppc_type_of_stub (asection *input_sec, return ppc_stub_none; } +/* Builds a 64-bit offset in r12 then adds it to r11 (LOAD false) or + loads r12 from r11+r12 (LOAD true). + . lis %r12,xxx-1b@highest + . ori %r12,xxx-1b@higher + . sldi %r12,%r12,32 + . oris %r12,%r12,xxx-1b@hi + . ori %r12,%r12,xxx-1b@l + . add %r12,%r11,%r12 */ + +static bfd_byte * +build_offset (bfd *abfd, bfd_byte *p, bfd_vma off, bfd_boolean load) +{ + if (off + 0x8000 < 0x10000) + { + if (load) + bfd_put_32 (abfd, LD_R12_0R11 + PPC_LO (off), p); + else + bfd_put_32 (abfd, ADDI_R12_R11 + PPC_LO (off), p); + p += 4; + } + else if (off + 0x80008000ULL < 0x100000000ULL) + { + bfd_put_32 (abfd, ADDIS_R12_R11 + PPC_HA (off), p); + p += 4; + if (load) + bfd_put_32 (abfd, LD_R12_0R12 + PPC_LO (off), p); + else + bfd_put_32 (abfd, ADDI_R12_R12 + PPC_LO (off), p); + p += 4; + } + else + { + if (off + 0x800000000000ULL < 0x1000000000000ULL) + { + bfd_put_32 (abfd, LI_R12_0 + ((off >> 32) & 0xffff), p); + p += 4; + } + else + { + bfd_put_32 (abfd, LIS_R12 + ((off >> 48) & 0xffff), p); + p += 4; + if (((off >> 32) & 0xffff) != 0) + { + bfd_put_32 (abfd, ORI_R12_R12_0 + ((off >> 32) & 0xffff), p); + p += 4; + } + } + if (((off >> 32) & 0xffffffffULL) != 0) + { + bfd_put_32 (abfd, SLDI_R12_R12_32, p); + p += 4; + } + if (PPC_HI (off) != 0) + { + bfd_put_32 (abfd, ORIS_R12_R12_0 + PPC_HI (off), p); + p += 4; + } + if (PPC_LO (off) != 0) + { + bfd_put_32 (abfd, ORI_R12_R12_0 + PPC_LO (off), p); + p += 4; + } + if (load) + bfd_put_32 (abfd, LDX_R12_R11_R12, p); + else + bfd_put_32 (abfd, ADD_R12_R11_R12, p); + p += 4; + } + return p; +} + +static unsigned int +size_offset (bfd_vma off) +{ + unsigned int size; + if (off + 0x8000 < 0x10000) + size = 4; + else if (off + 0x80008000ULL < 0x100000000ULL) + size = 8; + else + { + if (off + 0x800000000000ULL < 0x1000000000000ULL) + size = 4; + else + { + size = 4; + if (((off >> 32) & 0xffff) != 0) + size += 4; + } + if (((off >> 32) & 0xffffffffULL) != 0) + size += 4; + if (PPC_HI (off) != 0) + size += 4; + if (PPC_LO (off) != 0) + size += 4; + size += 4; + } + return size; +} + /* With power7 weakly ordered memory model, it is possible for ld.so to update a plt entry in one thread and have another thread see a stale zero toc entry. To avoid this we need some sort of acquire @@ -10784,8 +10992,17 @@ plt_stub_size (struct ppc_link_hash_table *htab, struct ppc_stub_hash_entry *stub_entry, bfd_vma off) { - unsigned size = 12; + unsigned size; + if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) + { + size = 24 + size_offset (off); + if (stub_entry->stub_type > ppc_stub_plt_call_notoc) + size += 4; + return size; + } + + size = 12; if (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save) size += 4; @@ -11422,6 +11639,78 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) p += 4; break; + case ppc_stub_long_branch_notoc: + case ppc_stub_long_branch_both: + case ppc_stub_plt_branch_notoc: + case ppc_stub_plt_branch_both: + case ppc_stub_plt_call_notoc: + case ppc_stub_plt_call_both: + p = loc; + off = (8 + stub_entry->stub_offset + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); + if (stub_entry->stub_type == ppc_stub_long_branch_both + || stub_entry->stub_type == ppc_stub_plt_branch_both + || stub_entry->stub_type == ppc_stub_plt_call_both) + { + off += 4; + bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), p); + p += 4; + } + if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) + { + targ = stub_entry->plt_ent->plt.offset & ~1; + if (targ >= (bfd_vma) -2) + abort (); + + plt = htab->elf.splt; + if (!htab->elf.dynamic_sections_created + || stub_entry->h == NULL + || stub_entry->h->elf.dynindx == -1) + { + if (stub_entry->symtype == STT_GNU_IFUNC) + plt = htab->elf.iplt; + else + plt = htab->pltlocal; + } + targ += plt->output_offset + plt->output_section->vma; + } + else + targ = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); + off = targ - off; + bfd_put_32 (htab->params->stub_bfd, MFLR_R12, p); + p += 4; + bfd_put_32 (htab->params->stub_bfd, BCL_20_31, p); + p += 4; + bfd_put_32 (htab->params->stub_bfd, MFLR_R11, p); + p += 4; + bfd_put_32 (htab->params->stub_bfd, MTLR_R12, p); + p += 4; + p = build_offset (htab->params->stub_bfd, p, off, + stub_entry->stub_type >= ppc_stub_plt_call_notoc); + if (stub_entry->stub_type == ppc_stub_long_branch_notoc) + { + off += 8; + bfd_put_32 (htab->params->stub_bfd, + B_DOT | ((off - (p - loc)) & 0x3fffffc), p); + } + else if (stub_entry->stub_type == ppc_stub_long_branch_both) + { + off += 12; + bfd_put_32 (htab->params->stub_bfd, + B_DOT | ((off - (p - loc)) & 0x3fffffc), p); + } + else + { + bfd_put_32 (htab->params->stub_bfd, MTCTR_R12, p); + p += 4; + bfd_put_32 (htab->params->stub_bfd, BCTR, p); + } + p += 4; + break; + case ppc_stub_plt_call: case ppc_stub_plt_call_r2save: if (stub_entry->h != NULL @@ -11513,9 +11802,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size_t len1, len2; char *name; const char *const stub_str[] = { "long_branch", + "long_branch", + "long_branch", "long_branch", "plt_branch", "plt_branch", + "plt_branch", + "plt_branch", + "plt_call", + "plt_call", "plt_call", "plt_call" }; @@ -11583,8 +11878,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return TRUE; } - if (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) + if (stub_entry->stub_type >= ppc_stub_plt_call + && stub_entry->stub_type <= ppc_stub_plt_call_both) { asection *plt; targ = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; @@ -11602,38 +11897,52 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } targ += plt->output_offset + plt->output_section->vma; - off = (elf_gp (info->output_bfd) - + htab->sec_info[stub_entry->group->link_sec->id].toc_off); - off = targ - off; + if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) + { + off = (8 + stub_entry->stub_offset + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); + if (stub_entry->stub_type > ppc_stub_plt_call_notoc) + off += 4; + } + else + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); if (htab->params->plt_stub_align != 0) { - unsigned pad = plt_stub_pad (htab, stub_entry, off); + unsigned pad = plt_stub_pad (htab, stub_entry, targ - off); stub_entry->group->stub_sec->size += pad; stub_entry->stub_offset = stub_entry->group->stub_sec->size; + if (stub_entry->stub_type >= ppc_stub_plt_call_notoc) + off += pad; } + off = targ - off; size = plt_stub_size (htab, stub_entry, off); - if (stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && htab->params->tls_get_addr_opt - && (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) - stub_entry->group->tls_get_addr_opt_bctrl - = stub_entry->stub_offset + size - 5 * 4; - - if (info->emitrelocations) + if (stub_entry->stub_type < ppc_stub_plt_call_notoc) { - stub_entry->group->stub_sec->reloc_count - += ((PPC_HA (off) != 0) - + (htab->opd_abi - ? 2 + (htab->params->plt_static_chain - && PPC_HA (off + 16) == PPC_HA (off)) - : 1)); - stub_entry->group->stub_sec->flags |= SEC_RELOC; + if (stub_entry->h != NULL + && (stub_entry->h == htab->tls_get_addr_fd + || stub_entry->h == htab->tls_get_addr) + && htab->params->tls_get_addr_opt + && (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save)) + stub_entry->group->tls_get_addr_opt_bctrl + = stub_entry->stub_offset + size - 5 * 4; + + if (info->emitrelocations) + { + stub_entry->group->stub_sec->reloc_count + += ((PPC_HA (off) != 0) + + (htab->opd_abi + ? 2 + (htab->params->plt_static_chain + && PPC_HA (off + 16) == PPC_HA (off)) + : 1)); + stub_entry->group->stub_sec->flags |= SEC_RELOC; + } } } else @@ -11671,83 +11980,103 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size += 4; off += size - 4; } + else if (stub_entry->stub_type >= ppc_stub_long_branch_notoc) + { + size = 20 + size_offset (targ - (off + 8)); + if (stub_entry->stub_type > ppc_stub_long_branch_notoc) + size += 4; + off += size - 4; + } off = targ - off; - local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); - - /* If the branch offset is too big, use a ppc_stub_plt_branch. - Do the same for -R objects without function descriptors. */ - if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off - || (stub_entry->stub_type == ppc_stub_long_branch_r2off - && r2off == 0 - && htab->sec_info[stub_entry->target_section->id].toc_off == 0)) + if (stub_entry->stub_type >= ppc_stub_long_branch_notoc) { - struct ppc_branch_hash_entry *br_entry; - - br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, - stub_entry->root.string + 9, - TRUE, FALSE); - if (br_entry == NULL) + if (off + (1 << 25) >= (bfd_vma) (1 << 26)) { - _bfd_error_handler (_("can't build branch stub `%s'"), - stub_entry->root.string); - htab->stub_error = TRUE; - return FALSE; + stub_entry->stub_type += (ppc_stub_plt_branch_notoc + - ppc_stub_long_branch_notoc); + size += 4; } - - if (br_entry->iter != htab->stub_iteration) + } + else + { + local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + + /* If the branch offset is too big, use a ppc_stub_plt_branch. + Do the same for -R objects without function descriptors. */ + if ((stub_entry->stub_type == ppc_stub_long_branch_r2off + && r2off == 0 + && htab->sec_info[stub_entry->target_section->id].toc_off == 0) + || off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off) { - br_entry->iter = htab->stub_iteration; - br_entry->offset = htab->brlt->size; - htab->brlt->size += 8; + struct ppc_branch_hash_entry *br_entry; - if (htab->relbrlt != NULL) - htab->relbrlt->size += sizeof (Elf64_External_Rela); - else if (info->emitrelocations) + br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, + stub_entry->root.string + 9, + TRUE, FALSE); + if (br_entry == NULL) { - htab->brlt->reloc_count += 1; - htab->brlt->flags |= SEC_RELOC; + _bfd_error_handler (_("can't build branch stub `%s'"), + stub_entry->root.string); + htab->stub_error = TRUE; + return FALSE; } - } - stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch; - targ = (br_entry->offset - + htab->brlt->output_offset - + htab->brlt->output_section->vma); - off = (elf_gp (info->output_bfd) - + htab->sec_info[stub_entry->group->link_sec->id].toc_off); - off = targ - off; + if (br_entry->iter != htab->stub_iteration) + { + br_entry->iter = htab->stub_iteration; + br_entry->offset = htab->brlt->size; + htab->brlt->size += 8; - if (info->emitrelocations) - { - stub_entry->group->stub_sec->reloc_count - += 1 + (PPC_HA (off) != 0); - stub_entry->group->stub_sec->flags |= SEC_RELOC; - } + if (htab->relbrlt != NULL) + htab->relbrlt->size += sizeof (Elf64_External_Rela); + else if (info->emitrelocations) + { + htab->brlt->reloc_count += 1; + htab->brlt->flags |= SEC_RELOC; + } + } - if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) - { - size = 12; - if (PPC_HA (off) != 0) - size = 16; + targ = (br_entry->offset + + htab->brlt->output_offset + + htab->brlt->output_section->vma); + off = (elf_gp (info->output_bfd) + + htab->sec_info[stub_entry->group->link_sec->id].toc_off); + off = targ - off; + + if (info->emitrelocations) + { + stub_entry->group->stub_sec->reloc_count + += 1 + (PPC_HA (off) != 0); + stub_entry->group->stub_sec->flags |= SEC_RELOC; + } + + stub_entry->stub_type + += ppc_stub_plt_branch - ppc_stub_long_branch; + if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + { + size = 12; + if (PPC_HA (off) != 0) + size = 16; + } + else + { + size = 16; + if (PPC_HA (off) != 0) + size += 4; + + if (PPC_HA (r2off) != 0) + size += 4; + if (PPC_LO (r2off) != 0) + size += 4; + } } - else + else if (info->emitrelocations) { - size = 16; - if (PPC_HA (off) != 0) - size += 4; - - if (PPC_HA (r2off) != 0) - size += 4; - if (PPC_LO (r2off) != 0) - size += 4; + stub_entry->group->stub_sec->reloc_count += 1; + stub_entry->group->stub_sec->flags |= SEC_RELOC; } } - else if (info->emitrelocations) - { - stub_entry->group->stub_sec->reloc_count += 1; - stub_entry->group->stub_sec->flags |= SEC_RELOC; - } } stub_entry->group->stub_sec->size += size; @@ -12154,6 +12483,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) r_type = ELF64_R_TYPE (rel->r_info); if (r_type != R_PPC64_REL24 + && r_type != R_PPC64_REL24_NOTOC && r_type != R_PPC64_REL14 && r_type != R_PPC64_REL14_BRTAKEN && r_type != R_PPC64_REL14_BRNTAKEN @@ -12750,6 +13080,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) /* Only look for stubs on branch instructions. */ if (r_type != R_PPC64_REL24 + && r_type != R_PPC64_REL24_NOTOC && r_type != R_PPC64_REL14 && r_type != R_PPC64_REL14_BRTAKEN && r_type != R_PPC64_REL14_BRNTAKEN) @@ -12857,7 +13188,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) &plt_ent, destination, local_off); - if (stub_type != ppc_stub_plt_call) + if (r_type == R_PPC64_REL24_NOTOC) + { + if (stub_type == ppc_stub_plt_call) + stub_type = ppc_stub_plt_call_notoc; + else if (stub_type == ppc_stub_long_branch + || (code_sec != NULL + && code_sec->output_section != NULL + && (((hash ? hash->elf.other : sym->st_other) + & STO_PPC64_LOCAL_MASK) + != 1 << STO_PPC64_LOCAL_BIT))) + stub_type = ppc_stub_long_branch_notoc; + } + else if (stub_type != ppc_stub_plt_call) { /* Check whether we need a TOC adjusting stub. Since the linker pastes together pieces from @@ -12882,6 +13225,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) /* __tls_get_addr calls might be eliminated. */ if (stub_type != ppc_stub_plt_call + && stub_type != ppc_stub_plt_call_notoc && hash != NULL && (hash == htab->tls_get_addr || hash == htab->tls_get_addr_fd) @@ -12929,9 +13273,71 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_name, FALSE, FALSE); if (stub_entry != NULL) { - /* The proper stub has already been created. */ + enum ppc_stub_type old_type; + /* A stub has already been created, but it may + not be the required type. We shouldn't be + transitioning from plt_call to long_branch + stubs or vice versa, but we might be + upgrading from plt_call to plt_call_r2save or + from long_branch to long_branch_r2off. */ free (stub_name); - if (stub_type == ppc_stub_plt_call_r2save) + old_type = stub_entry->stub_type; + switch (old_type) + { + default: + abort (); + + case ppc_stub_save_res: + continue; + + case ppc_stub_plt_call: + case ppc_stub_plt_call_r2save: + case ppc_stub_plt_call_notoc: + case ppc_stub_plt_call_both: + if (stub_type == ppc_stub_plt_call) + continue; + else if (stub_type == ppc_stub_plt_call_r2save) + { + if (old_type == ppc_stub_plt_call_notoc) + stub_type = ppc_stub_plt_call_both; + } + else if (stub_type == ppc_stub_plt_call_notoc) + { + if (old_type == ppc_stub_plt_call_r2save) + stub_type = ppc_stub_plt_call_both; + } + else + abort (); + break; + + case ppc_stub_plt_branch: + case ppc_stub_plt_branch_r2off: + case ppc_stub_plt_branch_notoc: + case ppc_stub_plt_branch_both: + old_type += (ppc_stub_long_branch + - ppc_stub_plt_branch); + /* Fall through. */ + case ppc_stub_long_branch: + case ppc_stub_long_branch_r2off: + case ppc_stub_long_branch_notoc: + case ppc_stub_long_branch_both: + if (stub_type == ppc_stub_long_branch) + continue; + else if (stub_type == ppc_stub_long_branch_r2off) + { + if (old_type == ppc_stub_long_branch_notoc) + stub_type = ppc_stub_long_branch_both; + } + else if (stub_type == ppc_stub_long_branch_notoc) + { + if (old_type == ppc_stub_long_branch_r2off) + stub_type = ppc_stub_long_branch_both; + } + else + abort (); + break; + } + if (old_type < stub_type) stub_entry->stub_type = stub_type; continue; } @@ -12952,16 +13358,16 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) } stub_entry->stub_type = stub_type; - if (stub_type != ppc_stub_plt_call - && stub_type != ppc_stub_plt_call_r2save) + if (stub_type >= ppc_stub_plt_call + && stub_type <= ppc_stub_plt_call_both) { - stub_entry->target_value = code_value; - stub_entry->target_section = code_sec; + stub_entry->target_value = sym_value; + stub_entry->target_section = sym_sec; } else { - stub_entry->target_value = sym_value; - stub_entry->target_section = sym_sec; + stub_entry->target_value = code_value; + stub_entry->target_section = code_sec; } stub_entry->h = hash; stub_entry->plt_ent = plt_ent; @@ -13841,19 +14247,31 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, "linker stubs in %u groups\n", stub_sec_count), stub_sec_count); - sprintf (*stats + len, _(" branch %lu\n" - " toc adjust %lu\n" - " long branch %lu\n" - " long toc adj %lu\n" - " plt call %lu\n" - " plt call toc %lu\n" - " global entry %lu"), + sprintf (*stats + len, _(" branch %lu\n" + " branch toc adj %lu\n" + " branch notoc %lu\n" + " branch both %lu\n" + " long branch %lu\n" + " long toc adj %lu\n" + " long notoc %lu\n" + " long both %lu\n" + " plt call %lu\n" + " plt call save %lu\n" + " plt call notoc %lu\n" + " plt call both %lu\n" + " global entry %lu"), htab->stub_count[ppc_stub_long_branch - 1], htab->stub_count[ppc_stub_long_branch_r2off - 1], + htab->stub_count[ppc_stub_long_branch_notoc - 1], + htab->stub_count[ppc_stub_long_branch_both - 1], htab->stub_count[ppc_stub_plt_branch - 1], htab->stub_count[ppc_stub_plt_branch_r2off - 1], + htab->stub_count[ppc_stub_plt_branch_notoc - 1], + htab->stub_count[ppc_stub_plt_branch_both - 1], htab->stub_count[ppc_stub_plt_call - 1], htab->stub_count[ppc_stub_plt_call_r2save - 1], + htab->stub_count[ppc_stub_plt_call_notoc - 1], + htab->stub_count[ppc_stub_plt_call_both - 1], htab->stub_count[ppc_stub_global_entry - 1]); } return TRUE; @@ -14685,6 +15103,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Fall through. */ case R_PPC64_REL24: + case R_PPC64_REL24_NOTOC: case R_PPC64_PLTCALL: /* Calls to functions with a different TOC, such as calls to shared objects, need to alter the TOC pointer. This is @@ -14701,15 +15120,18 @@ ppc64_elf_relocate_section (bfd *output_bfd, htab); if (r_type == R_PPC64_PLTCALL && stub_entry != NULL - && (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) + && stub_entry->stub_type >= ppc_stub_plt_call + && stub_entry->stub_type <= ppc_stub_plt_call_both) stub_entry = NULL; if (stub_entry != NULL && (stub_entry->stub_type == ppc_stub_plt_call || stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both || stub_entry->stub_type == ppc_stub_plt_branch_r2off - || stub_entry->stub_type == ppc_stub_long_branch_r2off)) + || stub_entry->stub_type == ppc_stub_plt_branch_both + || stub_entry->stub_type == ppc_stub_long_branch_r2off + || stub_entry->stub_type == ppc_stub_long_branch_both)) { bfd_boolean can_plt_call = FALSE; @@ -14721,6 +15143,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* The function doesn't use or change r2. */ can_plt_call = TRUE; } + else if (r_type == R_PPC64_REL24_NOTOC) + { + /* NOTOC calls don't need to restore r2. */ + can_plt_call = TRUE; + } /* All of these stubs may modify r2, so there must be a branch and link followed by a nop. The nop is @@ -14802,8 +15229,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!can_plt_call) { - if (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) + if (stub_entry->stub_type >= ppc_stub_plt_call + && stub_entry->stub_type <= ppc_stub_plt_call_both) info->callbacks->einfo /* xgettext:c-format */ (_("%H: call to `%pT' lacks nop, can't restore toc; " @@ -14821,8 +15248,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, } if (can_plt_call - && (stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save)) + && stub_entry->stub_type >= ppc_stub_plt_call + && stub_entry->stub_type <= ppc_stub_plt_call_both) unresolved_reloc = FALSE; } @@ -14864,6 +15291,28 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* Don't use the stub if this branch is in range. */ stub_entry = NULL; + if (stub_entry != NULL + && (stub_entry->stub_type == ppc_stub_long_branch_notoc + || stub_entry->stub_type == ppc_stub_long_branch_both + || stub_entry->stub_type == ppc_stub_plt_branch_notoc + || stub_entry->stub_type == ppc_stub_plt_branch_both) + && (r_type != R_PPC64_REL24_NOTOC + || ((fdh ? fdh->elf.other : sym->st_other) + & STO_PPC64_LOCAL_MASK) == 1 << STO_PPC64_LOCAL_BIT) + && (relocation + addend - from + max_br_offset + < 2 * max_br_offset)) + stub_entry = NULL; + + if (stub_entry != NULL + && (stub_entry->stub_type == ppc_stub_long_branch_r2off + || stub_entry->stub_type == ppc_stub_long_branch_both + || stub_entry->stub_type == ppc_stub_plt_branch_r2off + || stub_entry->stub_type == ppc_stub_plt_branch_both) + && r_type == R_PPC64_REL24_NOTOC + && (relocation + addend - from + max_br_offset + < 2 * max_br_offset)) + stub_entry = NULL; + if (stub_entry != NULL) { /* Munge up the value and addend so that we call the stub @@ -14883,14 +15332,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, addend = 0; reloc_dest = DEST_STUB; - if ((stub_entry->stub_type == ppc_stub_plt_call - || stub_entry->stub_type == ppc_stub_plt_call_r2save) - && (ALWAYS_EMIT_R2SAVE - || stub_entry->stub_type == ppc_stub_plt_call_r2save) + if (((stub_entry->stub_type == ppc_stub_plt_call + && ALWAYS_EMIT_R2SAVE) + || stub_entry->stub_type == ppc_stub_plt_call_r2save + || stub_entry->stub_type == ppc_stub_plt_call_both) && rel + 1 < relend && rel[1].r_offset == rel->r_offset + 4 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) relocation += 4; + else if ((stub_entry->stub_type == ppc_stub_long_branch_both + || stub_entry->stub_type == ppc_stub_plt_branch_both + || stub_entry->stub_type == ppc_stub_plt_call_both) + && r_type == R_PPC64_REL24_NOTOC) + relocation += 4; } if (insn != 0) @@ -14923,7 +15377,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, else if (h != NULL && h->elf.root.type == bfd_link_hash_undefweak && h->elf.dynindx == -1 - && r_type == R_PPC64_REL24 + && (r_type == R_PPC64_REL24 + || r_type == R_PPC64_REL24_NOTOC) && relocation == 0 && addend == 0) { @@ -15300,6 +15755,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: + case R_PPC64_REL24_NOTOC: break; case R_PPC64_TPREL16: diff --git a/bfd/libbfd.h b/bfd/libbfd.h index cd4b096ba88..6c1e1ea9a59 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1469,6 +1469,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_PPC64_ADDR16_HIGHA", "BFD_RELOC_PPC64_ADDR64_LOCAL", "BFD_RELOC_PPC64_ENTRY", + "BFD_RELOC_PPC64_REL24_NOTOC", "BFD_RELOC_PPC_TLS", "BFD_RELOC_PPC_TLSGD", "BFD_RELOC_PPC_TLSLD", diff --git a/bfd/reloc.c b/bfd/reloc.c index c8ddb2f0600..b63473e12ae 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3011,6 +3011,8 @@ ENUMX BFD_RELOC_PPC64_ADDR64_LOCAL ENUMX BFD_RELOC_PPC64_ENTRY +ENUMX + BFD_RELOC_PPC64_REL24_NOTOC ENUMDOC Power(rs6000) and PowerPC relocations. diff --git a/gas/ChangeLog b/gas/ChangeLog index b704d8c8744..94b496bce93 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +2018-08-05 Alan Modra + + * config/tc-ppc.c (ppc_elf_suffix): Support @notoc. + (ppc_force_relocation, ppc_fix_adjustable): Handle REL24_NOTOC. + 2018-08-03 Dimitar Dimitrov * config/tc-pru.c (pru_regname_to_dw2regnum): Return the starting HW diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index eaa866dbd29..6135cb40f93 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -2085,6 +2085,7 @@ ppc_elf_suffix (char **str_p, expressionS *exp_p) MAP64 ("tprel@highera", BFD_RELOC_PPC64_TPREL16_HIGHERA), MAP64 ("tprel@highest", BFD_RELOC_PPC64_TPREL16_HIGHEST), MAP64 ("tprel@highesta", BFD_RELOC_PPC64_TPREL16_HIGHESTA), + MAP64 ("notoc", BFD_RELOC_PPC64_REL24_NOTOC), { (char *) 0, 0, 0, 0, BFD_RELOC_NONE } }; @@ -6416,6 +6417,7 @@ ppc_force_relocation (fixS *fix) case BFD_RELOC_PPC_BA26: case BFD_RELOC_PPC_B16: case BFD_RELOC_PPC_BA16: + case BFD_RELOC_PPC64_REL24_NOTOC: /* All branch fixups targeting a localentry symbol must force a relocation. */ if (fix->fx_addsy) @@ -6454,6 +6456,7 @@ ppc_fix_adjustable (fixS *fix) case BFD_RELOC_PPC_B16_BRNTAKEN: case BFD_RELOC_PPC_BA16_BRTAKEN: case BFD_RELOC_PPC_BA16_BRNTAKEN: + case BFD_RELOC_PPC64_REL24_NOTOC: if (fix->fx_addsy) { asymbol *bfdsym = symbol_get_bfdsym (fix->fx_addsy); diff --git a/ld/ChangeLog b/ld/ChangeLog index b32879df0a3..62ba5300777 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,12 @@ +2018-08-05 Alan Modra + + * testsuite/ld-powerpc/ext.d, + * testsuite/ld-powerpc/ext.s, + * testsuite/ld-powerpc/ext.lnk, + * testsuite/ld-powerpc/notoc.d, + * testsuite/ld-powerpc/notoc.s: New tests. + * testsuite/ld-powerpc/powerpc.exp: Run them. + 2018-08-05 Alan Modra * testsuite/ld-powerpc/elfv2exe.d: Adjust for stub symbol change. diff --git a/ld/testsuite/ld-powerpc/ext.d b/ld/testsuite/ld-powerpc/ext.d new file mode 100644 index 00000000000..61527f9be74 --- /dev/null +++ b/ld/testsuite/ld-powerpc/ext.d @@ -0,0 +1,17 @@ +#source: ext.s +#as: -a64 +#objdump: -dr +#target: powerpc64*-*-* +# Just assembles an object for notoc.d + +.* + +Disassembly of section \.text: + +0+ : + 0: (00 00 4c 3c|3c 4c 00 00) addis r2,r12,0 + (0|2): R_PPC64_REL16_HA \.TOC\.(|\+0x2) + 4: (00 00 42 38|38 42 00 00) addi r2,r2,0 + (4|6): R_PPC64_REL16_LO \.TOC\.\+0x(4|6) + 8: (00 00 00 60|60 00 00 00) nop + c: (20 00 80 4e|4e 80 00 20) blr diff --git a/ld/testsuite/ld-powerpc/ext.lnk b/ld/testsuite/ld-powerpc/ext.lnk new file mode 100644 index 00000000000..62c4a230bac --- /dev/null +++ b/ld/testsuite/ld-powerpc/ext.lnk @@ -0,0 +1,6 @@ +SECTIONS +{ + . = 0x8000000000000000; + .text.ext : { tmpdir/ext.o(.text) } +} +INSERT BEFORE .stab; diff --git a/ld/testsuite/ld-powerpc/ext.s b/ld/testsuite/ld-powerpc/ext.s new file mode 100644 index 00000000000..dd51d8f4f81 --- /dev/null +++ b/ld/testsuite/ld-powerpc/ext.s @@ -0,0 +1,9 @@ + .text + .globl ext +ext: +0: + addis 2,12,.TOC.-0b@ha + addi 2,2,.TOC.-0b@l + .localentry ext,.-0b + nop + blr diff --git a/ld/testsuite/ld-powerpc/notoc.d b/ld/testsuite/ld-powerpc/notoc.d new file mode 100644 index 00000000000..97e7274beef --- /dev/null +++ b/ld/testsuite/ld-powerpc/notoc.d @@ -0,0 +1,102 @@ +#source: notoc.s +#as: -a64 +#ld: --no-plt-localentry -T ext.lnk +#objdump: -dr +#target: powerpc64*-*-* + +.* + +Disassembly of section \.text: + +.* <.*\.long_branch\.f1>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (7c 00 00 48|48 00 00 7c) b .* + +.* <.*\.long_branch\.g1>: +.*: (18 00 41 f8|f8 41 00 18) std r2,24\(r1\) +.*: (8c 00 00 48|48 00 00 8c) b .* + +.* <.*\.plt_branch\.ext>: +.*: (a6 02 88 7d|7d 88 02 a6) mflr r12 +.*: (05 00 9f 42|42 9f 00 05) bcl .* +.*: (a6 02 68 7d|7d 68 02 a6) mflr r11 +.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12 +.*: (ff 7f 80 3d|3d 80 7f ff) lis r12,32767 +.*: (ff ff 8c 61|61 8c ff ff) ori r12,r12,65535 +.*: (c6 07 9c 79|79 9c 07 c6) rldicr r28,r12,32,31 +.*: (ff ef 8c 65|65 8c ef ff) oris r12,r12,61439 +.*: (28 ff 8c 61|61 8c ff 28) ori r12,r12,65320 +.*: (14 62 8b 7d|7d 8b 62 14) add r12,r11,r12 +.*: (a6 03 89 7d|7d 89 03 a6) mtctr r12 +.*: (20 04 80 4e|4e 80 04 20) bctr + +.* <.*\.long_branch\.f2>: +.*: (a6 02 88 7d|7d 88 02 a6) mflr r12 +.*: (05 00 9f 42|42 9f 00 05) bcl .* +.*: (a6 02 68 7d|7d 68 02 a6) mflr r11 +.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12 +.*: (64 00 8b 39|39 8b 00 64) addi r12,r11,100 +.*: (58 00 00 48|48 00 00 58) b .* + +.* <.*\.long_branch\.g2>: +.*: (a6 02 88 7d|7d 88 02 a6) mflr r12 +.*: (05 00 9f 42|42 9f 00 05) bcl .* +.*: (a6 02 68 7d|7d 68 02 a6) mflr r11 +.*: (a6 03 88 7d|7d 88 03 a6) mtlr r12 +.*: (80 00 8b 39|39 8b 00 80) addi r12,r11,128 +.*: (74 00 00 48|48 00 00 74) b .* + \.\.\. + +.* : +.*: (01 00 00 48|48 00 00 01) bl .* +.*: (bd ff ff 4b|4b ff ff bd) bl .* <.*\.long_branch\.f2> +.*: (11 00 00 48|48 00 00 11) bl .* +.*: (cd ff ff 4b|4b ff ff cd) bl .* <.*\.long_branch\.g2> +.*: (81 ff ff 4b|4b ff ff 81) bl .* <.*\.plt_branch\.ext> +.*: (20 00 80 4e|4e 80 00 20) blr + +.* : +.*: (a9 ff ff 4b|4b ff ff a9) bl .* <.*\.long_branch\.f2> +.*: (e5 ff ff 4b|4b ff ff e5) bl .* +.*: (b9 ff ff 4b|4b ff ff b9) bl .* <.*\.long_branch\.g2> +.*: (f5 ff ff 4b|4b ff ff f5) bl .* +.*: (20 00 80 4e|4e 80 00 20) blr + +.* : +.*: (02 10 40 3c|3c 40 10 02) lis r2,4098 +.*: (00 90 42 38|38 42 90 00) addi r2,r2,-28672 +.*: (4d ff ff 4b|4b ff ff 4d) bl .* <.*\.long_branch\.f1> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (f9 ff ff 4b|4b ff ff f9) bl .* +.*: (00 00 00 60|60 00 00 00) nop +.*: (45 ff ff 4b|4b ff ff 45) bl .* <.*\.long_branch\.g1> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (1d 00 00 48|48 00 00 1d) bl .* +.*: (00 00 00 60|60 00 00 00) nop +.*: (3d ff ff 4b|4b ff ff 3d) bl .* <.*\.plt_branch\.ext> +.*: (00 00 00 60|60 00 00 00) nop +.*: (20 00 80 4e|4e 80 00 20) blr + +.* : +.*: (02 10 40 3c|3c 40 10 02) lis r2,4098 +.*: (00 90 42 38|38 42 90 00) addi r2,r2,-28672 +.*: (cd ff ff 4b|4b ff ff cd) bl .* +.*: (00 00 00 60|60 00 00 00) nop +.*: (11 ff ff 4b|4b ff ff 11) bl .* <.*\.long_branch\.f1> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (f1 ff ff 4b|4b ff ff f1) bl .* +.*: (00 00 00 60|60 00 00 00) nop +.*: (09 ff ff 4b|4b ff ff 09) bl .* <.*\.long_branch\.g1> +.*: (18 00 41 e8|e8 41 00 18) ld r2,24\(r1\) +.*: (20 00 80 4e|4e 80 00 20) blr + +.* <_start>: +.*: (00 00 00 48|48 00 00 00) b .* <_start> + +Disassembly of section \.text\.ext: + +8000000000000000 : +8000000000000000: (02 10 40 3c|3c 40 10 02) lis r2,4098 +8000000000000004: (00 90 42 38|38 42 90 00) addi r2,r2,-28672 +8000000000000008: (00 00 00 60|60 00 00 00) nop +800000000000000c: (20 00 80 4e|4e 80 00 20) blr diff --git a/ld/testsuite/ld-powerpc/notoc.s b/ld/testsuite/ld-powerpc/notoc.s new file mode 100644 index 00000000000..8c620df3b41 --- /dev/null +++ b/ld/testsuite/ld-powerpc/notoc.s @@ -0,0 +1,56 @@ + .text + .globl f1, f2, g1, g2, _start + .weak ext + .abiversion 2 + +f1: + .localentry f1,1 + bl f1@notoc + bl f2@notoc + bl g1@notoc + bl g2@notoc + bl ext@notoc + blr + +g1: + .localentry g1,1 + bl f2@notoc + bl f1@notoc + bl g2@notoc + bl g1@notoc + blr + +f2: +0: + addis 2,12,.TOC.-0b@ha + addi 2,2,.TOC.-0b@l + .localentry f2,.-0b + bl f1 + nop + bl f2 + nop + bl g1 + nop + bl g2 + nop + bl ext + nop + blr + +g2: +0: + addis 2,12,.TOC.-0b@ha + addi 2,2,.TOC.-0b@l + .localentry g2,.-0b + bl f2 + nop + bl f1 + nop + bl g2 + nop + bl g1 + nop + blr + +_start: + b _start diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index ac563eba142..c4ab3decb87 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -331,6 +331,8 @@ if [ supports_ppc64 ] then { run_dump_test "dotsym2" run_dump_test "dotsym3" run_dump_test "dotsym4" + run_dump_test "ext" + run_dump_test "notoc" } run_dump_test "tlsld32" -- 2.30.2