X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf64-ppc.c;h=70fa5c3301ac5bf86ecea0c73172950c9a1a914e;hb=0c9663cbd41c27a8e20ca88a53ba3deae374f1d8;hp=e7e2e397666d097d87325297a4955525f5d2594a;hpb=397998fc32a34d3c8993ef46da45c3957a4dd402;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index e7e2e39766..70fa5c3301 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright (C) 1999-2014 Free Software Foundation, Inc. + Copyright (C) 1999-2016 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB , based on elf32-ppc.c by Ian Lance Taylor. Largely rewritten by Alan Modra. @@ -64,7 +64,7 @@ static bfd_vma opd_entry_value #define ELF_TARGET_ID PPC64_ELF_DATA #define ELF_MACHINE_CODE EM_PPC64 #define ELF_MAXPAGESIZE 0x10000 -#define ELF_COMMONPAGESIZE 0x1000 +#define ELF_COMMONPAGESIZE 0x10000 #define elf_info_to_howto ppc64_elf_info_to_howto #define elf_backend_want_got_sym 0 @@ -84,7 +84,6 @@ static bfd_vma opd_entry_value #define bfd_elf64_bfd_print_private_bfd_data ppc64_elf_print_private_bfd_data #define bfd_elf64_new_section_hook ppc64_elf_new_section_hook #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create -#define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free #define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab #define bfd_elf64_bfd_link_just_syms ppc64_elf_link_just_syms @@ -139,6 +138,8 @@ static bfd_vma opd_entry_value /* TOC base pointers offset from start of TOC. */ #define TOC_BASE_OFF 0x8000 +/* TOC base alignment. */ +#define TOC_BASE_ALIGN 256 /* Offset of tp and dtp pointers from start of TLS block. */ #define TP_OFFSET 0x7000 @@ -172,8 +173,12 @@ static bfd_vma opd_entry_value #define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ #define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ +#define LD_R2_0R12 0xe84c0000 /* ld %r2,0(%r12) */ +#define ADD_R2_R2_R12 0x7c426214 /* add %r2,%r2,%r12 */ -#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ +#define LIS_R2 0x3c400000 /* lis %r2,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_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ #define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ @@ -236,6 +241,23 @@ static bfd_vma opd_entry_value #ifndef NO_OPD_RELOCS #define NO_OPD_RELOCS 0 #endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +#endif + +static inline int +abiversion (bfd *abfd) +{ + return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; +} + +static inline void +set_abiversion (bfd *abfd, int ver) +{ + elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; + elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; +} #define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1) @@ -246,8 +268,8 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { /* This reloc does nothing. */ HOWTO (R_PPC64_NONE, /* type */ 0, /* rightshift */ - 2, /* size (0 = byte, 1 = short, 2 = long) */ - 32, /* bitsize */ + 3, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ @@ -2004,6 +2026,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ + /* Like R_PPC64_REL16_HA but for split field in addpcis. */ + HOWTO (R_PPC64_REL16DX_HA, /* type */ + 16, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + ppc64_elf_ha_reloc, /* special_function */ + "R_PPC64_REL16DX_HA", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0x1fffc1, /* dst_mask */ + TRUE), /* pcrel_offset */ + /* Like R_PPC64_ADDR16_HI, but no overflow. */ HOWTO (R_PPC64_ADDR16_HIGH, /* type */ 16, /* rightshift */ @@ -2094,6 +2131,21 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Marker reloc on ELFv2 large-model function entry. */ + HOWTO (R_PPC64_ENTRY, + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_PPC64_ENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + /* Like ADDR64, but use local entry point of function. */ HOWTO (R_PPC64_ADDR64_LOCAL, /* type */ 0, /* rightshift */ @@ -2149,13 +2201,10 @@ ppc_howto_init (void) { unsigned int i, type; - for (i = 0; - i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]); - i++) + for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++) { type = ppc64_elf_howto_raw[i].type; - BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table) - / sizeof (ppc64_elf_howto_table[0]))); + BFD_ASSERT (type < ARRAY_SIZE (ppc64_elf_howto_table)); ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i]; } } @@ -2397,6 +2446,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_HI16_S_PCREL: r = R_PPC64_REL16_HA; break; + case BFD_RELOC_PPC_REL16DX_HA: r = R_PPC64_REL16DX_HA; + break; + case BFD_RELOC_PPC64_ENTRY: r = R_PPC64_ENTRY; + break; case BFD_RELOC_PPC64_ADDR64_LOCAL: r = R_PPC64_ADDR64_LOCAL; break; case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT; @@ -2414,9 +2467,7 @@ ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, { unsigned int i; - for (i = 0; - i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]); - i++) + for (i = 0; i < ARRAY_SIZE (ppc64_elf_howto_raw); i++) if (ppc64_elf_howto_raw[i].name != NULL && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0) return &ppc64_elf_howto_raw[i]; @@ -2437,8 +2488,7 @@ ppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, ppc_howto_init (); type = ELF64_R_TYPE (dst->r_info); - if (type >= (sizeof (ppc64_elf_howto_table) - / sizeof (ppc64_elf_howto_table[0]))) + if (type >= ARRAY_SIZE (ppc64_elf_howto_table)) { (*_bfd_error_handler) (_("%B: invalid relocation type %d"), abfd, (int) type); @@ -2454,6 +2504,11 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, void *data, asection *input_section, bfd *output_bfd, char **error_message) { + enum elf_ppc64_reloc_type r_type; + long insn; + bfd_size_type octets; + bfd_vma value; + /* If this is a relocatable link (output_bfd test tells us), just call the generic function. Any adjustment will be done at final link time. */ @@ -2465,7 +2520,29 @@ ppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, We won't actually be using the low 16 bits, so trashing them doesn't matter. */ reloc_entry->addend += 0x8000; - return bfd_reloc_continue; + r_type = reloc_entry->howto->type; + if (r_type != R_PPC64_REL16DX_HA) + return bfd_reloc_continue; + + value = 0; + if (!bfd_is_com_section (symbol->section)) + value = symbol->value; + value += (reloc_entry->addend + + symbol->section->output_offset + + symbol->section->output_section->vma); + value -= (reloc_entry->address + + input_section->output_offset + + input_section->output_section->vma); + value = (bfd_signed_vma) value >> 16; + + octets = reloc_entry->address * bfd_octets_per_byte (abfd); + insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); + insn &= ~0x1fffc1; + insn |= (value & 0xffc1) | ((value & 0x3e) << 15); + bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); + if (value + 0x8000 > 0xffff) + return bfd_reloc_overflow; + return bfd_reloc_ok; } static bfd_reloc_status_type @@ -2488,6 +2565,30 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + symbol->section->output_section->vma + symbol->section->output_offset); } + else + { + elf_symbol_type *elfsym = (elf_symbol_type *) symbol; + + if (symbol->section->owner != abfd + && symbol->section->owner != NULL + && abiversion (symbol->section->owner) >= 2) + { + unsigned int i; + + for (i = 0; i < symbol->section->owner->symcount; ++i) + { + asymbol *symdef = symbol->section->owner->outsymbols[i]; + + if (strcmp (symdef->name, symbol->name) == 0) + { + elfsym = (elf_symbol_type *) symdef; + break; + } + } + } + reloc_entry->addend + += PPC64_LOCAL_ENTRY_OFFSET (elfsym->internal_elf_sym.st_other); + } return bfd_reloc_continue; } @@ -2787,12 +2888,15 @@ ppc64_elf_mkobject (bfd *abfd) } /* Fix bad default arch selected for a 64 bit input bfd when the - default is 32 bit. */ + default is 32 bit. Also select arch based on apuinfo. */ static bfd_boolean ppc64_elf_object_p (bfd *abfd) { - if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32) + if (!abfd->arch_info->the_default) + return TRUE; + + if (abfd->arch_info->bits_per_word == 32) { Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); @@ -2803,7 +2907,7 @@ ppc64_elf_object_p (bfd *abfd) BFD_ASSERT (abfd->arch_info->bits_per_word == 64); } } - return TRUE; + return _bfd_elf_ppc_set_arch (abfd); } /* Support for core dump NOTE sections. */ @@ -2919,7 +3023,9 @@ struct _ppc64_elf_section_data union { - /* An array with one entry for each opd function descriptor. */ + /* An array with one entry for each opd function descriptor, + and some spares since opd entries may be either 16 or 24 bytes. */ +#define OPD_NDX(OFF) ((OFF) >> 4) struct _opd_sec_data { /* Points to the function code section for local opd entries. */ @@ -2976,19 +3082,6 @@ get_opd_info (asection * sec) return &ppc64_elf_section_data (sec)->u.opd; return NULL; } - -static inline int -abiversion (bfd *abfd) -{ - return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; -} - -static inline void -set_abiversion (bfd *abfd, int ver) -{ - elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; - elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; -} /* Parameters for the qsort hook. */ static bfd_boolean synthetic_relocatable; @@ -3075,11 +3168,11 @@ compare_symbols (const void *ap, const void *bp) /* Search SYMS for a symbol of the given VALUE. */ static asymbol * -sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value) +sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value) { long mid; - if (id == -1) + if (id == (unsigned) -1) { while (lo < hi) { @@ -3122,7 +3215,8 @@ section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr) } /* Create synthetic symbols, effectively restoring "dot-symbol" function - entry syms. Also generate @plt symbols for the glink branch table. */ + entry syms. Also generate @plt symbols for the glink branch table. + Returns count of synthetic symbols in RET or -1 on error. */ static long ppc64_elf_get_synthetic_symtab (bfd *abfd, @@ -3265,6 +3359,8 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, } } + if (size == 0) + goto done; s = *ret = bfd_malloc (size); if (s == NULL) { @@ -3325,10 +3421,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents)) { + free_contents_and_exit_err: + count = -1; free_contents_and_exit: if (contents) free (contents); - count = -1; goto done; } @@ -3359,7 +3456,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf)) - goto free_contents_and_exit; + goto free_contents_and_exit_err; extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; @@ -3421,7 +3518,7 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, { slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE)) - goto free_contents_and_exit; + goto free_contents_and_exit_err; plt_count = relplt->size / sizeof (Elf64_External_Rela); size += plt_count * sizeof (asymbol); @@ -3436,9 +3533,11 @@ ppc64_elf_get_synthetic_symtab (bfd *abfd, } } + if (size == 0) + goto free_contents_and_exit; s = *ret = bfd_malloc (size); if (s == NULL) - goto free_contents_and_exit; + goto free_contents_and_exit_err; names = (char *) (s + count + plt_count + (resolv_vma != 0)); @@ -3684,7 +3783,7 @@ must_be_dyn_reloc (struct bfd_link_info *info, case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: case R_PPC64_TPREL64: - return !info->executable; + return !bfd_link_executable (info); } } @@ -3763,7 +3862,23 @@ enum ppc_stub_type { ppc_stub_plt_branch, ppc_stub_plt_branch_r2off, ppc_stub_plt_call, - ppc_stub_plt_call_r2save + ppc_stub_plt_call_r2save, + ppc_stub_global_entry, + ppc_stub_save_res +}; + +/* Information on stub grouping. */ +struct map_stub +{ + /* The stub section. */ + asection *stub_sec; + /* This is the section to which stubs in the group will be attached. */ + asection *link_sec; + /* Next group. */ + struct map_stub *next; + /* Whether to emit a copy of register save/restore functions in this + group. */ + int needs_save_res; }; struct ppc_stub_hash_entry { @@ -3773,8 +3888,8 @@ struct ppc_stub_hash_entry { enum ppc_stub_type stub_type; - /* The stub section. */ - asection *stub_sec; + /* Group information. */ + struct map_stub *group; /* Offset within stub_sec of the beginning of this stub. */ bfd_vma stub_offset; @@ -3788,10 +3903,6 @@ struct ppc_stub_hash_entry { struct ppc_link_hash_entry *h; struct plt_entry *plt_ent; - /* Where this stub is being called from, or, in the case of combined - stub sections, the first input section in the group. */ - asection *id_sec; - /* Symbol st_other. */ unsigned char other; }; @@ -3855,6 +3966,10 @@ struct ppc_link_hash_entry /* Set if we twiddled this symbol to weak at some stage. */ unsigned int was_undefined:1; + /* Set if this is an out-of-line register save/restore function, + with non-standard calling convention. */ + unsigned int save_res:1; + /* Contexts in which symbol is used in the GOT (or TOC). TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the corresponding relocs are encountered during check_relocs. @@ -3892,34 +4007,37 @@ struct ppc_link_hash_table /* Various options and other info passed from the linker. */ struct ppc64_elf_params *params; - /* Array to keep track of which stub sections have been created, and - information on stub grouping. */ - struct map_stub { - /* This is the section to which stubs in the group will be attached. */ - asection *link_sec; - /* The stub section. */ - asection *stub_sec; - /* Along with elf_gp, specifies the TOC pointer used in this group. */ + /* The size of sec_info below. */ + unsigned int sec_info_arr_size; + + /* Per-section array of extra section info. Done this way rather + than as part of ppc64_elf_section_data so we have the info for + non-ppc64 sections. */ + struct + { + /* Along with elf_gp, specifies the TOC pointer used by this section. */ bfd_vma toc_off; - } *stub_group; + + union + { + /* The section group that this section belongs to. */ + struct map_stub *group; + /* A temp section list pointer. */ + asection *list; + } u; + } *sec_info; + + /* Linked list of groups. */ + struct map_stub *group; /* Temp used when calculating TOC pointers. */ bfd_vma toc_curr; bfd *toc_bfd; asection *toc_first_sec; - /* Highest input section id. */ - int top_id; - - /* Highest output section index. */ - int top_index; - /* Used when adding symbols. */ struct ppc_link_hash_entry *dot_syms; - /* List of input sections for each output section. */ - asection **input_list; - /* Shortcuts to get to dynamic linker sections. */ asection *dynbss; asection *relbss; @@ -3937,7 +4055,7 @@ struct ppc_link_hash_table bfd_size_type got_reli_size; /* Statistics. */ - unsigned long stub_count[ppc_stub_plt_call_r2save]; + unsigned long stub_count[ppc_stub_global_entry]; /* Number of stubs against global syms. */ unsigned long stub_globals; @@ -4023,13 +4141,12 @@ stub_hash_newfunc (struct bfd_hash_entry *entry, /* Initialize the local fields. */ eh = (struct ppc_stub_hash_entry *) entry; eh->stub_type = ppc_stub_none; - eh->stub_sec = NULL; + eh->group = NULL; eh->stub_offset = 0; eh->target_value = 0; eh->target_section = NULL; eh->h = NULL; eh->plt_ent = NULL; - eh->id_sec = NULL; eh->other = 0; } @@ -4142,6 +4259,21 @@ tocsave_htab_eq (const void *p1, const void *p2) return e1->sec == e2->sec && e1->offset == e2->offset; } +/* Destroy a ppc64 ELF linker hash table. */ + +static void +ppc64_elf_link_hash_table_free (bfd *obfd) +{ + struct ppc_link_hash_table *htab; + + htab = (struct ppc_link_hash_table *) obfd->link.hash; + if (htab->tocsave_htab) + htab_delete (htab->tocsave_htab); + bfd_hash_table_free (&htab->branch_hash_table); + bfd_hash_table_free (&htab->stub_hash_table); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create a ppc64 ELF linker hash table. */ static struct bfd_link_hash_table * @@ -4166,7 +4298,7 @@ ppc64_elf_link_hash_table_create (bfd *abfd) if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc, sizeof (struct ppc_stub_hash_entry))) { - _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab); + _bfd_elf_link_hash_table_free (abfd); return NULL; } @@ -4175,7 +4307,7 @@ ppc64_elf_link_hash_table_create (bfd *abfd) sizeof (struct ppc_branch_hash_entry))) { bfd_hash_table_free (&htab->stub_hash_table); - _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab); + _bfd_elf_link_hash_table_free (abfd); return NULL; } @@ -4185,11 +4317,10 @@ ppc64_elf_link_hash_table_create (bfd *abfd) NULL); if (htab->tocsave_htab == NULL) { - bfd_hash_table_free (&htab->branch_hash_table); - bfd_hash_table_free (&htab->stub_hash_table); - _bfd_elf_link_hash_table_free ((struct bfd_link_hash_table *) htab); + ppc64_elf_link_hash_table_free (abfd); return NULL; } + htab->elf.root.hash_table_free = ppc64_elf_link_hash_table_free; /* Initializing two fields of the union is just cosmetic. We really only care about glist, but when compiled on a 32-bit host the @@ -4207,20 +4338,6 @@ ppc64_elf_link_hash_table_create (bfd *abfd) return &htab->elf.root; } -/* Free the derived linker hash table. */ - -static void -ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash) -{ - struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash; - - bfd_hash_table_free (&htab->stub_hash_table); - bfd_hash_table_free (&htab->branch_hash_table); - if (htab->tocsave_htab) - htab_delete (htab->tocsave_htab); - _bfd_elf_link_hash_table_free (hash); -} - /* Create sections for linker generated code. */ static bfd_boolean @@ -4231,14 +4348,20 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab = ppc_hash_table (info); - /* Create .sfpr for code to save and restore fp regs. */ flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", - flags); - if (htab->sfpr == NULL - || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) - return FALSE; + if (htab->params->save_restore_funcs) + { + /* Create .sfpr for code to save and restore fp regs. */ + htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", + flags); + if (htab->sfpr == NULL + || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) + return FALSE; + } + + if (bfd_link_relocatable (info)) + return TRUE; /* Create .glink for lazy dynamic linking support. */ htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", @@ -4282,7 +4405,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) || ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) return FALSE; - if (!info->shared) + if (!bfd_link_pic (info)) return TRUE; flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY @@ -4311,14 +4434,9 @@ ppc64_elf_init_stub_bfd (struct bfd_link_info *info, linker created stub bfd. This ensures that the GOT header is at the start of the output TOC section. */ htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; htab->elf.dynobj = params->stub_bfd; htab->params = params; - if (info->relocatable) - return TRUE; - return create_linkage_sections (htab->elf.dynobj, info); } @@ -4379,18 +4497,18 @@ ppc_get_stub_entry (const asection *input_section, struct ppc_link_hash_table *htab) { struct ppc_stub_hash_entry *stub_entry; - const asection *id_sec; + struct map_stub *group; /* If this input section is part of a group of sections sharing one stub section, then use the id of the first section in the group. Stub names need to include a section id, as there may well be more than one stub used to reach say, printf, and we need to distinguish between them. */ - id_sec = htab->stub_group[input_section->id].link_sec; + group = htab->sec_info[input_section->id].u.group; if (h != NULL && h->u.stub_cache != NULL && h->u.stub_cache->h == h - && h->u.stub_cache->id_sec == id_sec) + && h->u.stub_cache->group == group) { stub_entry = h->u.stub_cache; } @@ -4398,7 +4516,7 @@ ppc_get_stub_entry (const asection *input_section, { char *stub_name; - stub_name = ppc_stub_name (id_sec, sym_sec, h, rel); + stub_name = ppc_stub_name (group->link_sec, sym_sec, h, rel); if (stub_name == NULL) return NULL; @@ -4422,35 +4540,32 @@ ppc_add_stub (const char *stub_name, struct bfd_link_info *info) { struct ppc_link_hash_table *htab = ppc_hash_table (info); + struct map_stub *group; asection *link_sec; asection *stub_sec; struct ppc_stub_hash_entry *stub_entry; - link_sec = htab->stub_group[section->id].link_sec; - stub_sec = htab->stub_group[section->id].stub_sec; + group = htab->sec_info[section->id].u.group; + link_sec = group->link_sec; + stub_sec = group->stub_sec; if (stub_sec == NULL) { - stub_sec = htab->stub_group[link_sec->id].stub_sec; - if (stub_sec == NULL) - { - size_t namelen; - bfd_size_type len; - char *s_name; + size_t namelen; + bfd_size_type len; + char *s_name; - namelen = strlen (link_sec->name); - len = namelen + sizeof (STUB_SUFFIX); - s_name = bfd_alloc (htab->params->stub_bfd, len); - if (s_name == NULL) - return NULL; + namelen = strlen (link_sec->name); + len = namelen + sizeof (STUB_SUFFIX); + s_name = bfd_alloc (htab->params->stub_bfd, len); + if (s_name == NULL) + return NULL; - memcpy (s_name, link_sec->name, namelen); - memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); - stub_sec = (*htab->params->add_stub_section) (s_name, link_sec); - if (stub_sec == NULL) - return NULL; - htab->stub_group[link_sec->id].stub_sec = stub_sec; - } - htab->stub_group[section->id].stub_sec = stub_sec; + memcpy (s_name, link_sec->name, namelen); + memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); + stub_sec = (*htab->params->add_stub_section) (s_name, link_sec); + if (stub_sec == NULL) + return NULL; + group->stub_sec = stub_sec; } /* Enter this entry into the linker stub hash table. */ @@ -4463,9 +4578,8 @@ ppc_add_stub (const char *stub_name, return NULL; } - stub_entry->stub_sec = stub_sec; + stub_entry->group = group; stub_entry->stub_offset = 0; - stub_entry->id_sec = link_sec; return stub_entry; } @@ -4522,11 +4636,11 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) return FALSE; htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss"); - if (!info->shared) + if (!bfd_link_pic (info)) htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss"); if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss - || (!info->shared && !htab->relbss)) + || (!bfd_link_pic (info) && !htab->relbss)) abort (); return TRUE; @@ -4782,22 +4896,42 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, const char **name, flagword *flags ATTRIBUTE_UNUSED, asection **sec, - bfd_vma *value ATTRIBUTE_UNUSED) + bfd_vma *value) { - if ((ibfd->flags & DYNAMIC) == 0 - && ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE) - elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + && (ibfd->flags & DYNAMIC) == 0 + && bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour) + elf_tdata (info->output_bfd)->has_gnu_symbols |= elf_gnu_symbol_ifunc; - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + if (*sec != NULL + && strcmp ((*sec)->name, ".opd") == 0) { - if ((ibfd->flags & DYNAMIC) == 0) - elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + asection *code_sec; + + if (!(ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + || ELF_ST_TYPE (isym->st_info) == STT_FUNC)) + isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); + + /* If the symbol is a function defined in .opd, and the function + code is in a discarded group, let it appear to be undefined. */ + if (!bfd_link_relocatable (info) + && (*sec)->reloc_count != 0 + && opd_entry_value (*sec, *value, &code_sec, NULL, + FALSE) != (bfd_vma) -1 + && discarded_section (code_sec)) + { + *sec = bfd_und_section_ptr; + isym->st_shndx = SHN_UNDEF; + } } - else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC) - ; else if (*sec != NULL - && strcmp ((*sec)->name, ".opd") == 0) - isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); + && strcmp ((*sec)->name, ".toc") == 0 + && ELF_ST_TYPE (isym->st_info) == STT_OBJECT) + { + struct ppc_link_hash_table *htab = ppc_hash_table (info); + if (htab != NULL) + htab->params->object_in_toc = 1; + } if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) { @@ -4895,7 +5029,7 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) fdh = lookup_fdh (eh, htab); if (fdh == NULL) { - if (!info->relocatable + if (!bfd_link_relocatable (info) && (eh->elf.root.type == bfd_link_hash_undefined || eh->elf.root.type == bfd_link_hash_undefweak) && eh->elf.ref_regular) @@ -4939,81 +5073,77 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; struct ppc_link_hash_entry **p, *eh; + asection *opd = bfd_get_section_by_name (ibfd, ".opd"); - if (!is_ppc64_elf (info->output_bfd)) - return TRUE; - htab = ppc_hash_table (info); - if (htab == NULL) - return FALSE; - - if (is_ppc64_elf (ibfd)) + if (opd != NULL && opd->size != 0) { - asection *opd = bfd_get_section_by_name (ibfd, ".opd"); - - if (opd != NULL && opd->size != 0) + if (abiversion (ibfd) == 0) + set_abiversion (ibfd, 1); + else if (abiversion (ibfd) == 2) { - if (abiversion (ibfd) == 0) - set_abiversion (ibfd, 1); - else if (abiversion (ibfd) == 2) - { - info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" - " version %d\n"), - ibfd, abiversion (ibfd)); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if ((ibfd->flags & DYNAMIC) == 0 - && (opd->flags & SEC_RELOC) != 0 - && opd->reloc_count != 0 - && !bfd_is_abs_section (opd->output_section)) - { - /* Garbage collection needs some extra help with .opd sections. - We don't want to necessarily keep everything referenced by - relocs in .opd, as that would keep all functions. Instead, - if we reference an .opd symbol (a function descriptor), we - want to keep the function code symbol's section. This is - easy for global symbols, but for local syms we need to keep - information about the associated function section. */ - bfd_size_type amt; - asection **opd_sym_map; - - amt = opd->size * sizeof (*opd_sym_map) / 8; - opd_sym_map = bfd_zalloc (ibfd, amt); - if (opd_sym_map == NULL) - return FALSE; - ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map; - BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal); - ppc64_elf_section_data (opd)->sec_type = sec_opd; - } + info->callbacks->einfo (_("%P: %B .opd not allowed in ABI" + " version %d\n"), + ibfd, abiversion (ibfd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; } - /* For input files without an explicit abiversion in e_flags - we should have flagged any with symbol st_other bits set - as ELFv1 and above flagged those with .opd as ELFv2. - Set the output abiversion if not yet set, and for any input - still ambiguous, take its abiversion from the output. - Differences in ABI are reported later. */ - if (abiversion (info->output_bfd) == 0) - set_abiversion (info->output_bfd, abiversion (ibfd)); - else if (abiversion (ibfd) == 0) - set_abiversion (ibfd, abiversion (info->output_bfd)); - - p = &htab->dot_syms; - while ((eh = *p) != NULL) + if ((ibfd->flags & DYNAMIC) == 0 + && (opd->flags & SEC_RELOC) != 0 + && opd->reloc_count != 0 + && !bfd_is_abs_section (opd->output_section)) { - *p = NULL; - if (&eh->elf == htab->elf.hgot) - ; - else if (htab->elf.hgot == NULL - && strcmp (eh->elf.root.root.string, ".TOC.") == 0) - htab->elf.hgot = &eh->elf; - else if (!add_symbol_adjust (eh, info)) + /* Garbage collection needs some extra help with .opd sections. + We don't want to necessarily keep everything referenced by + relocs in .opd, as that would keep all functions. Instead, + if we reference an .opd symbol (a function descriptor), we + want to keep the function code symbol's section. This is + easy for global symbols, but for local syms we need to keep + information about the associated function section. */ + bfd_size_type amt; + asection **opd_sym_map; + + amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map); + opd_sym_map = bfd_zalloc (ibfd, amt); + if (opd_sym_map == NULL) return FALSE; - p = &eh->u.next_dot_sym; + ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map; + BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal); + ppc64_elf_section_data (opd)->sec_type = sec_opd; } } + if (!is_ppc64_elf (info->output_bfd)) + return TRUE; + htab = ppc_hash_table (info); + if (htab == NULL) + return FALSE; + + /* For input files without an explicit abiversion in e_flags + we should have flagged any with symbol st_other bits set + as ELFv1 and above flagged those with .opd as ELFv2. + Set the output abiversion if not yet set, and for any input + still ambiguous, take its abiversion from the output. + Differences in ABI are reported later. */ + if (abiversion (info->output_bfd) == 0) + set_abiversion (info->output_bfd, abiversion (ibfd)); + else if (abiversion (ibfd) == 0) + set_abiversion (ibfd, abiversion (info->output_bfd)); + + p = &htab->dot_syms; + while ((eh = *p) != NULL) + { + *p = NULL; + if (&eh->elf == htab->elf.hgot) + ; + else if (htab->elf.hgot == NULL + && strcmp (eh->elf.root.root.string, ".TOC.") == 0) + htab->elf.hgot = &eh->elf; + else if (!add_symbol_adjust (eh, info)) + return FALSE; + p = &eh->u.next_dot_sym; + } + /* Clear the list for non-ppc64 input files. */ p = &htab->dot_syms; while ((eh = *p) != NULL) @@ -5023,7 +5153,7 @@ ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info) } /* We need to fix the undefs list for any syms we have twiddled to - undef_weak. */ + undefweak. */ if (htab->twiddled_syms) { bfd_link_repair_undef_list (&htab->elf.root); @@ -5176,7 +5306,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection **opd_sym_map; struct elf_link_hash_entry *tga, *dottga; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; /* Don't do anything special with non-loaded, non-alloced sections. @@ -5214,7 +5344,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, enum elf_ppc64_reloc_type r_type; int tls_type; struct _ppc64_elf_section_data *ppc64_sec; - struct plt_entry **ifunc; + struct plt_entry **ifunc, **plt_list; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -5257,28 +5387,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; } } - r_type = ELF64_R_TYPE (rel->r_info); - if (is_branch_reloc (r_type)) - { - if (h != NULL && (h == tga || h == dottga)) - { - if (rel != relocs - && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD - || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD)) - /* We have a new-style __tls_get_addr call with a marker - reloc. */ - ; - else - /* Mark this section as having an old-style call. */ - sec->has_tls_get_addr_call = 1; - } - - /* STT_GNU_IFUNC symbols must have a PLT entry. */ - if (ifunc != NULL - && !update_plt_info (abfd, ifunc, rel->r_addend)) - return FALSE; - } + r_type = ELF64_R_TYPE (rel->r_info); switch (r_type) { case R_PPC64_TLSGD: @@ -5305,7 +5415,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HA: - if (!info->executable) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; tls_type = TLS_TLS | TLS_TPREL; goto dogottls; @@ -5378,7 +5488,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* We may also need a plt entry if the symbol turns out to be an ifunc. */ - if (h != NULL && !info->shared && abiversion (abfd) != 1) + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1) { if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) return FALSE; @@ -5390,27 +5500,29 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_PLT16_LO: case R_PPC64_PLT32: case R_PPC64_PLT64: - /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - if (h == NULL) - { - /* It does not make sense to have a procedure linkage - table entry for a local symbol. */ - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else + /* This symbol requires a procedure linkage table entry. */ + plt_list = ifunc; + if (h != NULL) { - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; h->needs_plt = 1; if (h->root.root.string[0] == '.' && h->root.root.string[1] != '\0') ((struct ppc_link_hash_entry *) h)->is_func = 1; + plt_list = &h->plt.plist; + } + if (plt_list == NULL) + { + /* It does not make sense to have a procedure linkage + table entry for a non-ifunc local symbol. */ + info->callbacks->einfo + (_("%P: %H: %s reloc against local symbol\n"), + abfd, sec, rel->r_offset, + ppc64_elf_howto_table[r_type]->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; } + if (!update_plt_info (abfd, plt_list, rel->r_addend)) + return FALSE; break; /* The following relocations don't need to propagate the @@ -5441,11 +5553,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL16_LO: case R_PPC64_REL16_HI: case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: break; /* Not supported as a dynamic relocation. */ case R_PPC64_ADDR64_LOCAL: - if (info->shared) + if (bfd_link_pic (info)) { if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) ppc_howto_init (); @@ -5469,6 +5582,10 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sec->has_toc_reloc = 1; break; + /* Marker reloc. */ + case R_PPC64_ENTRY: + break; + /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_PPC64_GNU_VTINHERIT: @@ -5518,24 +5635,46 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Fall through. */ case R_PPC64_REL24: - if (h != NULL && ifunc == NULL) + plt_list = ifunc; + if (h != NULL) { - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) - return FALSE; h->needs_plt = 1; if (h->root.root.string[0] == '.' && h->root.root.string[1] != '\0') ((struct ppc_link_hash_entry *) h)->is_func = 1; + if (h == tga || h == dottga) - sec->has_tls_reloc = 1; + { + sec->has_tls_reloc = 1; + if (rel != relocs + && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD + || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD)) + /* We have a new-style __tls_get_addr call with + a marker reloc. */ + ; + else + /* Mark this section as having an old-style call. */ + sec->has_tls_get_addr_call = 1; + } + plt_list = &h->plt.plist; } + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + if (plt_list + && !update_plt_info (abfd, plt_list, rel->r_addend)) + return FALSE; break; + case R_PPC64_ADDR14: + case R_PPC64_ADDR14_BRNTAKEN: + case R_PPC64_ADDR14_BRTAKEN: + case R_PPC64_ADDR24: + goto dodyn; + case R_PPC64_TPREL64: tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL; - if (!info->executable) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; goto dotlstoc; @@ -5611,10 +5750,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: - if (info->shared) + if (bfd_link_pic (info)) { - if (!info->executable) - info->flags |= DF_STATIC_TLS; + info->flags |= DF_STATIC_TLS; goto dodyn; } break; @@ -5645,7 +5783,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, s = bfd_section_from_elf_index (abfd, isym->st_shndx); if (s != NULL && s != sec) - opd_sym_map[rel->r_offset / 8] = s; + opd_sym_map[OPD_NDX (rel->r_offset)] = s; } } /* Fall through. */ @@ -5662,7 +5800,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_ADDR16_HIGHESTA: case R_PPC64_ADDR16_LO: case R_PPC64_ADDR16_LO_DS: - if (h != NULL && !info->shared && abiversion (abfd) != 1 + if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1 && rel->r_addend == 0) { /* We may need a .plt entry if this reloc refers to a @@ -5676,16 +5814,12 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL30: case R_PPC64_REL32: case R_PPC64_REL64: - case R_PPC64_ADDR14: - case R_PPC64_ADDR14_BRNTAKEN: - case R_PPC64_ADDR14_BRTAKEN: - case R_PPC64_ADDR24: case R_PPC64_ADDR32: case R_PPC64_UADDR16: case R_PPC64_UADDR32: case R_PPC64_UADDR64: case R_PPC64_TOC: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) /* We may need a copy reloc. */ h->non_got_ref = 1; @@ -5715,18 +5849,18 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, dynamic library if we manage to avoid copy relocs for the symbol. */ dodyn: - if ((info->shared + if ((bfd_link_pic (info) && (must_be_dyn_reloc (info, r_type) || (h != NULL && (!SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && (h->root.type == bfd_link_hash_defweak || !h->def_regular)) - || (!info->shared + || (!bfd_link_pic (info) && ifunc != NULL)) { /* We must copy these reloc types into the output file. @@ -5882,7 +6016,8 @@ ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) } /* OFFSET in OPD_SEC specifies a function descriptor. Return the address - of the code entry point, and its section. */ + of the code entry point, and its section, which must be in the same + object as OPD_SEC. Returns (bfd_vma) -1 on error. */ static bfd_vma opd_entry_value (asection *opd_sec, @@ -5909,6 +6044,10 @@ opd_entry_value (asection *opd_sec, ppc64_elf_tdata (opd_bfd)->opd.contents = contents; } + /* PR 17512: file: 64b9dfbb. */ + if (offset + 7 >= opd_sec->size || offset + 7 < offset) + return (bfd_vma) -1; + val = bfd_get_64 (opd_bfd, contents + offset); if (code_sec != NULL) { @@ -5944,10 +6083,12 @@ opd_entry_value (asection *opd_sec, relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs; if (relocs == NULL) relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE); + /* PR 17512: file: df8e1fd6. */ + if (relocs == NULL) + return (bfd_vma) -1; /* Go find the opd reloc at the sym address. */ lo = relocs; - BFD_ASSERT (lo != NULL); hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */ val = (bfd_vma) -1; while (lo < hi) @@ -5965,63 +6106,64 @@ opd_entry_value (asection *opd_sec, && ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC) { unsigned long symndx = ELF64_R_SYM (look->r_info); - asection *sec; + asection *sec = NULL; - if (symndx < symtab_hdr->sh_info - || elf_sym_hashes (opd_bfd) == NULL) + if (symndx >= symtab_hdr->sh_info + && elf_sym_hashes (opd_bfd) != NULL) { - Elf_Internal_Sym *sym; + struct elf_link_hash_entry **sym_hashes; + struct elf_link_hash_entry *rh; - sym = (Elf_Internal_Sym *) symtab_hdr->contents; - if (sym == NULL) + sym_hashes = elf_sym_hashes (opd_bfd); + rh = sym_hashes[symndx - symtab_hdr->sh_info]; + if (rh != NULL) { - size_t symcnt = symtab_hdr->sh_info; - if (elf_sym_hashes (opd_bfd) == NULL) - symcnt = symtab_hdr->sh_size / symtab_hdr->sh_entsize; - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, symcnt, - 0, NULL, NULL, NULL); - if (sym == NULL) + rh = elf_follow_link (rh); + if (rh->root.type != bfd_link_hash_defined + && rh->root.type != bfd_link_hash_defweak) break; - symtab_hdr->contents = (bfd_byte *) sym; + if (rh->root.u.def.section->owner == opd_bfd) + { + val = rh->root.u.def.value; + sec = rh->root.u.def.section; + } } + } - sym += symndx; - val = sym->st_value; - sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); - BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); - } - else + if (sec == NULL) { - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry *rh; + Elf_Internal_Sym *sym; - sym_hashes = elf_sym_hashes (opd_bfd); - rh = sym_hashes[symndx - symtab_hdr->sh_info]; - if (rh != NULL) + if (symndx < symtab_hdr->sh_info) { - rh = elf_follow_link (rh); - BFD_ASSERT (rh->root.type == bfd_link_hash_defined - || rh->root.type == bfd_link_hash_defweak); - val = rh->root.u.def.value; - sec = rh->root.u.def.section; + sym = (Elf_Internal_Sym *) symtab_hdr->contents; + if (sym == NULL) + { + size_t symcnt = symtab_hdr->sh_info; + sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, + symcnt, 0, + NULL, NULL, NULL); + if (sym == NULL) + break; + symtab_hdr->contents = (bfd_byte *) sym; + } + sym += symndx; } else { - /* Handle the odd case where we can be called - during bfd_elf_link_add_symbols before the - symbol hashes have been fully populated. */ - Elf_Internal_Sym *sym; - - sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 1, - symndx, NULL, NULL, NULL); + sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, + 1, symndx, + NULL, NULL, NULL); if (sym == NULL) break; - - val = sym->st_value; - sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); - free (sym); } + sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); + if (sec == NULL) + break; + BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); + val = sym->st_value; } + val += look->r_addend; if (code_off != NULL) *code_off = val; @@ -6032,7 +6174,7 @@ opd_entry_value (asection *opd_sec, else *code_sec = sec; } - if (sec != NULL && sec->output_section != NULL) + if (sec->output_section != NULL) val += sec->output_section->vma + sec->output_offset; } break; @@ -6062,7 +6204,23 @@ ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec, if (strcmp (sym->section->name, ".opd") == 0) { - if (opd_entry_value (sym->section, sym->value, + struct _opd_sec_data *opd = get_opd_info (sym->section); + bfd_vma symval = sym->value; + + if (opd != NULL + && opd->adjust != NULL + && elf_section_data (sym->section)->relocs != NULL) + { + /* opd_entry_value will use cached relocs that have been + adjusted, but with raw symbols. That means both local + and global symbols need adjusting. */ + long adjust = opd->adjust[OPD_NDX (symval)]; + if (adjust == -1) + return 0; + symval += adjust; + } + + if (opd_entry_value (sym->section, symval, &sec, code_off, TRUE) == (bfd_vma) -1) return 0; /* An old ABI binary with dot-syms has a size of 24 on the .opd @@ -6196,10 +6354,10 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) if ((eh->elf.root.type == bfd_link_hash_defined || eh->elf.root.type == bfd_link_hash_defweak) && (eh->elf.ref_dynamic - || (eh->elf.def_regular + || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf)) && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN - && (!info->executable + && (!bfd_link_executable (info) || info->export_dynamic || (eh->elf.dynamic && d != NULL @@ -6309,7 +6467,7 @@ ppc64_elf_gc_mark_hook (asection *sec, { rsec->gc_mark = 1; - rsec = opd->func_sec[(sym->st_value + rel->r_addend) / 8]; + rsec = opd->func_sec[OPD_NDX (sym->st_value + rel->r_addend)]; } } @@ -6329,7 +6487,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, struct got_entry **local_got_ents; const Elf_Internal_Rela *rel, *relend; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; if ((sec->flags & SEC_ALLOC) == 0) @@ -6351,6 +6509,7 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, unsigned long r_symndx; enum elf_ppc64_reloc_type r_type; struct elf_link_hash_entry *h = NULL; + struct plt_entry **plt_list; unsigned char tls_type = 0; r_symndx = ELF64_R_SYM (rel->r_info); @@ -6374,38 +6533,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, } } - if (is_branch_reloc (r_type)) - { - struct plt_entry **ifunc = NULL; - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - ifunc = &h->plt.plist; - } - else if (local_got_ents != NULL) - { - struct plt_entry **local_plt = (struct plt_entry **) - (local_got_ents + symtab_hdr->sh_info); - unsigned char *local_got_tls_masks = (unsigned char *) - (local_plt + symtab_hdr->sh_info); - if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) - ifunc = local_plt + r_symndx; - } - if (ifunc != NULL) - { - struct plt_entry *ent; - - for (ent = *ifunc; ent != NULL; ent = ent->next) - if (ent->addend == rel->r_addend) - break; - if (ent == NULL) - abort (); - if (ent->plt.refcount > 0) - ent->plt.refcount -= 1; - continue; - } - } - switch (r_type) { case R_PPC64_GOT_TLSLD16: @@ -6472,11 +6599,23 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_PPC64_REL14_BRNTAKEN: case R_PPC64_REL14_BRTAKEN: case R_PPC64_REL24: + plt_list = NULL; if (h != NULL) + plt_list = &h->plt.plist; + else if (local_got_ents != NULL) + { + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_ents + symtab_hdr->sh_info); + unsigned char *local_got_tls_masks = (unsigned char *) + (local_plt + symtab_hdr->sh_info); + if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) + plt_list = local_plt + r_symndx; + } + if (plt_list) { struct plt_entry *ent; - for (ent = h->plt.plist; ent != NULL; ent = ent->next) + for (ent = *plt_list; ent != NULL; ent = ent->next) if (ent->addend == rel->r_addend) break; if (ent != NULL && ent->plt.refcount > 0) @@ -6502,10 +6641,14 @@ struct sfpr_def_parms bfd_byte * (*write_tail) (bfd *, bfd_byte *, int); }; -/* Auto-generate _save*, _rest* functions in .sfpr. */ +/* Auto-generate _save*, _rest* functions in .sfpr. + If STUB_SEC is non-null, define alias symbols in STUB_SEC + instead. */ static bfd_boolean -sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm) +sfpr_define (struct bfd_link_info *info, + const struct sfpr_def_parms *parm, + asection *stub_sec) { struct ppc_link_hash_table *htab = ppc_hash_table (info); unsigned int i; @@ -6521,26 +6664,61 @@ sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm) for (i = parm->lo; i <= parm->hi; i++) { - struct elf_link_hash_entry *h; + struct ppc_link_hash_entry *h; sym[len + 0] = i / 10 + '0'; sym[len + 1] = i % 10 + '0'; - h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE); - if (h != NULL - && !h->def_regular) + h = (struct ppc_link_hash_entry *) + elf_link_hash_lookup (&htab->elf, sym, writing, TRUE, TRUE); + if (stub_sec != NULL) { - h->root.type = bfd_link_hash_defined; - h->root.u.def.section = htab->sfpr; - h->root.u.def.value = htab->sfpr->size; - h->type = STT_FUNC; - h->def_regular = 1; - _bfd_elf_link_hash_hide_symbol (info, h, TRUE); - writing = TRUE; - if (htab->sfpr->contents == NULL) + if (h != NULL + && h->elf.root.type == bfd_link_hash_defined + && h->elf.root.u.def.section == htab->sfpr) { - htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX); - if (htab->sfpr->contents == NULL) + struct elf_link_hash_entry *s; + char buf[32]; + sprintf (buf, "%08x.%s", stub_sec->id & 0xffffffff, sym); + s = elf_link_hash_lookup (&htab->elf, buf, TRUE, TRUE, FALSE); + if (s == NULL) return FALSE; + if (s->root.type == bfd_link_hash_new + || (s->root.type = bfd_link_hash_defined + && s->root.u.def.section == stub_sec)) + { + s->root.type = bfd_link_hash_defined; + s->root.u.def.section = stub_sec; + s->root.u.def.value = (stub_sec->size + + h->elf.root.u.def.value); + s->ref_regular = 1; + s->def_regular = 1; + s->ref_regular_nonweak = 1; + s->forced_local = 1; + s->non_elf = 0; + s->root.linker_def = 1; + } + } + continue; + } + if (h != NULL) + { + h->save_res = 1; + if (!h->elf.def_regular) + { + h->elf.root.type = bfd_link_hash_defined; + h->elf.root.u.def.section = htab->sfpr; + h->elf.root.u.def.value = htab->sfpr->size; + h->elf.type = STT_FUNC; + h->elf.def_regular = 1; + h->elf.non_elf = 0; + _bfd_elf_link_hash_hide_symbol (info, &h->elf, TRUE); + writing = TRUE; + if (htab->sfpr->contents == NULL) + { + htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX); + if (htab->sfpr->contents == NULL) + return FALSE; + } } } if (writing) @@ -6779,7 +6957,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) fdh = lookup_fdh (fh, htab); if (fdh == NULL - && !info->executable + && !bfd_link_executable (info) && (fh->elf.root.type == bfd_link_hash_undefined || fh->elf.root.type == bfd_link_hash_undefweak)) { @@ -6812,7 +6990,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) if (fdh != NULL && !fdh->elf.forced_local - && (!info->executable + && (!bfd_link_executable (info) || fdh->elf.def_dynamic || fdh->elf.ref_dynamic || (fdh->elf.root.type == bfd_link_hash_undefweak @@ -6851,6 +7029,22 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) return TRUE; } +static const struct sfpr_def_parms save_res_funcs[] = + { + { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail }, + { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail }, + { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail }, + { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail }, + { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail }, + { "_savefpr_", 14, 31, savefpr, savefpr0_tail }, + { "_restfpr_", 14, 29, restfpr, restfpr0_tail }, + { "_restfpr_", 30, 31, restfpr, restfpr0_tail }, + { "._savef", 14, 31, savefpr, savefpr1_tail }, + { "._restf", 14, 31, restfpr, restfpr1_tail }, + { "_savevr_", 20, 31, savevr, savevr_tail }, + { "_restvr_", 20, 31, restvr, restvr_tail } + }; + /* Called near the start of bfd_elf_size_dynamic_sections. We use this hook to a) provide some gcc support functions, and b) transfer dynamic linking information gathered so far on function code symbol @@ -6861,58 +7055,48 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; - unsigned int i; - static const struct sfpr_def_parms funcs[] = - { - { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail }, - { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail }, - { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail }, - { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail }, - { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail }, - { "_savefpr_", 14, 31, savefpr, savefpr0_tail }, - { "_restfpr_", 14, 29, restfpr, restfpr0_tail }, - { "_restfpr_", 30, 31, restfpr, restfpr0_tail }, - { "._savef", 14, 31, savefpr, savefpr1_tail }, - { "._restf", 14, 31, restfpr, restfpr1_tail }, - { "_savevr_", 20, 31, savevr, savevr_tail }, - { "_restvr_", 20, 31, restvr, restvr_tail } - }; htab = ppc_hash_table (info); if (htab == NULL) return FALSE; - if (!info->relocatable - && htab->elf.hgot != NULL) + /* Provide any missing _save* and _rest* functions. */ + if (htab->sfpr != NULL) + { + unsigned int i; + + htab->sfpr->size = 0; + for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) + if (!sfpr_define (info, &save_res_funcs[i], NULL)) + return FALSE; + if (htab->sfpr->size == 0) + htab->sfpr->flags |= SEC_EXCLUDE; + } + + if (bfd_link_relocatable (info)) + return TRUE; + + if (htab->elf.hgot != NULL) { _bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE); /* Make .TOC. defined so as to prevent it being made dynamic. The wrong value here is fixed later in ppc64_elf_set_toc. */ + if (!htab->elf.hgot->def_regular + || htab->elf.hgot->root.type != bfd_link_hash_defined) + { + htab->elf.hgot->root.type = bfd_link_hash_defined; + htab->elf.hgot->root.u.def.value = 0; + htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr; + htab->elf.hgot->def_regular = 1; + htab->elf.hgot->root.linker_def = 1; + } htab->elf.hgot->type = STT_OBJECT; - htab->elf.hgot->root.type = bfd_link_hash_defined; - htab->elf.hgot->root.u.def.value = 0; - htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr; - htab->elf.hgot->def_regular = 1; htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN); } - if (htab->sfpr == NULL) - /* We don't have any relocs. */ - return TRUE; - - /* Provide any missing _save* and _rest* functions. */ - htab->sfpr->size = 0; - if (htab->params->save_restore_funcs) - for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++) - if (!sfpr_define (info, &funcs[i])) - return FALSE; - elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); - if (htab->sfpr->size == 0) - htab->sfpr->flags |= SEC_EXCLUDE; - return TRUE; } @@ -6967,13 +7151,27 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, || (h->type != STT_GNU_IFUNC && (SYMBOL_CALLS_LOCAL (info, h) || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT - && h->root.type == bfd_link_hash_undefweak)))) + && h->root.type == bfd_link_hash_undefweak))) + || ((struct ppc_link_hash_entry *) h)->save_res) { h->plt.plist = NULL; h->needs_plt = 0; + h->pointer_equality_needed = 0; } else if (abiversion (info->output_bfd) == 2) { + /* Taking a function's address in a read/write section + doesn't require us to define the function symbol in the + executable on a global entry stub. A dynamic reloc can + be used instead. */ + if (h->pointer_equality_needed + && h->type != STT_GNU_IFUNC + && !readonly_dynrelocs (h)) + { + h->pointer_equality_needed = 0; + h->non_got_ref = 0; + } + /* After adjust_dynamic_symbol, non_got_ref set in the non-shared case means that we have allocated space in .dynbss for the symbol and thus dyn_relocs for this @@ -6983,10 +7181,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, relocations against this symbol to the PLT entry. Allow dynamic relocs if the reference is weak, and the dynamic relocs will not cause text relocation. */ - if (!h->ref_regular_nonweak - && h->non_got_ref - && h->type != STT_GNU_IFUNC - && !readonly_dynrelocs (h)) + else if (!h->ref_regular_nonweak + && h->non_got_ref + && h->type != STT_GNU_IFUNC + && !readonly_dynrelocs (h)) h->non_got_ref = 0; /* If making a plt entry, then we don't need copy relocs. */ @@ -7014,7 +7212,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (bfd_link_pic (info)) return TRUE; /* If there are no references to this symbol that do not use the @@ -7026,6 +7224,13 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!h->def_dynamic || !h->ref_regular || h->def_regular) return TRUE; + /* If -z nocopyreloc was given, don't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + /* If we didn't find any dynamic relocs in read-only sections, then we'll be keeping the dynamic relocs and avoiding the copy reloc. */ if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) @@ -7034,6 +7239,16 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, return TRUE; } + /* Protected variables do not work with .dynbss. The copy in + .dynbss won't be used by the shared library with the protected + definition for the variable. Text relocations are preferable + to an incorrect program. */ + if (h->protected_def) + { + h->non_got_ref = 0; + return TRUE; + } + if (h->plt.plist != NULL) { /* We should never get here, but unfortunately there are versions @@ -7072,7 +7287,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, s = htab->dynbss; - return _bfd_elf_adjust_dynamic_copy (h, s); + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* If given a function descriptor symbol, hide both the function code @@ -7357,7 +7572,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) opd = get_opd_info (sym_sec); if (opd != NULL && opd->adjust != NULL) { - long adjust = opd->adjust[eh->elf.root.u.def.value / 8]; + long adjust = opd->adjust[OPD_NDX (eh->elf.root.u.def.value)]; if (adjust == -1) { /* This entry has been deleted. */ @@ -7416,7 +7631,7 @@ dec_dynrel_count (bfd_vma r_info, case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: - if (!info->shared) + if (!bfd_link_pic (info)) return TRUE; case R_PPC64_TPREL64: @@ -7460,14 +7675,14 @@ dec_dynrel_count (bfd_vma r_info, return FALSE; } - if ((info->shared + if ((bfd_link_pic (info) && (must_be_dyn_reloc (info, r_type) || (h != NULL && (!SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && (h->root.type == bfd_link_hash_defweak || !h->def_regular))) @@ -7558,15 +7773,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) if (htab == NULL) return FALSE; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *sec; Elf_Internal_Rela *relstart, *rel, *relend; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Sym *local_syms; - bfd_vma offset; struct _opd_sec_data *opd; - bfd_boolean need_edit, add_aux_fields; + bfd_boolean need_edit, add_aux_fields, broken; bfd_size_type cnt_16b = 0; if (!is_ppc64_elf (ibfd)) @@ -7598,8 +7812,8 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) /* First run through the relocs to check they are sane, and to determine whether we need to edit this opd section. */ need_edit = FALSE; + broken = FALSE; need_pad = sec; - offset = 0; relend = relstart + sec->reloc_count; for (rel = relstart; rel < relend; ) { @@ -7608,13 +7822,14 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) asection *sym_sec; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; + bfd_vma offset; - /* .opd contains a regular array of 16 or 24 byte entries. We're + /* .opd contains an array of 16 or 24 byte entries. We're only interested in the reloc pointing to a function entry point. */ - if (rel->r_offset != offset - || rel + 1 >= relend - || (rel + 1)->r_offset != offset + 8) + offset = rel->r_offset; + if (rel + 1 == relend + || rel[1].r_offset != offset + 8) { /* If someone messes with .opd alignment then after a "ld -r" we might have padding in the middle of .opd. @@ -7624,7 +7839,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) broken_opd: (*_bfd_error_handler) (_("%B: .opd is not a regular array of opd entries"), ibfd); - need_edit = FALSE; + broken = TRUE; break; } @@ -7634,7 +7849,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) (*_bfd_error_handler) (_("%B: unexpected reloc type %u in .opd section"), ibfd, r_type); - need_edit = FALSE; + broken = TRUE; break; } @@ -7655,7 +7870,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) (*_bfd_error_handler) (_("%B: undefined sym `%s' in .opd section"), ibfd, sym_name); - need_edit = FALSE; + broken = TRUE; break; } @@ -7671,39 +7886,33 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) need_edit = TRUE; rel += 2; - if (rel == relend - || (rel + 1 == relend && rel->r_offset == offset + 16)) + if (rel + 1 == relend + || (rel + 2 < relend + && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC)) + ++rel; + + if (rel == relend) { if (sec->size == offset + 24) { need_pad = NULL; break; } - if (rel == relend && sec->size == offset + 16) + if (sec->size == offset + 16) { cnt_16b++; break; } goto broken_opd; } - - if (rel->r_offset == offset + 24) - offset += 24; - else if (rel->r_offset != offset + 16) - goto broken_opd; else if (rel + 1 < relend && ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64 && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC) { - offset += 16; - cnt_16b++; - } - else if (rel + 2 < relend - && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_ADDR64 - && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC) - { - offset += 24; - rel += 1; + if (rel[0].r_offset == offset + 16) + cnt_16b++; + else if (rel[0].r_offset != offset + 24) + goto broken_opd; } else goto broken_opd; @@ -7711,18 +7920,16 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) add_aux_fields = htab->params->non_overlapping_opd && cnt_16b > 0; - if (need_edit || add_aux_fields) + if (!broken && (need_edit || add_aux_fields)) { Elf_Internal_Rela *write_rel; Elf_Internal_Shdr *rel_hdr; bfd_byte *rptr, *wptr; bfd_byte *new_contents; - bfd_boolean skip; - long opd_ent_size; bfd_size_type amt; new_contents = NULL; - amt = sec->size * sizeof (long) / 8; + amt = OPD_NDX (sec->size) * sizeof (long); opd = &ppc64_elf_section_data (sec)->u.opd; opd->adjust = bfd_zalloc (sec->owner, amt); if (opd->adjust == NULL) @@ -7760,123 +7967,134 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) new_contents = bfd_malloc (sec->size + cnt_16b * 8); if (new_contents == NULL) return FALSE; - need_pad = FALSE; + need_pad = NULL; } wptr = new_contents; rptr = sec->contents; - write_rel = relstart; - skip = FALSE; - offset = 0; - opd_ent_size = 0; - for (rel = relstart; rel < relend; rel++) + for (rel = relstart; rel < relend; ) { unsigned long r_symndx; asection *sym_sec; struct elf_link_hash_entry *h; + struct ppc_link_hash_entry *fdh = NULL; Elf_Internal_Sym *sym; + long opd_ent_size; + Elf_Internal_Rela *next_rel; + bfd_boolean skip; r_symndx = ELF64_R_SYM (rel->r_info); if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx, ibfd)) goto error_ret; - if (rel->r_offset == offset) + next_rel = rel + 2; + if (next_rel + 1 == relend + || (next_rel + 2 < relend + && ELF64_R_TYPE (next_rel[2].r_info) == R_PPC64_TOC)) + ++next_rel; + + /* See if the .opd entry is full 24 byte or + 16 byte (with fd_aux entry overlapped with next + fd_func). */ + opd_ent_size = 24; + if (next_rel == relend) { - struct ppc_link_hash_entry *fdh = NULL; - - /* See if the .opd entry is full 24 byte or - 16 byte (with fd_aux entry overlapped with next - fd_func). */ - opd_ent_size = 24; - if ((rel + 2 == relend && sec->size == offset + 16) - || (rel + 3 < relend - && rel[2].r_offset == offset + 16 - && rel[3].r_offset == offset + 24 - && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_ADDR64 - && ELF64_R_TYPE (rel[3].r_info) == R_PPC64_TOC)) + if (sec->size == rel->r_offset + 16) opd_ent_size = 16; + } + else if (next_rel->r_offset == rel->r_offset + 16) + opd_ent_size = 16; - if (h != NULL - && h->root.root.string[0] == '.') - { - fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab); - if (fdh != NULL - && fdh->elf.root.type != bfd_link_hash_defined - && fdh->elf.root.type != bfd_link_hash_defweak) - fdh = NULL; - } + if (h != NULL + && h->root.root.string[0] == '.') + { + fdh = lookup_fdh ((struct ppc_link_hash_entry *) h, htab); + if (fdh != NULL + && fdh->elf.root.type != bfd_link_hash_defined + && fdh->elf.root.type != bfd_link_hash_defweak) + fdh = NULL; + } - skip = (sym_sec->owner != ibfd - || sym_sec->output_section == bfd_abs_section_ptr); - if (skip) + skip = (sym_sec->owner != ibfd + || sym_sec->output_section == bfd_abs_section_ptr); + if (skip) + { + if (fdh != NULL && sym_sec->owner == ibfd) { - if (fdh != NULL && sym_sec->owner == ibfd) - { - /* Arrange for the function descriptor sym - to be dropped. */ - fdh->elf.root.u.def.value = 0; - fdh->elf.root.u.def.section = sym_sec; - } - opd->adjust[rel->r_offset / 8] = -1; + /* Arrange for the function descriptor sym + to be dropped. */ + fdh->elf.root.u.def.value = 0; + fdh->elf.root.u.def.section = sym_sec; } - else - { - /* We'll be keeping this opd entry. */ + opd->adjust[OPD_NDX (rel->r_offset)] = -1; - if (fdh != NULL) - { - /* Redefine the function descriptor symbol to - this location in the opd section. It is - necessary to update the value here rather - than using an array of adjustments as we do - for local symbols, because various places - in the generic ELF code use the value - stored in u.def.value. */ - fdh->elf.root.u.def.value = wptr - new_contents; - fdh->adjust_done = 1; - } + if (NO_OPD_RELOCS || bfd_link_relocatable (info)) + rel = next_rel; + else + while (1) + { + if (!dec_dynrel_count (rel->r_info, sec, info, + NULL, h, sym)) + goto error_ret; - /* Local syms are a bit tricky. We could - tweak them as they can be cached, but - we'd need to look through the local syms - for the function descriptor sym which we - don't have at the moment. So keep an - array of adjustments. */ - opd->adjust[rel->r_offset / 8] - = (wptr - new_contents) - (rptr - sec->contents); - - if (wptr != rptr) - memcpy (wptr, rptr, opd_ent_size); - wptr += opd_ent_size; - if (add_aux_fields && opd_ent_size == 16) - { - memset (wptr, '\0', 8); - wptr += 8; - } - } - rptr += opd_ent_size; - offset += opd_ent_size; - } + if (++rel == next_rel) + break; - if (skip) - { - if (!NO_OPD_RELOCS - && !info->relocatable - && !dec_dynrel_count (rel->r_info, sec, info, - NULL, h, sym)) - goto error_ret; + r_symndx = ELF64_R_SYM (rel->r_info); + if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, + r_symndx, ibfd)) + goto error_ret; + } } else { + /* We'll be keeping this opd entry. */ + long adjust; + + if (fdh != NULL) + { + /* Redefine the function descriptor symbol to + this location in the opd section. It is + necessary to update the value here rather + than using an array of adjustments as we do + for local symbols, because various places + in the generic ELF code use the value + stored in u.def.value. */ + fdh->elf.root.u.def.value = wptr - new_contents; + fdh->adjust_done = 1; + } + + /* Local syms are a bit tricky. We could + tweak them as they can be cached, but + we'd need to look through the local syms + for the function descriptor sym which we + don't have at the moment. So keep an + array of adjustments. */ + adjust = (wptr - new_contents) - (rptr - sec->contents); + opd->adjust[OPD_NDX (rel->r_offset)] = adjust; + + if (wptr != rptr) + memcpy (wptr, rptr, opd_ent_size); + wptr += opd_ent_size; + if (add_aux_fields && opd_ent_size == 16) + { + memset (wptr, '\0', 8); + wptr += 8; + } + /* We need to adjust any reloc offsets to point to the - new opd entries. While we're at it, we may as well - remove redundant relocs. */ - rel->r_offset += opd->adjust[(offset - opd_ent_size) / 8]; - if (write_rel != rel) - memcpy (write_rel, rel, sizeof (*rel)); - ++write_rel; + new opd entries. */ + for ( ; rel != next_rel; ++rel) + { + rel->r_offset += adjust; + if (write_rel != rel) + memcpy (write_rel, rel, sizeof (*rel)); + ++write_rel; + } } + + rptr += opd_ent_size; } sec->size = wptr - new_contents; @@ -7911,7 +8129,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info) /* If we are doing a final link and the last .opd entry is just 16 byte long, add a 8 byte padding after it. */ - if (need_pad != NULL && !info->relocatable) + if (need_pad != NULL && !bfd_link_relocatable (info)) { bfd_byte *p; @@ -7974,7 +8192,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE)); - if (!htab->params->no_tls_get_addr_opt) + if (htab->params->tls_get_addr_opt) { struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd; @@ -8011,6 +8229,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga_fd->root.type = bfd_link_hash_indirect; tga_fd->root.u.i.link = &opt_fd->root; ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); + opt_fd->forced_local = 0; if (opt_fd->dynindx != -1) { /* Use __tls_get_addr_opt in dynamic relocations. */ @@ -8027,6 +8246,7 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) tga->root.type = bfd_link_hash_indirect; tga->root.u.i.link = &opt->root; ppc64_elf_copy_indirect_symbol (info, opt, tga); + opt->forced_local = 0; _bfd_elf_link_hash_hide_symbol (info, opt, tga->forced_local); htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; @@ -8041,8 +8261,8 @@ ppc64_elf_tls_setup (struct bfd_link_info *info) } } } - else - htab->params->no_tls_get_addr_opt = TRUE; + else if (htab->params->tls_get_addr_opt < 0) + htab->params->tls_get_addr_opt = 0; } return _bfd_elf_tls_setup (info->output_bfd, info); } @@ -8089,7 +8309,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) unsigned char *toc_ref; int pass; - if (info->relocatable || !info->executable) + if (!bfd_link_executable (info)) return TRUE; htab = ppc_hash_table (info); @@ -8105,7 +8325,7 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) and plt refcounts. */ toc_ref = NULL; for (pass = 0; pass < 2; ++pass) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { Elf_Internal_Sym *locsyms = NULL; asection *toc = bfd_get_section_by_name (ibfd, ".toc"); @@ -8184,7 +8404,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) if (h != NULL && h->root.type == bfd_link_hash_undefweak) ok_tprel = TRUE; - else + else if (sym_sec != NULL + && sym_sec->output_section != NULL) { value += sym_sec->output_offset; value += sym_sec->output_section->vma; @@ -8296,7 +8517,10 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info) else value = sym->st_value; value += rel->r_addend; - BFD_ASSERT (value < toc->size && value % 8 == 0); + if (value % 8 != 0) + continue; + BFD_ASSERT (value < toc->size + && toc->output_offset % 8 == 0); toc_ref_index = (value + toc->output_offset) / 8; if (r_type == R_PPC64_TLS || r_type == R_PPC64_TLSGD @@ -8602,7 +8826,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) htab->do_toc_opt = 1; toc_inf.global_toc_syms = TRUE; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *toc, *sec; Elf_Internal_Shdr *symtab_hdr; @@ -8742,6 +8966,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) goto error_ret; if (sym_sec == NULL + || sym_sec->output_section == NULL || discarded_section (sym_sec)) continue; @@ -9280,7 +9505,7 @@ allocate_got (struct elf_link_hash_entry *h, htab->elf.irelplt->size += rentsize; htab->got_reli_size += rentsize; } - else if ((info->shared + else if ((bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak)) @@ -9331,71 +9556,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab == NULL) return FALSE; - if ((htab->elf.dynamic_sections_created - && h->dynindx != -1 - && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) - || h->type == STT_GNU_IFUNC) - { - struct plt_entry *pent; - bfd_boolean doneone = FALSE; - for (pent = h->plt.plist; pent != NULL; pent = pent->next) - if (pent->plt.refcount > 0) - { - if (!htab->elf.dynamic_sections_created - || h->dynindx == -1) - { - s = htab->elf.iplt; - pent->plt.offset = s->size; - s->size += PLT_ENTRY_SIZE (htab); - s = htab->elf.irelplt; - } - else - { - /* If this is the first .plt entry, make room for the special - first entry. */ - s = htab->elf.splt; - if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE (htab); - - pent->plt.offset = s->size; - - /* Make room for this entry. */ - s->size += PLT_ENTRY_SIZE (htab); - - /* Make room for the .glink code. */ - s = htab->glink; - if (s->size == 0) - s->size += GLINK_CALL_STUB_SIZE; - if (htab->opd_abi) - { - /* We need bigger stubs past index 32767. */ - if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) - s->size += 4; - s->size += 2*4; - } - else - s->size += 4; - - /* We also need to make an entry in the .rela.plt section. */ - s = htab->elf.srelplt; - } - s->size += sizeof (Elf64_External_Rela); - doneone = TRUE; - } - else - pent->plt.offset = (bfd_vma) -1; - if (!doneone) - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - } - else - { - h->plt.plist = NULL; - h->needs_plt = 0; - } - eh = (struct ppc_link_hash_entry *) h; /* Run through the TLS GD got entries first if we're changing them to TPREL. */ @@ -9465,99 +9625,165 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) allocate_got (h, info, gent); } - if (eh->dyn_relocs == NULL - || (!htab->elf.dynamic_sections_created - && h->type != STT_GNU_IFUNC)) - return TRUE; - - /* In the shared -Bsymbolic case, discard space allocated for - dynamic pc-relative relocs against symbols which turn out to be - defined in regular objects. For the normal shared case, discard - space for relocs that have become local due to symbol visibility - changes. */ - - if (info->shared) + if (eh->dyn_relocs != NULL + && (htab->elf.dynamic_sections_created + || h->type == STT_GNU_IFUNC)) { - /* Relocs that use pc_count are those that appear on a call insn, - or certain REL relocs (see must_be_dyn_reloc) that can be - generated via assembly. We want calls to protected symbols to - resolve directly to the function rather than going via the plt. - If people want function pointer comparisons to work as expected - then they should avoid writing weird assembly. */ - if (SYMBOL_CALLS_LOCAL (info, h)) + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to + be defined in regular objects. For the normal shared case, + discard space for relocs that have become local due to symbol + visibility changes. */ + + if (bfd_link_pic (info)) { - struct elf_dyn_relocs **pp; + /* Relocs that use pc_count are those that appear on a call + insn, or certain REL relocs (see must_be_dyn_reloc) that + can be generated via assembly. We want calls to + protected symbols to resolve directly to the function + rather than going via the plt. If people want function + pointer comparisons to work as expected then they should + avoid writing weird assembly. */ + if (SYMBOL_CALLS_LOCAL (info, h)) + { + struct elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + /* Also discard relocs on undefined weak syms with + non-default visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) { - p->count -= p->pc_count; - p->pc_count = 0; - if (p->count == 0) - *pp = p->next; - else - pp = &p->next; + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } } } - - /* Also discard relocs on undefined weak syms with non-default - visibility. */ - if (eh->dyn_relocs != NULL - && h->root.type == bfd_link_hash_undefweak) + else if (h->type == STT_GNU_IFUNC) { - if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + if (!h->non_got_ref) eh->dyn_relocs = NULL; + } + else if (ELIMINATE_COPY_RELOCS) + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - else if (h->dynindx == -1 - && !h->forced_local) + if (!h->non_got_ref + && !h->def_regular) { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; - } - } - } - else if (h->type == STT_GNU_IFUNC) - { - if (!h->non_got_ref) - eh->dyn_relocs = NULL; - } - else if (ELIMINATE_COPY_RELOCS) - { - /* For the non-shared case, discard space for relocs against - symbols which turn out to need copy relocs or are not - dynamic. */ + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } - if (!h->non_got_ref - && !h->def_regular) - { - /* Make sure this symbol is output as a dynamic symbol. - Undefined weak syms won't yet be marked as dynamic. */ - if (h->dynindx == -1 - && !h->forced_local) - { - if (! bfd_elf_link_record_dynamic_symbol (info, h)) - return FALSE; + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; } - /* If that succeeded, we know we'll be keeping all the - relocs. */ - if (h->dynindx != -1) - goto keep; - } + eh->dyn_relocs = NULL; - eh->dyn_relocs = NULL; + keep: ; + } - keep: ; + /* Finally, allocate space. */ + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + if (eh->elf.type == STT_GNU_IFUNC) + sreloc = htab->elf.irelplt; + sreloc->size += p->count * sizeof (Elf64_External_Rela); + } } - /* Finally, allocate space. */ - for (p = eh->dyn_relocs; p != NULL; p = p->next) + if ((htab->elf.dynamic_sections_created + && h->dynindx != -1 + && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)) + || h->type == STT_GNU_IFUNC) + { + struct plt_entry *pent; + bfd_boolean doneone = FALSE; + for (pent = h->plt.plist; pent != NULL; pent = pent->next) + if (pent->plt.refcount > 0) + { + if (!htab->elf.dynamic_sections_created + || h->dynindx == -1) + { + s = htab->elf.iplt; + pent->plt.offset = s->size; + s->size += PLT_ENTRY_SIZE (htab); + s = htab->elf.irelplt; + } + else + { + /* If this is the first .plt entry, make room for the special + first entry. */ + s = htab->elf.splt; + if (s->size == 0) + s->size += PLT_INITIAL_ENTRY_SIZE (htab); + + pent->plt.offset = s->size; + + /* Make room for this entry. */ + s->size += PLT_ENTRY_SIZE (htab); + + /* Make room for the .glink code. */ + s = htab->glink; + if (s->size == 0) + s->size += GLINK_CALL_STUB_SIZE; + if (htab->opd_abi) + { + /* We need bigger stubs past index 32767. */ + if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) + s->size += 4; + s->size += 2*4; + } + else + s->size += 4; + + /* We also need to make an entry in the .rela.plt section. */ + s = htab->elf.srelplt; + } + s->size += sizeof (Elf64_External_Rela); + doneone = TRUE; + } + else + pent->plt.offset = (bfd_vma) -1; + if (!doneone) + { + h->plt.plist = NULL; + h->needs_plt = 0; + } + } + else { - asection *sreloc = elf_section_data (p->sec)->sreloc; - if (eh->elf.type == STT_GNU_IFUNC) - sreloc = htab->elf.irelplt; - sreloc->size += p->count * sizeof (Elf64_External_Rela); + h->plt.plist = NULL; + h->needs_plt = 0; } return TRUE; @@ -9650,7 +9876,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, if (htab->elf.dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) @@ -9662,7 +9888,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry **lgot_ents; struct got_entry **end_lgot_ents; @@ -9742,7 +9968,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, htab->elf.irelplt->size += rel_size; htab->got_reli_size += rel_size; } - else if (info->shared) + else if (bfd_link_pic (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += rel_size; @@ -9780,11 +10006,11 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, if (htab->glink != NULL) htab->glink->rawsize = htab->glink->size; - if (!htab->opd_abi && !info->shared) + if (!htab->opd_abi && !bfd_link_pic (info)) elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info); first_tlsld = NULL; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent; @@ -9807,7 +10033,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, ent->got.offset = s->size; ent->owner = ibfd; s->size += 16; - if (info->shared) + if (bfd_link_pic (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += sizeof (Elf64_External_Rela); @@ -9892,7 +10118,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, return FALSE; } - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { if (!is_ppc64_elf (ibfd)) continue; @@ -9937,7 +10163,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (info->executable) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; @@ -9960,7 +10186,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd, return FALSE; } - tls_opt = (!htab->params->no_tls_get_addr_opt + tls_opt = (htab->params->tls_get_addr_opt && htab->tls_get_addr_fd != NULL && htab->tls_get_addr_fd->elf.plt.plist != NULL); if (tls_opt || !htab->opd_abi) @@ -10134,7 +10360,10 @@ plt_stub_size (struct ppc_link_hash_table *htab, size += 4; if (htab->params->plt_static_chain) size += 4; - if (htab->params->plt_thread_safe) + if (htab->params->plt_thread_safe + && htab->elf.dynamic_sections_created + && stub_entry->h != NULL + && stub_entry->h->elf.dynindx != -1) size += 8; if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off)) size += 4; @@ -10142,7 +10371,7 @@ plt_stub_size (struct ppc_link_hash_table *htab, if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) - && !htab->params->no_tls_get_addr_opt) + && htab->params->tls_get_addr_opt) size += 13 * 4; return size; } @@ -10156,10 +10385,10 @@ plt_stub_pad (struct ppc_link_hash_table *htab, { int stub_align = 1 << htab->params->plt_stub_align; unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); - bfd_vma stub_off = stub_entry->stub_sec->size; + bfd_vma stub_off = stub_entry->group->stub_sec->size; if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) - > (stub_size & -stub_align)) + > ((stub_size - 1) & -stub_align)) return stub_align - (stub_off & (stub_align - 1)); return 0; } @@ -10174,17 +10403,19 @@ build_plt_stub (struct ppc_link_hash_table *htab, bfd *obfd = htab->params->stub_bfd; bfd_boolean plt_load_toc = htab->opd_abi; bfd_boolean plt_static_chain = htab->params->plt_static_chain; - bfd_boolean plt_thread_safe = htab->params->plt_thread_safe; + bfd_boolean plt_thread_safe = (htab->params->plt_thread_safe + && htab->elf.dynamic_sections_created + && stub_entry->h != NULL + && stub_entry->h->elf.dynindx != -1); bfd_boolean use_fake_dep = plt_thread_safe; bfd_vma cmp_branch_off = 0; if (!ALWAYS_USE_FAKE_DEP && plt_load_toc && plt_thread_safe - && !(stub_entry->h != NULL - && (stub_entry->h == htab->tls_get_addr_fd - || stub_entry->h == htab->tls_get_addr) - && !htab->params->no_tls_get_addr_opt)) + && !((stub_entry->h == htab->tls_get_addr_fd + || stub_entry->h == htab->tls_get_addr) + && htab->params->tls_get_addr_opt)) { bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab)) @@ -10197,7 +10428,7 @@ build_plt_stub (struct ppc_link_hash_table *htab, to = (glinkoff + htab->glink->output_offset + htab->glink->output_section->vma); - from = (p - stub_entry->stub_sec->contents + from = (p - stub_entry->group->stub_sec->contents + 4 * (ALWAYS_EMIT_R2SAVE || stub_entry->stub_type == ppc_stub_plt_call_r2save) + 4 * (PPC_HA (offset) != 0) @@ -10205,8 +10436,8 @@ build_plt_stub (struct ppc_link_hash_table *htab, != PPC_HA (offset)) + 4 * (plt_static_chain != 0) + 20 - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); cmp_branch_off = to - from; use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26); } @@ -10376,8 +10607,8 @@ build_tls_get_addr_stub (struct ppc_link_hash_table *htab, p = build_plt_stub (htab, stub_entry, p, offset, r); bfd_put_32 (obfd, BCTRL, p - 4); - bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4; + bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; bfd_put_32 (obfd, MTLR_R11, p), p += 4; bfd_put_32 (obfd, BLR, p), p += 4; @@ -10419,7 +10650,7 @@ get_r2off (struct bfd_link_info *info, struct ppc_stub_hash_entry *stub_entry) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_vma r2off = htab->stub_group[stub_entry->target_section->id].toc_off; + bfd_vma r2off = htab->sec_info[stub_entry->target_section->id].toc_off; if (r2off == 0) { @@ -10437,14 +10668,14 @@ get_r2off (struct bfd_link_info *info, info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"), stub_entry->h->elf.root.root.string); bfd_set_error (bfd_error_bad_value); - return 0; + return (bfd_vma) -1; } if (!bfd_get_section_contents (opd->owner, opd, buf, opd_off + 8, 8)) - return 0; + return (bfd_vma) -1; r2off = bfd_get_64 (opd->owner, buf); r2off -= elf_gp (info->output_bfd); } - r2off -= htab->stub_group[stub_entry->id_sec->id].toc_off; + r2off -= htab->sec_info[stub_entry->group->link_sec->id].toc_off; return r2off; } @@ -10471,8 +10702,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) return FALSE; /* Make a note of the offset within the stubs for this entry. */ - stub_entry->stub_offset = stub_entry->stub_sec->size; - loc = stub_entry->stub_sec->contents + stub_entry->stub_offset; + stub_entry->stub_offset = stub_entry->group->stub_sec->size; + loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset; htab->stub_count[stub_entry->stub_type - 1] += 1; switch (stub_entry->stub_type) @@ -10488,31 +10719,36 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) /* And this is where we are coming from. */ off -= (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); size = 4; if (stub_entry->stub_type == ppc_stub_long_branch_r2off) { bfd_vma r2off = get_r2off (info, stub_entry); - if (r2off == 0) + if (r2off == (bfd_vma) -1) { htab->stub_error = TRUE; return FALSE; } bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); loc += 4; - size = 12; + size = 8; if (PPC_HA (r2off) != 0) { - size = 16; bfd_put_32 (htab->params->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); loc += 4; + size += 4; + } + if (PPC_LO (r2off) != 0) + { + bfd_put_32 (htab->params->stub_bfd, + ADDI_R2_R2 | PPC_LO (r2off), loc); + loc += 4; + size += 4; } - bfd_put_32 (htab->params->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); - loc += 4; off -= size - 4; } bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc); @@ -10528,10 +10764,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { - r = get_relocs (stub_entry->stub_sec, 1); + r = get_relocs (stub_entry->group->stub_sec, 1); if (r == NULL) return FALSE; - r->r_offset = loc - stub_entry->stub_sec->contents; + r->r_offset = loc - stub_entry->group->stub_sec->contents; r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); r->r_addend = dest; if (stub_entry->h != NULL) @@ -10638,7 +10874,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = (dest - elf_gp (htab->brlt->output_section->owner) - - htab->stub_group[stub_entry->id_sec->id].toc_off); + - htab->sec_info[stub_entry->group->link_sec->id].toc_off); if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { @@ -10652,10 +10888,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (info->emitrelocations) { - r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0)); + r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0)); if (r == NULL) return FALSE; - r[0].r_offset = loc - stub_entry->stub_sec->contents; + r[0].r_offset = loc - stub_entry->group->stub_sec->contents; if (bfd_big_endian (info->output_bfd)) r[0].r_offset += 2; if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) @@ -10693,7 +10929,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) { bfd_vma r2off = get_r2off (info, stub_entry); - if (r2off == 0 && htab->opd_abi) + if (r2off == (bfd_vma) -1) { htab->stub_error = TRUE; return FALSE; @@ -10744,11 +10980,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh); /* If the old-ABI "dot-symbol" is undefined make it weak so - we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. - FIXME: We used to define the symbol on one of the call - stubs instead, which is why we test symbol section id - against htab->top_id in various places. Likely all - these checks could now disappear. */ + we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. */ if (fh->elf.root.type == bfd_link_hash_undefined) fh->elf.root.type = bfd_link_hash_undefweak; /* Stop undo_symbol_twiddle changing it back to undefined. */ @@ -10792,7 +11024,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = (dest - elf_gp (plt->output_section->owner) - - htab->stub_group[stub_entry->id_sec->id].toc_off); + - htab->sec_info[stub_entry->group->link_sec->id].toc_off); if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) { @@ -10810,15 +11042,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) { unsigned pad = plt_stub_pad (htab, stub_entry, off); - stub_entry->stub_sec->size += pad; - stub_entry->stub_offset = stub_entry->stub_sec->size; + stub_entry->group->stub_sec->size += pad; + stub_entry->stub_offset = stub_entry->group->stub_sec->size; loc += pad; } r = NULL; if (info->emitrelocations) { - r = get_relocs (stub_entry->stub_sec, + r = get_relocs (stub_entry->group->stub_sec, ((PPC_HA (off) != 0) + (htab->opd_abi ? 2 + (htab->params->plt_static_chain @@ -10826,7 +11058,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) : 1))); if (r == NULL) return FALSE; - r[0].r_offset = loc - stub_entry->stub_sec->contents; + r[0].r_offset = loc - stub_entry->group->stub_sec->contents; if (bfd_big_endian (info->output_bfd)) r[0].r_offset += 2; r[0].r_addend = dest; @@ -10834,19 +11066,22 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd || stub_entry->h == htab->tls_get_addr) - && !htab->params->no_tls_get_addr_opt) + && htab->params->tls_get_addr_opt) p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); else p = build_plt_stub (htab, stub_entry, loc, off, r); size = p - loc; break; + case ppc_stub_save_res: + return TRUE; + default: BFD_FAIL (); return FALSE; } - stub_entry->stub_sec->size += size; + stub_entry->group->stub_sec->size += size; if (htab->params->emit_stub_syms) { @@ -10874,13 +11109,14 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (h->root.type == bfd_link_hash_new) { h->root.type = bfd_link_hash_defined; - h->root.u.def.section = stub_entry->stub_sec; + h->root.u.def.section = stub_entry->group->stub_sec; h->root.u.def.value = stub_entry->stub_offset; h->ref_regular = 1; h->def_regular = 1; h->ref_regular_nonweak = 1; h->forced_local = 1; h->non_elf = 0; + h->root.linker_def = 1; } } @@ -10908,6 +11144,18 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab == NULL) return FALSE; + if (stub_entry->h != NULL + && stub_entry->h->save_res + && stub_entry->h->elf.root.type == bfd_link_hash_defined + && stub_entry->h->elf.root.u.def.section == htab->sfpr) + { + /* Don't make stubs to out-of-line register save/restore + functions. Instead, emit copies of the functions. */ + stub_entry->group->needs_save_res = 1; + stub_entry->stub_type = ppc_stub_save_res; + return TRUE; + } + if (stub_entry->stub_type == ppc_stub_plt_call || stub_entry->stub_type == ppc_stub_plt_call_r2save) { @@ -10923,20 +11171,20 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off += (plt->output_offset + plt->output_section->vma - elf_gp (plt->output_section->owner) - - htab->stub_group[stub_entry->id_sec->id].toc_off); + - htab->sec_info[stub_entry->group->link_sec->id].toc_off); size = plt_stub_size (htab, stub_entry, off); if (htab->params->plt_stub_align) size += plt_stub_pad (htab, stub_entry, off); if (info->emitrelocations) { - stub_entry->stub_sec->reloc_count + 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->stub_sec->flags |= SEC_RELOC; + stub_entry->group->stub_sec->flags |= SEC_RELOC; } } else @@ -10949,9 +11197,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) off = (stub_entry->target_value + stub_entry->target_section->output_offset + stub_entry->target_section->output_section->vma); - off -= (stub_entry->stub_sec->size - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + off -= (stub_entry->group->stub_sec->size + + stub_entry->group->stub_sec->output_offset + + stub_entry->group->stub_sec->output_section->vma); /* Reset the stub type from the plt variant in case we now can reach with a shorter stub. */ @@ -10962,14 +11210,16 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->stub_type == ppc_stub_long_branch_r2off) { r2off = get_r2off (info, stub_entry); - if (r2off == 0 && htab->opd_abi) + if (r2off == (bfd_vma) -1) { htab->stub_error = TRUE; return FALSE; } - size = 12; + size = 8; if (PPC_HA (r2off) != 0) - size = 16; + size += 4; + if (PPC_LO (r2off) != 0) + size += 4; off -= size - 4; } @@ -10979,7 +11229,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 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)) + && r2off == 0 + && htab->sec_info[stub_entry->target_section->id].toc_off == 0)) { struct ppc_branch_hash_entry *br_entry; @@ -11014,12 +11265,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) + htab->brlt->output_offset + htab->brlt->output_section->vma - elf_gp (htab->brlt->output_section->owner) - - htab->stub_group[stub_entry->id_sec->id].toc_off); + - htab->sec_info[stub_entry->group->link_sec->id].toc_off); if (info->emitrelocations) { - stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0); - stub_entry->stub_sec->flags |= SEC_RELOC; + stub_entry->group->stub_sec->reloc_count + += 1 + (PPC_HA (off) != 0); + stub_entry->group->stub_sec->flags |= SEC_RELOC; } if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) @@ -11042,12 +11294,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) } else if (info->emitrelocations) { - stub_entry->stub_sec->reloc_count += 1; - stub_entry->stub_sec->flags |= SEC_RELOC; + stub_entry->group->stub_sec->reloc_count += 1; + stub_entry->group->stub_sec->flags |= SEC_RELOC; } } - stub_entry->stub_sec->size += size; + stub_entry->group->stub_sec->size += size; return TRUE; } @@ -11058,57 +11310,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) int ppc64_elf_setup_section_lists (struct bfd_link_info *info) { - bfd *input_bfd; - int top_id, top_index, id; - asection *section; - asection **input_list; + unsigned int id; bfd_size_type amt; struct ppc_link_hash_table *htab = ppc_hash_table (info); if (htab == NULL) return -1; - /* Find the top input section id. */ - for (input_bfd = info->input_bfds, top_id = 3; - input_bfd != NULL; - input_bfd = input_bfd->link_next) - { - for (section = input_bfd->sections; - section != NULL; - section = section->next) - { - if (top_id < section->id) - top_id = section->id; - } - } - - htab->top_id = top_id; - amt = sizeof (struct map_stub) * (top_id + 1); - htab->stub_group = bfd_zmalloc (amt); - if (htab->stub_group == NULL) + htab->sec_info_arr_size = bfd_get_next_section_id (); + amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size); + htab->sec_info = bfd_zmalloc (amt); + if (htab->sec_info == NULL) return -1; /* Set toc_off for com, und, abs and ind sections. */ for (id = 0; id < 3; id++) - htab->stub_group[id].toc_off = TOC_BASE_OFF; - - /* We can't use output_bfd->section_count here to find the top output - section index as some sections may have been removed, and - strip_excluded_output_sections doesn't renumber the indices. */ - for (section = info->output_bfd->sections, top_index = 0; - section != NULL; - section = section->next) - { - if (top_index < section->index) - top_index = section->index; - } - - htab->top_index = top_index; - amt = sizeof (asection *) * (top_index + 1); - input_list = bfd_zmalloc (amt); - htab->input_list = input_list; - if (input_list == NULL) - return -1; + htab->sec_info[id].toc_off = TOC_BASE_OFF; return 1; } @@ -11159,6 +11376,7 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) addr = (htab->toc_first_sec->output_offset + htab->toc_first_sec->output_section->vma); htab->toc_curr = addr; + htab->toc_curr &= -TOC_BASE_ALIGN; } /* toc_curr is the base address of this toc group. Set elf_gp @@ -11252,7 +11470,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) elf_link_hash_traverse (&htab->elf, merge_global_got, info); /* And tlsld_got. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent, *ent2; @@ -11263,7 +11481,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) if (!ent->is_indirect && ent->got.offset != (bfd_vma) -1) { - for (ibfd2 = ibfd->link_next; ibfd2 != NULL; ibfd2 = ibfd2->link_next) + for (ibfd2 = ibfd->link.next; ibfd2 != NULL; ibfd2 = ibfd2->link.next) { if (!is_ppc64_elf (ibfd2)) continue; @@ -11285,7 +11503,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) htab->elf.irelplt->size -= htab->got_reli_size; htab->got_reli_size = 0; - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *got, *relgot; @@ -11305,7 +11523,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) /* Now reallocate the got, local syms first. We don't need to allocate section contents again since we never increase size. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry **lgot_ents; struct got_entry **end_lgot_ents; @@ -11351,7 +11569,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) htab->elf.irelplt->size += rel_size; htab->got_reli_size += rel_size; } - else if (info->shared) + else if (bfd_link_pic (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += rel_size; @@ -11362,7 +11580,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) elf_link_hash_traverse (&htab->elf, reallocate_got, info); - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { struct got_entry *ent; @@ -11376,7 +11594,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) asection *s = ppc64_elf_tdata (ibfd)->got; ent->got.offset = s->size; s->size += 16; - if (info->shared) + if (bfd_link_pic (info)) { asection *srel = ppc64_elf_tdata (ibfd)->relgot; srel->size += sizeof (Elf64_External_Rela); @@ -11386,7 +11604,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info) done_something = htab->elf.irelplt->rawsize != htab->elf.irelplt->size; if (!done_something) - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { asection *got; @@ -11539,7 +11757,7 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) { long adjust; - adjust = opd->adjust[sym->st_value / 8]; + adjust = opd->adjust[OPD_NDX (sym_value)]; if (adjust == -1) /* Assume deleted functions won't ever be called. */ continue; @@ -11656,15 +11874,13 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) return FALSE; if ((isec->output_section->flags & SEC_CODE) != 0 - && isec->output_section->index <= htab->top_index) + && isec->output_section->id < htab->sec_info_arr_size) { - asection **list = htab->input_list + isec->output_section->index; - /* Steal the link_sec pointer for our list. */ -#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) /* This happens to make the list in reverse order, which is what we want. */ - PREV_SEC (isec) = *list; - *list = isec; + htab->sec_info[isec->id].u.list + = htab->sec_info[isec->output_section->id].u.list; + htab->sec_info[isec->output_section->id].u.list = isec; } if (htab->multi_toc_needed) @@ -11688,7 +11904,7 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) htab->toc_curr = elf_gp (isec->owner); } - htab->stub_group[isec->id].toc_off = htab->toc_curr; + htab->sec_info[isec->id].toc_off = htab->toc_curr; return TRUE; } @@ -11710,8 +11926,8 @@ check_pasted_section (struct bfd_link_info *info, const char *name) if (i->has_toc_reloc) { if (toc_off == 0) - toc_off = htab->stub_group[i->id].toc_off; - else if (toc_off != htab->stub_group[i->id].toc_off) + toc_off = htab->sec_info[i->id].toc_off; + else if (toc_off != htab->sec_info[i->id].toc_off) return FALSE; } @@ -11719,14 +11935,14 @@ check_pasted_section (struct bfd_link_info *info, const char *name) for (i = o->map_head.s; i != NULL; i = i->map_head.s) if (i->makes_toc_func_call) { - toc_off = htab->stub_group[i->id].toc_off; + toc_off = htab->sec_info[i->id].toc_off; break; } /* Make sure the whole pasted function uses the same toc offset. */ if (toc_off != 0) for (i = o->map_head.s; i != NULL; i = i->map_head.s) - htab->stub_group[i->id].toc_off = toc_off; + htab->sec_info[i->id].toc_off = toc_off; } return TRUE; } @@ -11745,17 +11961,22 @@ ppc64_elf_check_init_fini (struct bfd_link_info *info) _init and _fini functions into multiple parts. Putting a stub in the middle of a function is not a good idea. */ -static void -group_sections (struct ppc_link_hash_table *htab, +static bfd_boolean +group_sections (struct bfd_link_info *info, bfd_size_type stub_group_size, bfd_boolean stubs_always_before_branch) { - asection **list; + struct ppc_link_hash_table *htab; + asection *osec; bfd_size_type stub14_group_size; bfd_boolean suppress_size_errors; + htab = ppc_hash_table (info); + if (htab == NULL) + return FALSE; + suppress_size_errors = FALSE; - stub14_group_size = stub_group_size; + stub14_group_size = stub_group_size >> 10; if (stub_group_size == 1) { /* Default values. */ @@ -11772,10 +11993,14 @@ group_sections (struct ppc_link_hash_table *htab, suppress_size_errors = TRUE; } - list = htab->input_list + htab->top_index; - do + for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next) { - asection *tail = *list; + asection *tail; + + if (osec->id >= htab->sec_info_arr_size) + continue; + + tail = htab->sec_info[osec->id].u.list; while (tail != NULL) { asection *curr; @@ -11783,6 +12008,7 @@ group_sections (struct ppc_link_hash_table *htab, bfd_size_type total; bfd_boolean big_sec; bfd_vma curr_toc; + struct map_stub *group; curr = tail; total = tail->size; @@ -11792,14 +12018,14 @@ group_sections (struct ppc_link_hash_table *htab, if (big_sec && !suppress_size_errors) (*_bfd_error_handler) (_("%B section %A exceeds stub group size"), tail->owner, tail); - curr_toc = htab->stub_group[tail->id].toc_off; + curr_toc = htab->sec_info[tail->id].toc_off; - while ((prev = PREV_SEC (curr)) != NULL + while ((prev = htab->sec_info[curr->id].u.list) != NULL && ((total += curr->output_offset - prev->output_offset) < (ppc64_elf_section_data (prev) != NULL && ppc64_elf_section_data (prev)->has_14bit_branch ? stub14_group_size : stub_group_size)) - && htab->stub_group[prev->id].toc_off == curr_toc) + && htab->sec_info[prev->id].toc_off == curr_toc) curr = prev; /* OK, the size from the start of CURR to the end is less @@ -11812,11 +12038,19 @@ group_sections (struct ppc_link_hash_table *htab, only break if stubs added make the total size more than 2^25, ie. for the default stub_group_size, if stubs total more than 2097152 bytes, or nearly 75000 plt call stubs. */ + group = bfd_alloc (curr->owner, sizeof (*group)); + if (group == NULL) + return FALSE; + group->link_sec = curr; + group->stub_sec = NULL; + group->needs_save_res = 0; + group->next = htab->group; + htab->group = group; do { - prev = PREV_SEC (tail); + prev = htab->sec_info[tail->id].u.list; /* Set up this stub group. */ - htab->stub_group[tail->id].link_sec = curr; + htab->sec_info[tail->id].u.group = group; } while (tail != curr && (tail = prev) != NULL); @@ -11833,19 +12067,17 @@ group_sections (struct ppc_link_hash_table *htab, < (ppc64_elf_section_data (prev) != NULL && ppc64_elf_section_data (prev)->has_14bit_branch ? stub14_group_size : stub_group_size)) - && htab->stub_group[prev->id].toc_off == curr_toc) + && htab->sec_info[prev->id].toc_off == curr_toc) { tail = prev; - prev = PREV_SEC (tail); - htab->stub_group[tail->id].link_sec = curr; + prev = htab->sec_info[tail->id].u.list; + htab->sec_info[tail->id].u.group = group; } } tail = prev; } } - while (list-- != htab->input_list); - free (htab->input_list); -#undef PREV_SEC + return TRUE; } static const unsigned char glink_eh_frame_cie[] = @@ -11859,7 +12091,8 @@ static const unsigned char glink_eh_frame_cie[] = 65, /* RA reg. */ 1, /* Augmentation size. */ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ + DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */ + 0, 0, 0, 0 }; /* Stripping output sections is normally done before dynamic section @@ -11899,7 +12132,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (htab == NULL) return FALSE; - if (htab->params->plt_thread_safe == -1 && !info->executable) + if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info)) htab->params->plt_thread_safe = 1; if (!htab->opd_abi) htab->params->plt_thread_safe = 0; @@ -11916,16 +12149,24 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) /* libanl */ "getaddrinfo_a", /* libgomp */ + "GOMP_parallel", "GOMP_parallel_start", + "GOMP_parallel_loop_static", "GOMP_parallel_loop_static_start", + "GOMP_parallel_loop_dynamic", "GOMP_parallel_loop_dynamic_start", + "GOMP_parallel_loop_guided", "GOMP_parallel_loop_guided_start", + "GOMP_parallel_loop_runtime", "GOMP_parallel_loop_runtime_start", + "GOMP_parallel_sections", "GOMP_parallel_sections_start", + /* libgo */ + "__go_go", }; unsigned i; - for (i = 0; i < sizeof (thread_starter)/ sizeof (thread_starter[0]); i++) + for (i = 0; i < ARRAY_SIZE (thread_starter); i++) { struct elf_link_hash_entry *h; h = elf_link_hash_lookup (&htab->elf, thread_starter[i], @@ -11941,19 +12182,21 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) else stub_group_size = htab->params->group_size; - group_sections (htab, stub_group_size, stubs_always_before_branch); + if (!group_sections (info, stub_group_size, stubs_always_before_branch)) + return FALSE; while (1) { bfd *input_bfd; unsigned int bfd_indx; + struct map_stub *group; asection *stub_sec; htab->stub_iteration += 1; for (input_bfd = info->input_bfds, bfd_indx = 0; input_bfd != NULL; - input_bfd = input_bfd->link_next, bfd_indx++) + input_bfd = input_bfd->link.next, bfd_indx++) { Elf_Internal_Shdr *symtab_hdr; asection *section; @@ -12048,7 +12291,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (hash == NULL) { sym_value = sym->st_value; - ok_dest = TRUE; + if (sym_sec != NULL + && sym_sec->output_section != NULL) + ok_dest = TRUE; } else if (hash->elf.root.type == bfd_link_hash_defined || hash->elf.root.type == bfd_link_hash_defweak) @@ -12106,7 +12351,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if (hash == NULL && opd->adjust != NULL) { - long adjust = opd->adjust[sym_value / 8]; + long adjust = opd->adjust[OPD_NDX (sym_value)]; if (adjust == -1) continue; code_value += adjust; @@ -12144,8 +12389,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) fact a call needing a TOC adjustment. */ if (code_sec != NULL && code_sec->output_section != NULL - && (htab->stub_group[code_sec->id].toc_off - != htab->stub_group[section->id].toc_off) + && (htab->sec_info[code_sec->id].toc_off + != htab->sec_info[section->id].toc_off) && (code_sec->has_toc_reloc || code_sec->makes_toc_func_call)) stub_type = ppc_stub_long_branch_r2off; @@ -12185,7 +12430,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_type = ppc_stub_plt_call_r2save; /* Support for grouping stub sections. */ - id_sec = htab->stub_group[section->id].link_sec; + id_sec = htab->sec_info[section->id].u.group->link_sec; /* Get the name of this stub. */ stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela); @@ -12274,6 +12519,10 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info); + for (group = htab->group; group != NULL; group = group->next) + if (group->needs_save_res) + group->stub_sec->size += htab->sfpr->size; + if (info->emitrelocations && htab->glink != NULL && htab->glink->size != 0) { @@ -12291,7 +12540,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - size += 20; + size += 24; if (htab->glink != NULL && htab->glink->size != 0) size += 24; if (size != 0) @@ -12311,7 +12560,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) stub_sec->size = ((stub_sec->size + (1 << htab->params->plt_stub_align) - 1) - & (-1 << htab->params->plt_stub_align)); + & -(1 << htab->params->plt_stub_align)); for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; @@ -12331,6 +12580,89 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) (*htab->params->layout_sections_again) (); } + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p, *last_fde; + size_t last_fde_len, size, align, pad; + asection *stub_sec; + + p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); + if (p == NULL) + return FALSE; + htab->glink_eh_frame->contents = p; + last_fde = p; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + last_fde_len = sizeof (glink_eh_frame_cie) - 4; + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); + p += sizeof (glink_eh_frame_cie); + + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + last_fde = p; + last_fde_len = 20; + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 20, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to stub section, written later. */ + p += 4; + /* stub section size. */ + bfd_put_32 (htab->elf.dynobj, stub_sec->size, p); + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + last_fde = p; + last_fde_len = 20; + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 20, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to .glink, written later. */ + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); + p += 4; + /* Augmentation. */ + p += 1; + + *p++ = DW_CFA_advance_loc + 1; + *p++ = DW_CFA_register; + *p++ = 65; + *p++ = htab->opd_abi ? 12 : 0; + *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + } + /* Subsume any padding into the last FDE if user .eh_frame + sections are aligned more than glink_eh_frame. Otherwise any + zero padding will be seen as a terminator. */ + size = p - htab->glink_eh_frame->contents; + align = 1; + align <<= htab->glink_eh_frame->output_section->alignment_power; + align -= 1; + pad = ((size + align) & ~align) - size; + htab->glink_eh_frame->size = size + pad; + bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); + } + maybe_strip_output (info, htab->brlt); if (htab->glink_eh_frame != NULL) maybe_strip_output (info, htab->glink_eh_frame); @@ -12345,7 +12677,35 @@ bfd_vma ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd) { asection *s; - bfd_vma TOCstart; + bfd_vma TOCstart, adjust; + + if (info != NULL) + { + struct elf_link_hash_entry *h; + struct elf_link_hash_table *htab = elf_hash_table (info); + + if (is_elf_hash_table (htab) + && htab->hgot != NULL) + h = htab->hgot; + else + { + h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE); + if (is_elf_hash_table (htab)) + htab->hgot = h; + } + if (h != NULL + && h->root.type == bfd_link_hash_defined + && !h->root.linker_def + && (!is_elf_hash_table (htab) + || h->def_regular)) + { + TOCstart = (h->root.u.def.value - TOC_BASE_OFF + + h->root.u.def.section->output_offset + + h->root.u.def.section->output_section->vma); + _bfd_set_gp_value (obfd, TOCstart); + return TOCstart; + } + } /* The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The TOC starts where the first of these sections starts. */ @@ -12393,17 +12753,29 @@ ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd) if (s != NULL) TOCstart = s->output_section->vma + s->output_offset; + /* Force alignment. */ + adjust = TOCstart & (TOC_BASE_ALIGN - 1); + TOCstart -= adjust; _bfd_set_gp_value (obfd, TOCstart); - if (info != NULL && s != NULL && is_ppc64_elf (obfd)) + if (info != NULL && s != NULL) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - if (htab != NULL - && htab->elf.hgot != NULL) + if (htab != NULL) + { + if (htab->elf.hgot != NULL) + { + htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust; + htab->elf.hgot->root.u.def.section = s; + } + } + else { - htab->elf.hgot->root.u.def.value = TOC_BASE_OFF; - htab->elf.hgot->root.u.def.section = s; + struct bfd_link_hash_entry *bh = NULL; + _bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL, + s, TOC_BASE_OFF - adjust, + NULL, FALSE, FALSE, &bh); } } return TOCstart; @@ -12460,6 +12832,33 @@ build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) htab->stub_error = TRUE; } + htab->stub_count[ppc_stub_global_entry - 1] += 1; + if (htab->params->emit_stub_syms) + { + size_t len = strlen (h->root.root.string); + char *name = bfd_malloc (sizeof "12345678.global_entry." + len); + + if (name == NULL) + return FALSE; + + sprintf (name, "%08x.global_entry.%s", s->id, h->root.root.string); + h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); + if (h == NULL) + return FALSE; + if (h->root.type == bfd_link_hash_new) + { + h->root.type = bfd_link_hash_defined; + h->root.u.def.section = s; + h->root.u.def.value = p - s->contents; + h->ref_regular = 1; + h->def_regular = 1; + h->ref_regular_nonweak = 1; + h->forced_local = 1; + h->non_elf = 0; + h->root.linker_def = 1; + } + } + if (PPC_HA (off) != 0) { bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p); @@ -12484,6 +12883,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, char **stats) { struct ppc_link_hash_table *htab = ppc_hash_table (info); + struct map_stub *group; asection *stub_sec; bfd_byte *p; int stub_sec_count = 0; @@ -12530,6 +12930,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, h->ref_regular_nonweak = 1; h->forced_local = 1; h->non_elf = 0; + h->root.linker_def = 1; } } plt0 = (htab->elf.splt->output_section->vma @@ -12638,7 +13039,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); } - if (htab->brlt->size != 0) + if (htab->brlt != NULL && htab->brlt->size != 0) { htab->brlt->contents = bfd_zalloc (htab->brlt->owner, htab->brlt->size); @@ -12653,119 +13054,25 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, return FALSE; } - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_vma val; - bfd_byte *last_fde; - size_t last_fde_len, size, align, pad; - - p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); - if (p == NULL) - return FALSE; - htab->glink_eh_frame->contents = p; - last_fde = p; - - htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; - - memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); - /* CIE length (rewrite in case little-endian). */ - last_fde_len = sizeof (glink_eh_frame_cie) - 4; - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += sizeof (glink_eh_frame_cie); + /* Build the stubs as directed by the stub hash table. */ + bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); - for (stub_sec = htab->params->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + for (group = htab->group; group != NULL; group = group->next) + if (group->needs_save_res) + { + stub_sec = group->stub_sec; + memcpy (stub_sec->contents + stub_sec->size, htab->sfpr->contents, + htab->sfpr->size); + if (htab->params->emit_stub_syms) { - last_fde = p; - last_fde_len = 16; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 16, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to stub section. */ - val = (stub_sec->output_section->vma - + stub_sec->output_offset); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset); - val -= p - htab->glink_eh_frame->contents; - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - stub_sec->name); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (save_res_funcs); i++) + if (!sfpr_define (info, &save_res_funcs[i], stub_sec)) return FALSE; - } - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* stub section size. */ - bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p); - p += 4; - /* Augmentation. */ - p += 1; - /* Pad. */ - p += 3; } - if (htab->glink != NULL && htab->glink->size != 0) - { - last_fde = p; - last_fde_len = 20; - /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); - p += 4; - /* CIE pointer. */ - val = p - htab->glink_eh_frame->contents; - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* Offset to .glink. */ - val = (htab->glink->output_section->vma - + htab->glink->output_offset - + 8); - val -= (htab->glink_eh_frame->output_section->vma - + htab->glink_eh_frame->output_offset); - val -= p - htab->glink_eh_frame->contents; - if (val + 0x80000000 > 0xffffffff) - { - info->callbacks->einfo - (_("%P: %s offset too large for .eh_frame sdata4 encoding"), - htab->glink->name); - return FALSE; - } - bfd_put_32 (htab->elf.dynobj, val, p); - p += 4; - /* .glink size. */ - bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); - p += 4; - /* Augmentation. */ - p += 1; - - *p++ = DW_CFA_advance_loc + 1; - *p++ = DW_CFA_register; - *p++ = 65; - *p++ = 12; - *p++ = DW_CFA_advance_loc + 4; - *p++ = DW_CFA_restore_extended; - *p++ = 65; - } - /* Subsume any padding into the last FDE if user .eh_frame - sections are aligned more than glink_eh_frame. Otherwise any - zero padding will be seen as a terminator. */ - size = p - htab->glink_eh_frame->contents; - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - pad = ((size + align) & ~align) - size; - htab->glink_eh_frame->size = size + pad; - bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); - } - - /* Build the stubs as directed by the stub hash table. */ - bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); + stub_sec->size += htab->sfpr->size; + } if (htab->relbrlt != NULL) htab->relbrlt->reloc_count = 0; @@ -12777,7 +13084,7 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) stub_sec->size = ((stub_sec->size + (1 << htab->params->plt_stub_align) - 1) - & (-1 << htab->params->plt_stub_align)); + & -(1 << htab->params->plt_stub_align)); for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; @@ -12789,6 +13096,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, break; } + /* Note that the glink_eh_frame check here is not only testing that + the generated size matched the calculated size but also that + bfd_elf_discard_info didn't make any changes to the section. */ if (stub_sec != NULL || (htab->glink_eh_frame != NULL && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size)) @@ -12812,7 +13122,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, " long branch %lu\n" " long toc adj %lu\n" " plt call %lu\n" - " plt call toc %lu"), + " plt call toc %lu\n" + " global entry %lu"), stub_sec_count, stub_sec_count == 1 ? "" : "s", htab->stub_count[ppc_stub_long_branch - 1], @@ -12820,7 +13131,8 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, htab->stub_count[ppc_stub_plt_branch - 1], htab->stub_count[ppc_stub_plt_branch_r2off - 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_r2save - 1], + htab->stub_count[ppc_stub_global_entry - 1]); } return TRUE; } @@ -12913,6 +13225,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; Elf_Internal_Rela *rel; + Elf_Internal_Rela *wrel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; bfd_byte *loc; @@ -12944,9 +13257,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, sym_hashes = elf_sym_hashes (input_bfd); is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; - rel = relocs; + rel = wrel = relocs; relend = relocs + input_section->reloc_count; - for (; rel < relend; rel++) + for (; rel < relend; wrel++, rel++) { enum elf_ppc64_reloc_type r_type; bfd_vma addend; @@ -12970,10 +13283,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, struct ppc_stub_hash_entry *stub_entry; bfd_vma max_br_offset; bfd_vma from; - const Elf_Internal_Rela orig_rel = *rel; + Elf_Internal_Rela orig_rel; reloc_howto_type *howto; struct reloc_howto_struct alt_howto; + again: + orig_rel = *rel; + r_type = ELF64_R_TYPE (rel->r_info); r_symndx = ELF64_R_SYM (rel->r_info); @@ -12981,10 +13297,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, symbol of the previous ADDR64 reloc. The symbol gives us the proper TOC base to use. */ if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC) - && rel != relocs - && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64 + && wrel != relocs + && ELF64_R_TYPE (wrel[-1].r_info) == R_PPC64_ADDR64 && is_opd) - r_symndx = ELF64_R_SYM (rel[-1].r_info); + r_symndx = ELF64_R_SYM (wrel[-1].r_info); sym = NULL; sec = NULL; @@ -13006,7 +13322,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, opd = get_opd_info (sec); if (opd != NULL && opd->adjust != NULL) { - long adjust = opd->adjust[(sym->st_value + rel->r_addend) / 8]; + long adjust = opd->adjust[OPD_NDX (sym->st_value + + rel->r_addend)]; if (adjust == -1) relocation = 0; else @@ -13064,18 +13381,31 @@ ppc64_elf_relocate_section (bfd *output_bfd, h = (struct ppc_link_hash_entry *) h_elf; if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, 1, relend, - ppc64_elf_howto_table[r_type], 0, - contents); + { + _bfd_clear_contents (ppc64_elf_howto_table[r_type], + input_bfd, input_section, + contents + rel->r_offset); + wrel->r_offset = rel->r_offset; + wrel->r_info = 0; + wrel->r_addend = 0; + + /* For ld -r, remove relocations in debug sections against + sections defined in discarded sections. Not done for + non-debug to preserve relocs in .eh_frame which the + eh_frame editing code expects to be present. */ + if (bfd_link_relocatable (info) + && (input_section->flags & SEC_DEBUGGING)) + wrel--; - if (info->relocatable) - continue; + continue; + } + + if (bfd_link_relocatable (info)) + goto copy_reloc; if (h != NULL && &h->elf == htab->elf.hgot) { - relocation = (TOCstart - + htab->stub_group[input_section->id].toc_off); + relocation = TOCstart + htab->sec_info[input_section->id].toc_off; sec = bfd_abs_section_ptr; unresolved_reloc = FALSE; } @@ -13231,10 +13561,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { toctprel: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); + insn = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset - d_offset); r_type = R_PPC64_TPREL16_HA; if (toc_symndx != 0) { @@ -13242,8 +13574,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13269,8 +13600,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_addend = toc_addend; /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } else rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -13329,12 +13659,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, htab->tls_get_addr, htab->tls_get_addr_fd)) offset = rel[1].r_offset; + /* We read the low GOT_TLS (or TOC16) insn because we + need to keep the destination reg. It may be + something other than the usual r3, and moved to r3 + before the call by intervening code. */ + insn1 = bfd_get_32 (output_bfd, + contents + rel->r_offset - d_offset); if ((tls_mask & tls_gd) != 0) { /* IE */ - insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - d_offset); - insn1 &= (1 << 26) - (1 << 2); + insn1 &= (0x1f << 21) | (0x1f << 16); insn1 |= 58 << 26; /* ld */ insn2 = 0x7c636a14; /* add 3,3,13 */ if (offset != (bfd_vma) -1) @@ -13349,7 +13683,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, else { /* LE */ - insn1 = 0x3c6d0000; /* addis 3,13,0 */ + insn1 &= 0x1f << 21; + insn1 |= 0x3c0d0000; /* addis r,13,0 */ insn2 = 0x38630000; /* addi 3,3,0 */ if (tls_gd == 0) { @@ -13404,8 +13739,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* We changed the symbol. Start over in order to get h, sym, sec etc. right. */ - rel--; - continue; + goto again; } } break; @@ -13449,10 +13783,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, } bfd_put_32 (output_bfd, insn2, contents + offset); if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0) - { - rel--; - continue; - } + goto again; } break; @@ -13494,8 +13825,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn2 = NOP; } bfd_put_32 (output_bfd, insn2, contents + offset); - rel--; - continue; + goto again; } break; @@ -13536,6 +13866,52 @@ ppc64_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC64_ENTRY: + relocation = TOCstart + htab->sec_info[input_section->id].toc_off; + if (!bfd_link_pic (info) + && !info->traditional_format + && relocation + 0x80008000 <= 0xffffffff) + { + unsigned int insn1, insn2; + + insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((insn1 & ~0xfffc) == LD_R2_0R12 + && insn2 == ADD_R2_R2_R12) + { + bfd_put_32 (output_bfd, + LIS_R2 + PPC_HA (relocation), + contents + rel->r_offset); + bfd_put_32 (output_bfd, + ADDI_R2_R2 + PPC_LO (relocation), + contents + rel->r_offset + 4); + } + } + else + { + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + if (relocation + 0x80008000 <= 0xffffffff) + { + unsigned int insn1, insn2; + + insn1 = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + if ((insn1 & ~0xfffc) == LD_R2_0R12 + && insn2 == ADD_R2_R2_R12) + { + bfd_put_32 (output_bfd, + ADDIS_R2_R12 + PPC_HA (relocation), + contents + rel->r_offset); + bfd_put_32 (output_bfd, + ADDI_R2_R2 + PPC_LO (relocation), + contents + rel->r_offset + 4); + } + } + } + break; + case R_PPC64_REL16_HA: /* If we are generating a non-PIC executable, edit . 0: addis 2,12,.TOC.-0b@ha @@ -13544,7 +13920,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, . lis 2,.TOC.@ha . addi 2,2,.TOC.@l if .TOC. is in range. */ - if (!info->shared + if (!bfd_link_pic (info) + && !info->traditional_format + && !htab->opd_abi + && rel->r_addend == d_offset && h != NULL && &h->elf == htab->elf.hgot && rel + 1 < relend && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO) @@ -13556,15 +13935,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_vma offset = rel->r_offset - d_offset; insn1 = bfd_get_32 (output_bfd, contents + offset); insn2 = bfd_get_32 (output_bfd, contents + offset + 4); - if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */ - && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */) + if ((insn1 & 0xffff0000) == ADDIS_R2_R12 + && (insn2 & 0xffff0000) == ADDI_R2_R2) { r_type = R_PPC64_ADDR16_HA; rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel->r_addend -= d_offset; rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); rel[1].r_addend -= d_offset + 4; - bfd_put_32 (output_bfd, 0x3c400000, contents + offset); + bfd_put_32 (output_bfd, LIS_R2, contents + offset); } } break; @@ -13656,7 +14035,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (h != NULL && (h == htab->tls_get_addr_fd || h == htab->tls_get_addr) - && !htab->params->no_tls_get_addr_opt) + && htab->params->tls_get_addr_opt) { /* Special stub used, leave nop alone. */ } @@ -13712,10 +14091,17 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (!can_plt_call) { - info->callbacks->einfo - (_("%P: %H: call to `%T' lacks nop, can't restore toc; " - "recompile with -fPIC\n"), - input_bfd, input_section, rel->r_offset, sym_name); + if (stub_entry->stub_type == ppc_stub_plt_call + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + info->callbacks->einfo + (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + "recompile with -fPIC\n"), + input_bfd, input_section, rel->r_offset, sym_name); + else + info->callbacks->einfo + (_("%P: %H: call to `%T' lacks nop, can't restore toc; " + "(-mcmodel=small toc adjust stub)\n"), + input_bfd, input_section, rel->r_offset, sym_name); bfd_set_error (bfd_error_bad_value); ret = FALSE; @@ -13769,9 +14155,18 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* Munge up the value and addend so that we call the stub rather than the procedure directly. */ - relocation = (stub_entry->stub_offset - + stub_entry->stub_sec->output_offset - + stub_entry->stub_sec->output_section->vma); + asection *stub_sec = stub_entry->group->stub_sec; + + if (stub_entry->stub_type == ppc_stub_save_res) + relocation += (stub_sec->output_offset + + stub_sec->output_section->vma + + stub_sec->size - htab->sfpr->size + - htab->sfpr->output_offset + - htab->sfpr->output_section->vma); + else + relocation = (stub_entry->stub_offset + + stub_sec->output_offset + + stub_sec->output_section->vma); addend = 0; reloc_dest = DEST_STUB; @@ -13820,7 +14215,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, && addend == 0) { bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); - continue; + goto copy_reloc; } break; } @@ -13836,7 +14231,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; case R_PPC64_NONE: case R_PPC64_TLS: @@ -13845,7 +14240,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOCSAVE: case R_PPC64_GNU_VTINHERIT: case R_PPC64_GNU_VTENTRY: - continue; + case R_PPC64_ENTRY: + goto copy_reloc; /* GOT16 relocations. Like an ADDR16 using the symbol's address in the GOT as relocation value instead of the @@ -13905,9 +14301,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (h != NULL) { bfd_boolean dyn = htab->elf.dynamic_sections_created; - if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), &h->elf) - || (info->shared + || (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -13966,7 +14362,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC); if (ifunc) relgot = htab->elf.irelplt; - else if ((info->shared || indx != 0) + else if ((bfd_link_pic (info) || indx != 0) && (h == NULL || (tls_type == (TLS_TLS | TLS_LD) && !h->elf.def_dynamic) @@ -14020,7 +14416,12 @@ ppc64_elf_relocate_section (bfd *output_bfd, { outrel.r_addend += relocation; if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - outrel.r_addend -= htab->elf.tls_sec->vma; + { + if (htab->elf.tls_sec == NULL) + outrel.r_addend = 0; + else + outrel.r_addend -= htab->elf.tls_sec->vma; + } } loc = relgot->contents; loc += (relgot->reloc_count++ @@ -14037,9 +14438,14 @@ ppc64_elf_relocate_section (bfd *output_bfd, relocation = 1; else if (tls_type != 0) { - relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; - if (tls_type == (TLS_TLS | TLS_TPREL)) - relocation += DTP_OFFSET - TP_OFFSET; + if (htab->elf.tls_sec == NULL) + relocation = 0; + else + { + relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (tls_type == (TLS_TLS | TLS_TPREL)) + relocation += DTP_OFFSET - TP_OFFSET; + } if (tls_type == (TLS_TLS | TLS_GD)) { @@ -14058,7 +14464,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, abort (); relocation = got->output_section->vma + got->output_offset + off; - addend = -(TOCstart + htab->stub_group[input_section->id].toc_off); + addend = -(TOCstart + htab->sec_info[input_section->id].toc_off); } break; @@ -14069,41 +14475,54 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_PLT64: /* Relocation is to the entry for this symbol in the procedure linkage table. */ + { + struct plt_entry **plt_list = NULL; + if (h != NULL) + plt_list = &h->elf.plt.plist; + else if (local_got_ents != NULL) + { + struct plt_entry **local_plt = (struct plt_entry **) + (local_got_ents + symtab_hdr->sh_info); + unsigned char *local_got_tls_masks = (unsigned char *) + (local_plt + symtab_hdr->sh_info); + if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0) + plt_list = local_plt + r_symndx; + } + if (plt_list) + { + struct plt_entry *ent; - /* Resolve a PLT reloc against a local symbol directly, - without using the procedure linkage table. */ - if (h == NULL) - break; - - /* It's possible that we didn't make a PLT entry for this - symbol. This happens when statically linking PIC code, - or when using -Bsymbolic. Go find a match if there is a - PLT entry. */ - if (htab->elf.splt != NULL) - { - struct plt_entry *ent; - for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next) - if (ent->plt.offset != (bfd_vma) -1 - && ent->addend == orig_rel.r_addend) - { - relocation = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + ent->plt.offset); - unresolved_reloc = FALSE; - break; - } - } + for (ent = *plt_list; ent != NULL; ent = ent->next) + if (ent->plt.offset != (bfd_vma) -1 + && ent->addend == orig_rel.r_addend) + { + asection *plt; + + plt = htab->elf.splt; + if (!htab->elf.dynamic_sections_created + || h == NULL + || h->elf.dynindx == -1) + plt = htab->elf.iplt; + relocation = (plt->output_section->vma + + plt->output_offset + + ent->plt.offset); + addend = 0; + unresolved_reloc = FALSE; + break; + } + } + } break; case R_PPC64_TOC: /* Relocation value is TOC base. */ relocation = TOCstart; if (r_symndx == STN_UNDEF) - relocation += htab->stub_group[input_section->id].toc_off; + relocation += htab->sec_info[input_section->id].toc_off; else if (unresolved_reloc) ; - else if (sec != NULL && sec->id <= htab->top_id) - relocation += htab->stub_group[sec->id].toc_off; + else if (sec != NULL && sec->id < htab->sec_info_arr_size) + relocation += htab->sec_info[sec->id].toc_off; else unresolved_reloc = TRUE; goto dodyn; @@ -14118,7 +14537,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TOC16_DS: case R_PPC64_TOC16_LO_DS: case R_PPC64_TOC16_HA: - addend -= TOCstart + htab->stub_group[input_section->id].toc_off; + addend -= TOCstart + htab->sec_info[input_section->id].toc_off; break; /* Relocate against the beginning of the section. */ @@ -14136,6 +14555,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_REL16_LO: case R_PPC64_REL16_HI: case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: break; case R_PPC64_REL14: @@ -14172,8 +14592,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, insn, p); break; } - addend -= htab->elf.tls_sec->vma + TP_OFFSET; - if (info->shared) + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (bfd_link_pic (info)) /* The TPREL16 relocs shouldn't really be used in shared libs as they will result in DT_TEXTREL being set, but support them anyway. */ @@ -14192,7 +14613,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_HIGHERA: case R_PPC64_DTPREL16_HIGHEST: case R_PPC64_DTPREL16_HIGHESTA: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; case R_PPC64_ADDR64_LOCAL: @@ -14207,11 +14629,13 @@ ppc64_elf_relocate_section (bfd *output_bfd, goto dodyn; case R_PPC64_TPREL64: - addend -= htab->elf.tls_sec->vma + TP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + TP_OFFSET; goto dodyn; case R_PPC64_DTPREL64: - addend -= htab->elf.tls_sec->vma + DTP_OFFSET; + if (htab->elf.tls_sec != NULL) + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; /* Fall thru */ /* Relocations that may need to be propagated if this is a @@ -14247,19 +14671,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (NO_OPD_RELOCS && is_opd) break; - if ((info->shared + if ((bfd_link_pic (info) && (h == NULL || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT || h->elf.root.type != bfd_link_hash_undefweak) && (must_be_dyn_reloc (info, r_type) || !SYMBOL_CALLS_LOCAL (info, &h->elf))) || (ELIMINATE_COPY_RELOCS - && !info->shared + && !bfd_link_pic (info) && h != NULL && h->elf.dynindx != -1 && !h->elf.non_got_ref && !h->elf.def_regular) - || (!info->shared + || (!bfd_link_pic (info) && (h != NULL ? h->elf.type == STT_GNU_IFUNC : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))) @@ -14467,7 +14891,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_set_error (bfd_error_invalid_operation); ret = FALSE; - continue; + goto copy_reloc; } /* Multi-instruction sequences that access the TOC can be @@ -14544,6 +14968,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, break; case R_PPC64_REL16_HA: + case R_PPC64_REL16DX_HA: case R_PPC64_ADDR16_HA: case R_PPC64_ADDR16_HIGHA: case R_PPC64_ADDR16_HIGHERA: @@ -14599,16 +15024,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_LO_DS: insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); mask = 3; - /* If this reloc is against an lq insn, then the value must be - a multiple of 16. This is somewhat of a hack, but the - "correct" way to do this by defining _DQ forms of all the - _DS relocs bloats all reloc switches in this file. It - doesn't seem to make much sense to use any of these relocs - in data, so testing the insn should be safe. */ - if ((insn & (0x3f << 26)) == (56u << 26)) + /* If this reloc is against an lq, lxv, or stxv insn, then + the value must be a multiple of 16. This is somewhat of + a hack, but the "correct" way to do this by defining _DQ + forms of all the _DS relocs bloats all reloc switches in + this file. It doesn't make much sense to use these + relocs in data, so testing the insn should be safe. */ + if ((insn & (0x3f << 26)) == (56u << 26) + || ((insn & (0x3f << 26)) == (61u << 26) && (insn & 3) == 1)) mask = 15; - if (((relocation + addend) & mask) != 0) + relocation += addend; + addend = insn & (mask ^ 3); + if ((relocation & mask) != 0) { + relocation ^= relocation & mask; info->callbacks->einfo (_("%P: %H: error: %s not a multiple of %u\n"), input_bfd, input_section, rel->r_offset, @@ -14616,7 +15045,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, mask + 1); bfd_set_error (bfd_error_bad_value); ret = FALSE; - continue; + goto copy_reloc; } break; } @@ -14648,14 +15077,15 @@ ppc64_elf_relocate_section (bfd *output_bfd, enum complain_overflow complain = complain_overflow_signed; insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); - if (howto->rightshift == 0 - ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ - || (insn & (0x3f << 26)) == 24u << 26 /* ori */ - || (insn & (0x3f << 26)) == 26u << 26 /* xori */ - || (insn & (0x3f << 26)) == 10u << 26 /* cmpli */) - : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ - || (insn & (0x3f << 26)) == 25u << 26 /* oris */ - || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) + if ((insn & (0x3f << 26)) == 10u << 26 /* cmpli */) + complain = complain_overflow_bitfield; + else if (howto->rightshift == 0 + ? ((insn & (0x3f << 26)) == 28u << 26 /* andi */ + || (insn & (0x3f << 26)) == 24u << 26 /* ori */ + || (insn & (0x3f << 26)) == 26u << 26 /* xori */) + : ((insn & (0x3f << 26)) == 29u << 26 /* andis */ + || (insn & (0x3f << 26)) == 25u << 26 /* oris */ + || (insn & (0x3f << 26)) == 27u << 26 /* xoris */)) complain = complain_overflow_unsigned; if (howto->complain_on_overflow != complain) { @@ -14665,8 +15095,30 @@ ppc64_elf_relocate_section (bfd *output_bfd, } } - r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, - rel->r_offset, relocation, addend); + if (r_type == R_PPC64_REL16DX_HA) + { + /* Split field reloc isn't handled by _bfd_final_link_relocate. */ + if (rel->r_offset + 4 > input_section->size) + r = bfd_reloc_outofrange; + else + { + relocation += addend; + relocation -= (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); + relocation = (bfd_signed_vma) relocation >> 16; + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + insn &= ~0x1fffc1; + insn |= (relocation & 0xffc1) | ((relocation & 0x3e) << 15); + bfd_put_32 (input_bfd, insn, contents + rel->r_offset); + r = bfd_reloc_ok; + if (relocation + 0x8000 > 0xffff) + r = bfd_reloc_overflow; + } + } + else + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, + rel->r_offset, relocation, addend); if (r != bfd_reloc_ok) { @@ -14687,26 +15139,19 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (r == bfd_reloc_overflow) { - if (warned) - continue; - if (h != NULL - && h->elf.root.type == bfd_link_hash_undefweak - && howto->pc_relative) - { - /* Assume this is a call protected by other code that - detects the symbol is undefined. If this is the case, - we can safely ignore the overflow. If not, the - program is hosed anyway, and a little warning isn't - going to help. */ - - continue; - } - - if (!((*info->callbacks->reloc_overflow) - (info, &h->elf.root, sym_name, - reloc_name, orig_rel.r_addend, - input_bfd, input_section, rel->r_offset))) - return FALSE; + /* On code like "if (foo) foo();" don't report overflow + on a branch to zero when foo is undefined. */ + if (!warned + && (reloc_dest == DEST_STUB + || !(h != NULL + && (h->elf.root.type == bfd_link_hash_undefweak + || h->elf.root.type == bfd_link_hash_undefined) + && is_branch_reloc (r_type)))) + info->callbacks->reloc_overflow (info, &h->elf.root, + sym_name, reloc_name, + orig_rel.r_addend, + input_bfd, input_section, + rel->r_offset); } else { @@ -14719,6 +15164,29 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (more_info != NULL) free (more_info); } + copy_reloc: + if (wrel != rel) + *wrel = *rel; + } + + if (wrel != rel) + { + Elf_Internal_Shdr *rel_hdr; + size_t deleted = rel - wrel; + + rel_hdr = _bfd_elf_single_rel_hdr (input_section->output_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + if (rel_hdr->sh_size == 0) + { + /* It is too late to remove an empty reloc section. Leave + one NONE reloc. + ??? What is wrong with an empty section??? */ + rel_hdr->sh_size = rel_hdr->sh_entsize; + deleted -= 1; + } + rel_hdr = _bfd_elf_single_rel_hdr (input_section); + rel_hdr->sh_size -= rel_hdr->sh_entsize * deleted; + input_section->reloc_count -= deleted; } /* If we're emitting relocations, then shortly after this function @@ -14726,7 +15194,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, adjusted. Worse, reloc symbol indices will be for the output file rather than the input. Save a copy of the relocs for opd_entry_value. */ - if (is_opd && (info->emitrelocations || info->relocatable)) + if (is_opd && (info->emitrelocations || bfd_link_relocatable (info))) { bfd_size_type amt; amt = input_section->reloc_count * sizeof (Elf_Internal_Rela); @@ -14761,10 +15229,10 @@ ppc64_elf_output_symbol_hook (struct bfd_link_info *info, return 1; value = elfsym->st_value - input_sec->output_offset; - if (!info->relocatable) + if (!bfd_link_relocatable (info)) value -= input_sec->output_section->vma; - adjust = opd->adjust[value / 8]; + adjust = opd->adjust[OPD_NDX (value)]; if (adjust == -1) return 2; @@ -15052,18 +15520,86 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, NULL)) return FALSE; - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME - && !_bfd_elf_write_section_eh_frame (output_bfd, info, - htab->glink_eh_frame, - htab->glink_eh_frame->contents)) - return FALSE; + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p; + asection *stub_sec; + + p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie); + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + p += 4; + /* Offset to stub section. */ + val = (stub_sec->output_section->vma + + stub_sec->output_offset); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + stub_sec->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* stub section size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + p += 4; + /* Offset to .glink. */ + val = (htab->glink->output_section->vma + + htab->glink->output_offset + + 8); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + htab->glink->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* .glink size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Ops. */ + p += 7; + } + + if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME + && !_bfd_elf_write_section_eh_frame (output_bfd, info, + htab->glink_eh_frame, + htab->glink_eh_frame->contents)) + return FALSE; + } /* We need to handle writing out multiple GOT sections ourselves, since we didn't add them to DYNOBJ. We know dynobj is the first bfd. */ - while ((dynobj = dynobj->link_next) != NULL) + while ((dynobj = dynobj->link.next) != NULL) { asection *s;