Index: bfd/elf64-ppc.c |
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c |
index 4560599ec844c934dbfe9fad16e427beae4aac5f..50dad3b10e64ffe9d1abae32a252fbbbd7fd1a3f 100644 |
--- a/bfd/elf64-ppc.c |
+++ b/bfd/elf64-ppc.c |
@@ -1,6 +1,6 @@ |
/* PowerPC64-specific support for 64-bit ELF. |
Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, |
- 2009, 2010, 2011 Free Software Foundation, Inc. |
+ 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
Written by Linus Nordberg, Swox AB <info@swox.com>, |
based on elf32-ppc.c by Ian Lance Taylor. |
Largely rewritten by Alan Modra. |
@@ -55,7 +55,7 @@ static bfd_reloc_status_type ppc64_elf_toc64_reloc |
static bfd_reloc_status_type ppc64_elf_unhandled_reloc |
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
static bfd_vma opd_entry_value |
- (asection *, bfd_vma, asection **, bfd_vma *); |
+ (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean); |
#define TARGET_LITTLE_SYM bfd_elf64_powerpcle_vec |
#define TARGET_LITTLE_NAME "elf64-powerpcle" |
@@ -105,6 +105,7 @@ static bfd_vma opd_entry_value |
#define elf_backend_gc_sweep_hook ppc64_elf_gc_sweep_hook |
#define elf_backend_adjust_dynamic_symbol ppc64_elf_adjust_dynamic_symbol |
#define elf_backend_hide_symbol ppc64_elf_hide_symbol |
+#define elf_backend_maybe_function_sym ppc64_elf_maybe_function_sym |
#define elf_backend_always_size_sections ppc64_elf_func_desc_adjust |
#define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections |
#define elf_backend_init_index_section _bfd_elf_init_2_index_sections |
@@ -152,6 +153,13 @@ static bfd_vma opd_entry_value |
#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ |
#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ |
+#define XOR_R11_R11_R11 0x7d6b5a78 /* xor %r11,%r11,%r11 */ |
+#define ADD_R12_R12_R11 0x7d8c5a14 /* add %r12,%r12,%r11 */ |
+#define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */ |
+#define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */ |
+#define BNECTR 0x4ca20420 /* bnectr+ */ |
+#define BNECTR_P4 0x4ce20420 /* bnectr+ */ |
+ |
#define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */ |
#define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ |
@@ -2339,7 +2347,7 @@ ppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
{ |
bfd_vma dest = opd_entry_value (symbol->section, |
symbol->value + reloc_entry->addend, |
- NULL, NULL); |
+ NULL, NULL, FALSE); |
if (dest != (bfd_vma) -1) |
reloc_entry->addend = dest - (symbol->value |
+ symbol->section->output_section->vma |
@@ -2356,8 +2364,8 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
long insn; |
enum elf_ppc64_reloc_type r_type; |
bfd_size_type octets; |
- /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ |
- bfd_boolean is_power4 = FALSE; |
+ /* Assume 'at' branch hints. */ |
+ bfd_boolean is_isa_v2 = TRUE; |
/* If this is a relocatable link (output_bfd test tells us), just |
call the generic function. Any adjustment will be done at final |
@@ -2374,7 +2382,7 @@ ppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
|| r_type == R_PPC64_REL14_BRTAKEN) |
insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ |
- if (is_power4) |
+ if (is_isa_v2) |
{ |
/* Set 'a' bit. This is 0b00010 in BO field for branch |
on CR(BI) insns (BO == 001at or 011at), and 0b01000 |
@@ -2714,7 +2722,7 @@ ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, |
va_list ap; |
va_start (ap, note_type); |
- memset (data, 0, 40); |
+ memset (data, 0, sizeof (data)); |
strncpy (data + 40, va_arg (ap, const char *), 16); |
strncpy (data + 56, va_arg (ap, const char *), 80); |
va_end (ap); |
@@ -3584,7 +3592,8 @@ enum ppc_stub_type { |
ppc_stub_long_branch_r2off, |
ppc_stub_plt_branch, |
ppc_stub_plt_branch_r2off, |
- ppc_stub_plt_call |
+ ppc_stub_plt_call, |
+ ppc_stub_plt_call_r2save |
}; |
struct ppc_stub_hash_entry { |
@@ -3752,14 +3761,20 @@ struct ppc_link_hash_table |
bfd_size_type got_reli_size; |
/* Statistics. */ |
- unsigned long stub_count[ppc_stub_plt_call]; |
+ unsigned long stub_count[ppc_stub_plt_call_r2save]; |
/* Number of stubs against global syms. */ |
unsigned long stub_globals; |
+ /* Alignment of PLT call stubs. */ |
+ unsigned int plt_stub_align:4; |
+ |
/* Set if PLT call stubs should load r11. */ |
unsigned int plt_static_chain:1; |
+ /* Set if PLT call stubs need a read-read barrier. */ |
+ unsigned int plt_thread_safe:1; |
+ |
/* Set if we should emit symbols for stubs. */ |
unsigned int emit_stub_syms:1; |
@@ -4230,7 +4245,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) |
".eh_frame", |
flags); |
if (htab->glink_eh_frame == NULL |
- || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2)) |
+ || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2)) |
return FALSE; |
} |
@@ -4293,7 +4308,7 @@ create_got_section (bfd *abfd, struct bfd_link_info *info) |
if (! _bfd_elf_create_got_section (htab->elf.dynobj, info)) |
return FALSE; |
- htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got"); |
+ htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got"); |
if (!htab->got) |
abort (); |
} |
@@ -4332,12 +4347,12 @@ ppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) |
return FALSE; |
if (!htab->got) |
- htab->got = bfd_get_section_by_name (dynobj, ".got"); |
- htab->plt = bfd_get_section_by_name (dynobj, ".plt"); |
- htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt"); |
- htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss"); |
+ htab->got = bfd_get_linker_section (dynobj, ".got"); |
+ htab->plt = bfd_get_linker_section (dynobj, ".plt"); |
+ htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt"); |
+ htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss"); |
if (!info->shared) |
- htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss"); |
+ htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss"); |
if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss |
|| (!info->shared && !htab->relbss)) |
@@ -5507,14 +5522,16 @@ static bfd_vma |
opd_entry_value (asection *opd_sec, |
bfd_vma offset, |
asection **code_sec, |
- bfd_vma *code_off) |
+ bfd_vma *code_off, |
+ bfd_boolean in_code_sec) |
{ |
bfd *opd_bfd = opd_sec->owner; |
Elf_Internal_Rela *relocs; |
Elf_Internal_Rela *lo, *hi, *look; |
bfd_vma val; |
- /* No relocs implies we are linking a --just-symbols object. */ |
+ /* No relocs implies we are linking a --just-symbols object, or looking |
+ at a final linked executable with addr2line or somesuch. */ |
if (opd_sec->reloc_count == 0) |
{ |
char buf[8]; |
@@ -5526,11 +5543,22 @@ opd_entry_value (asection *opd_sec, |
if (code_sec != NULL) |
{ |
asection *sec, *likely = NULL; |
- for (sec = opd_bfd->sections; sec != NULL; sec = sec->next) |
- if (sec->vma <= val |
- && (sec->flags & SEC_LOAD) != 0 |
- && (sec->flags & SEC_ALLOC) != 0) |
- likely = sec; |
+ |
+ if (in_code_sec) |
+ { |
+ sec = *code_sec; |
+ if (sec->vma <= val |
+ && val < sec->vma + sec->size) |
+ likely = sec; |
+ else |
+ val = -1; |
+ } |
+ else |
+ for (sec = opd_bfd->sections; sec != NULL; sec = sec->next) |
+ if (sec->vma <= val |
+ && (sec->flags & SEC_LOAD) != 0 |
+ && (sec->flags & SEC_ALLOC) != 0) |
+ likely = sec; |
if (likely != NULL) |
{ |
*code_sec = likely; |
@@ -5569,15 +5597,18 @@ opd_entry_value (asection *opd_sec, |
unsigned long symndx = ELF64_R_SYM (look->r_info); |
asection *sec; |
- if (symndx < symtab_hdr->sh_info) |
+ if (symndx < symtab_hdr->sh_info |
+ || elf_sym_hashes (opd_bfd) == NULL) |
{ |
Elf_Internal_Sym *sym; |
sym = (Elf_Internal_Sym *) symtab_hdr->contents; |
if (sym == NULL) |
{ |
- sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, |
- symtab_hdr->sh_info, |
+ 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) |
break; |
@@ -5606,7 +5637,12 @@ opd_entry_value (asection *opd_sec, |
if (code_off != NULL) |
*code_off = val; |
if (code_sec != NULL) |
- *code_sec = sec; |
+ { |
+ if (in_code_sec && *code_sec != sec) |
+ return -1; |
+ else |
+ *code_sec = sec; |
+ } |
if (sec != NULL && sec->output_section != NULL) |
val += sec->output_section->vma + sec->output_offset; |
} |
@@ -5617,6 +5653,55 @@ opd_entry_value (asection *opd_sec, |
return val; |
} |
+/* If the ELF symbol SYM might be a function in SEC, return the |
+ function size and set *CODE_OFF to the function's entry point, |
+ otherwise return zero. */ |
+ |
+static bfd_size_type |
+ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec, |
+ bfd_vma *code_off) |
+{ |
+ bfd_size_type size; |
+ |
+ if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT |
+ | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0) |
+ return 0; |
+ |
+ size = 0; |
+ if (!(sym->flags & BSF_SYNTHETIC)) |
+ size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; |
+ |
+ if (strcmp (sym->section->name, ".opd") == 0) |
+ { |
+ if (opd_entry_value (sym->section, sym->value, |
+ &sec, code_off, TRUE) == (bfd_vma) -1) |
+ return 0; |
+ /* An old ABI binary with dot-syms has a size of 24 on the .opd |
+ symbol. This size has nothing to do with the code size of the |
+ function, which is what we're supposed to return, but the |
+ code size isn't available without looking up the dot-sym. |
+ However, doing that would be a waste of time particularly |
+ since elf_find_function will look at the dot-sym anyway. |
+ Now, elf_find_function will keep the largest size of any |
+ function sym found at the code address of interest, so return |
+ 1 here to avoid it incorrectly caching a larger function size |
+ for a small function. This does mean we return the wrong |
+ size for a new-ABI function of size 24, but all that does is |
+ disable caching for such functions. */ |
+ if (size == 24) |
+ size = 1; |
+ } |
+ else |
+ { |
+ if (sym->section != sec) |
+ return 0; |
+ *code_off = sym->value; |
+ } |
+ if (size == 0) |
+ size = 1; |
+ return size; |
+} |
+ |
/* Return true if symbol is defined in a regular object file. */ |
static bfd_boolean |
@@ -5694,7 +5779,7 @@ ppc64_elf_gc_keep (struct bfd_link_info *info) |
else if (get_opd_info (eh->elf.root.u.def.section) != NULL |
&& opd_entry_value (eh->elf.root.u.def.section, |
eh->elf.root.u.def.value, |
- &sec, NULL) != (bfd_vma) -1) |
+ &sec, NULL, FALSE) != (bfd_vma) -1) |
sec->flags |= SEC_KEEP; |
sec = eh->elf.root.u.def.section; |
@@ -5745,7 +5830,7 @@ ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) |
else if (get_opd_info (eh->elf.root.u.def.section) != NULL |
&& opd_entry_value (eh->elf.root.u.def.section, |
eh->elf.root.u.def.value, |
- &code_sec, NULL) != (bfd_vma) -1) |
+ &code_sec, NULL, FALSE) != (bfd_vma) -1) |
code_sec->flags |= SEC_KEEP; |
} |
@@ -5805,7 +5890,7 @@ ppc64_elf_gc_mark_hook (asection *sec, |
else if (get_opd_info (eh->elf.root.u.def.section) != NULL |
&& opd_entry_value (eh->elf.root.u.def.section, |
eh->elf.root.u.def.value, |
- &rsec, NULL) != (bfd_vma) -1) |
+ &rsec, NULL, FALSE) != (bfd_vma) -1) |
eh->elf.root.u.def.section->gc_mark = 1; |
else |
rsec = h->root.u.def.section; |
@@ -6274,7 +6359,7 @@ func_desc_adjust (struct elf_link_hash_entry *h, void *inf) |
&& opd_entry_value (fdh->elf.root.u.def.section, |
fdh->elf.root.u.def.value, |
&fh->elf.root.u.def.section, |
- &fh->elf.root.u.def.value) != (bfd_vma) -1) |
+ &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1) |
{ |
fh->elf.root.type = fdh->elf.root.type; |
fh->elf.forced_local = 1; |
@@ -6383,7 +6468,7 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, |
{ |
struct ppc_link_hash_table *htab; |
unsigned int i; |
- const struct sfpr_def_parms funcs[] = |
+ static const struct sfpr_def_parms funcs[] = |
{ |
{ "_savegpr0_", 14, 31, savegpr0, savegpr0_tail }, |
{ "_restgpr0_", 14, 29, restgpr0, restgpr0_tail }, |
@@ -6409,9 +6494,10 @@ ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, |
/* Provide any missing _save* and _rest* functions. */ |
htab->sfpr->size = 0; |
- for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++) |
- if (!sfpr_define (info, &funcs[i])) |
- return FALSE; |
+ if (!info->relocatable) |
+ 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); |
@@ -6530,13 +6616,6 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
/* This is a reference to a symbol defined by a dynamic object which |
is not a function. */ |
- if (h->size == 0) |
- { |
- info->callbacks->einfo (_("%P: dynamic variable `%s' is zero size\n"), |
- h->root.root.string); |
- return TRUE; |
- } |
- |
/* We must allocate the symbol in our .dynbss section, which will |
become part of the .bss section of the executable. There will be |
an entry for this symbol in the .dynsym section. The dynamic |
@@ -6551,7 +6630,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, |
to copy the initial value out of the dynamic object and into the |
runtime process image. We need to remember the offset into the |
.rela.bss section we are going to use. */ |
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) |
+ if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) |
{ |
htab->relbss->size += sizeof (Elf64_External_Rela); |
h->needs_copy = 1; |
@@ -6852,7 +6931,7 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) |
if (dsec == NULL) |
{ |
for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next) |
- if (elf_discarded_section (dsec)) |
+ if (discarded_section (dsec)) |
{ |
ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec; |
break; |
@@ -7033,7 +7112,7 @@ ppc64_elf_edit_opd (struct bfd_link_info *info, bfd_boolean non_overlapping) |
if (sec == NULL || sec->size == 0) |
continue; |
- if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) |
+ if (sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) |
continue; |
if (sec->output_section == bfd_abs_section_ptr) |
@@ -8077,8 +8156,8 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) |
toc = bfd_get_section_by_name (ibfd, ".toc"); |
if (toc == NULL |
|| toc->size == 0 |
- || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS |
- || elf_discarded_section (toc)) |
+ || toc->sec_info_type == SEC_INFO_TYPE_JUST_SYMS |
+ || discarded_section (toc)) |
continue; |
toc_relocs = NULL; |
@@ -8091,7 +8170,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) |
for (sec = ibfd->sections; sec != NULL; sec = sec->next) |
{ |
if (sec->reloc_count == 0 |
- || !elf_discarded_section (sec) |
+ || !discarded_section (sec) |
|| get_opd_info (sec) |
|| (sec->flags & SEC_ALLOC) == 0 |
|| (sec->flags & SEC_DEBUGGING) != 0) |
@@ -8201,7 +8280,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) |
goto error_ret; |
if (sym_sec == NULL |
- || elf_discarded_section (sym_sec)) |
+ || discarded_section (sym_sec)) |
continue; |
if (!SYMBOL_CALLS_LOCAL (info, h)) |
@@ -8281,7 +8360,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) |
int repeat; |
if (sec->reloc_count == 0 |
- || elf_discarded_section (sec) |
+ || discarded_section (sec) |
|| get_opd_info (sec) |
|| (sec->flags & SEC_ALLOC) == 0 |
|| (sec->flags & SEC_DEBUGGING) != 0) |
@@ -8503,7 +8582,7 @@ ppc64_elf_edit_toc (struct bfd_link_info *info) |
for (sec = ibfd->sections; sec != NULL; sec = sec->next) |
{ |
if (sec->reloc_count == 0 |
- || elf_discarded_section (sec)) |
+ || discarded_section (sec)) |
continue; |
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, |
@@ -9061,7 +9140,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, |
/* Set the contents of the .interp section to the interpreter. */ |
if (info->executable) |
{ |
- s = bfd_get_section_by_name (dynobj, ".interp"); |
+ s = bfd_get_linker_section (dynobj, ".interp"); |
if (s == NULL) |
abort (); |
s->size = sizeof ELF_DYNAMIC_INTERPRETER; |
@@ -9471,21 +9550,126 @@ ppc_type_of_stub (asection *input_sec, |
return ppc_stub_none; |
} |
-/* Build a .plt call stub. */ |
+/* With power7 weakly ordered memory model, it is possible for ld.so |
+ to update a plt entry in one thread and have another thread see a |
+ stale zero toc entry. To avoid this we need some sort of acquire |
+ barrier in the call stub. One solution is to make the load of the |
+ toc word seem to appear to depend on the load of the function entry |
+ word. Another solution is to test for r2 being zero, and branch to |
+ the appropriate glink entry if so. |
+ |
+ . fake dep barrier compare |
+ . ld 11,xxx(2) ld 11,xxx(2) |
+ . mtctr 11 mtctr 11 |
+ . xor 11,11,11 ld 2,xxx+8(2) |
+ . add 2,2,11 cmpldi 2,0 |
+ . ld 2,xxx+8(2) bnectr+ |
+ . bctr b <glink_entry> |
+ |
+ The solution involving the compare turns out to be faster, so |
+ that's what we use unless the branch won't reach. */ |
+ |
+#define ALWAYS_USE_FAKE_DEP 0 |
+#define ALWAYS_EMIT_R2SAVE 0 |
-static inline bfd_byte * |
-build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
- bfd_boolean plt_static_chain) |
-{ |
#define PPC_LO(v) ((v) & 0xffff) |
#define PPC_HI(v) (((v) >> 16) & 0xffff) |
#define PPC_HA(v) PPC_HI ((v) + 0x8000) |
+static inline unsigned int |
+plt_stub_size (struct ppc_link_hash_table *htab, |
+ struct ppc_stub_hash_entry *stub_entry, |
+ bfd_vma off) |
+{ |
+ unsigned size = PLT_CALL_STUB_SIZE; |
+ |
+ if (!(ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save)) |
+ size -= 4; |
+ if (!htab->plt_static_chain) |
+ size -= 4; |
+ if (htab->plt_thread_safe) |
+ size += 8; |
+ if (PPC_HA (off) == 0) |
+ size -= 4; |
+ if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) |
+ size += 4; |
+ if (stub_entry->h != NULL |
+ && (stub_entry->h == htab->tls_get_addr_fd |
+ || stub_entry->h == htab->tls_get_addr) |
+ && !htab->no_tls_get_addr_opt) |
+ size += 13 * 4; |
+ return size; |
+} |
+ |
+/* If this stub would cross fewer 2**plt_stub_align boundaries if we align, |
+ then return the padding needed to do so. */ |
+static inline unsigned int |
+plt_stub_pad (struct ppc_link_hash_table *htab, |
+ struct ppc_stub_hash_entry *stub_entry, |
+ bfd_vma plt_off) |
+{ |
+ int stub_align = 1 << htab->plt_stub_align; |
+ unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); |
+ bfd_vma stub_off = stub_entry->stub_sec->size; |
+ |
+ if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) |
+ > (stub_size & -stub_align)) |
+ return stub_align - (stub_off & (stub_align - 1)); |
+ return 0; |
+} |
+ |
+/* Build a .plt call stub. */ |
+ |
+static inline bfd_byte * |
+build_plt_stub (struct ppc_link_hash_table *htab, |
+ struct ppc_stub_hash_entry *stub_entry, |
+ bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) |
+{ |
+ bfd *obfd = htab->stub_bfd; |
+ bfd_boolean plt_static_chain = htab->plt_static_chain; |
+ bfd_boolean plt_thread_safe = htab->plt_thread_safe; |
+ bfd_boolean use_fake_dep = plt_thread_safe; |
+ bfd_vma cmp_branch_off = 0; |
+ |
+ if (!ALWAYS_USE_FAKE_DEP |
+ && plt_thread_safe |
+ && !(stub_entry->h != NULL |
+ && (stub_entry->h == htab->tls_get_addr_fd |
+ || stub_entry->h == htab->tls_get_addr) |
+ && !htab->no_tls_get_addr_opt)) |
+ { |
+ bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; |
+ bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE; |
+ bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8; |
+ bfd_vma to, from; |
+ |
+ if (pltindex > 32767) |
+ glinkoff += (pltindex - 32767) * 4; |
+ to = (glinkoff |
+ + htab->glink->output_offset |
+ + htab->glink->output_section->vma); |
+ from = (p - stub_entry->stub_sec->contents |
+ + 4 * (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ + 4 * (PPC_HA (offset) != 0) |
+ + 4 * (PPC_HA (offset + 8 + 8 * plt_static_chain) |
+ != PPC_HA (offset)) |
+ + 4 * (plt_static_chain != 0) |
+ + 20 |
+ + stub_entry->stub_sec->output_offset |
+ + stub_entry->stub_sec->output_section->vma); |
+ cmp_branch_off = to - from; |
+ use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26); |
+ } |
+ |
if (PPC_HA (offset) != 0) |
{ |
if (r != NULL) |
{ |
- r[0].r_offset += 4; |
+ if (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ r[0].r_offset += 4; |
r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA); |
r[1].r_offset = r[0].r_offset + 4; |
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); |
@@ -9498,7 +9682,7 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
} |
else |
{ |
- r[2].r_offset = r[1].r_offset + 8; |
+ r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; |
r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); |
r[2].r_addend = r[0].r_addend + 8; |
if (plt_static_chain) |
@@ -9509,7 +9693,9 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
} |
} |
} |
- bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; |
+ if (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; |
bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; |
bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; |
if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) |
@@ -9518,16 +9704,22 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
offset = 0; |
} |
bfd_put_32 (obfd, MTCTR_R11, p), p += 4; |
+ if (use_fake_dep) |
+ { |
+ bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; |
+ bfd_put_32 (obfd, ADD_R12_R12_R11, p), p += 4; |
+ } |
bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p), p += 4; |
if (plt_static_chain) |
bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4; |
- bfd_put_32 (obfd, BCTR, p), p += 4; |
} |
else |
{ |
if (r != NULL) |
{ |
- r[0].r_offset += 4; |
+ if (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ r[0].r_offset += 4; |
r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); |
if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) |
{ |
@@ -9537,7 +9729,7 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
} |
else |
{ |
- r[1].r_offset = r[0].r_offset + 8; |
+ r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; |
r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); |
r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; |
if (plt_static_chain) |
@@ -9548,7 +9740,9 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
} |
} |
} |
- bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; |
+ if (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; |
bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p), p += 4; |
if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) |
{ |
@@ -9556,11 +9750,23 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
offset = 0; |
} |
bfd_put_32 (obfd, MTCTR_R11, p), p += 4; |
+ if (use_fake_dep) |
+ { |
+ bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; |
+ bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; |
+ } |
if (plt_static_chain) |
bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; |
bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; |
- bfd_put_32 (obfd, BCTR, p), p += 4; |
} |
+ if (plt_thread_safe && !use_fake_dep) |
+ { |
+ bfd_put_32 (obfd, CMPLDI_R2_0, p), p += 4; |
+ bfd_put_32 (obfd, BNECTR_P4, p), p += 4; |
+ bfd_put_32 (obfd, B_DOT + cmp_branch_off, p), p += 4; |
+ } |
+ else |
+ bfd_put_32 (obfd, BCTR, p), p += 4; |
return p; |
} |
@@ -9581,9 +9787,12 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r, |
#define MTLR_R11 0x7d6803a6 |
static inline bfd_byte * |
-build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset, |
- Elf_Internal_Rela *r, bfd_boolean plt_static_chain) |
+build_tls_get_addr_stub (struct ppc_link_hash_table *htab, |
+ struct ppc_stub_hash_entry *stub_entry, |
+ bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) |
{ |
+ bfd *obfd = htab->stub_bfd; |
+ |
bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4; |
bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; |
bfd_put_32 (obfd, MR_R0_R3, p), p += 4; |
@@ -9596,7 +9805,7 @@ build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset, |
if (r != NULL) |
r[0].r_offset += 9 * 4; |
- p = build_plt_stub (obfd, p, offset, r, plt_static_chain); |
+ p = build_plt_stub (htab, stub_entry, p, offset, r); |
bfd_put_32 (obfd, BCTRL, p - 4); |
bfd_put_32 (obfd, LD_R11_0R1 + 32, p), p += 4; |
@@ -9943,6 +10152,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
break; |
case ppc_stub_plt_call: |
+ case ppc_stub_plt_call_r2save: |
if (stub_entry->h != NULL |
&& stub_entry->h->is_func_descriptor |
&& stub_entry->h->oh != NULL) |
@@ -10009,6 +10219,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
return FALSE; |
} |
+ if (htab->plt_stub_align != 0) |
+ { |
+ unsigned pad = plt_stub_pad (htab, stub_entry, off); |
+ |
+ stub_entry->stub_sec->size += pad; |
+ stub_entry->stub_offset = stub_entry->stub_sec->size; |
+ loc += pad; |
+ } |
+ |
r = NULL; |
if (info->emitrelocations) |
{ |
@@ -10028,11 +10247,9 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
&& (stub_entry->h == htab->tls_get_addr_fd |
|| stub_entry->h == htab->tls_get_addr) |
&& !htab->no_tls_get_addr_opt) |
- p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r, |
- htab->plt_static_chain); |
+ p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r); |
else |
- p = build_plt_stub (htab->stub_bfd, loc, off, r, |
- htab->plt_static_chain); |
+ p = build_plt_stub (htab, stub_entry, loc, off, r); |
size = p - loc; |
break; |
@@ -10052,6 +10269,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
"long_branch_r2off", |
"plt_branch", |
"plt_branch_r2off", |
+ "plt_call", |
"plt_call" }; |
len1 = strlen (stub_str[stub_entry->stub_type - 1]); |
@@ -10102,7 +10320,8 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
if (htab == NULL) |
return FALSE; |
- if (stub_entry->stub_type == ppc_stub_plt_call) |
+ if (stub_entry->stub_type == ppc_stub_plt_call |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
{ |
asection *plt; |
off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1; |
@@ -10118,18 +10337,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) |
- elf_gp (plt->output_section->owner) |
- htab->stub_group[stub_entry->id_sec->id].toc_off); |
- size = PLT_CALL_STUB_SIZE; |
- if (!htab->plt_static_chain) |
- size -= 4; |
- if (PPC_HA (off) == 0) |
- size -= 4; |
- if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) |
- size += 4; |
- if (stub_entry->h != NULL |
- && (stub_entry->h == htab->tls_get_addr_fd |
- || stub_entry->h == htab->tls_get_addr) |
- && !htab->no_tls_get_addr_opt) |
- size += 13 * 4; |
+ size = plt_stub_size (htab, stub_entry, off); |
+ if (htab->plt_stub_align) |
+ size += plt_stub_pad (htab, stub_entry, off); |
if (info->emitrelocations) |
{ |
stub_entry->stub_sec->reloc_count |
@@ -10344,7 +10554,9 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) |
if (!htab->second_toc_pass) |
{ |
/* Keep track of the first .toc or .got section for this input bfd. */ |
- if (htab->toc_bfd != isec->owner) |
+ bfd_boolean new_bfd = htab->toc_bfd != isec->owner; |
+ |
+ if (new_bfd) |
{ |
htab->toc_bfd = isec->owner; |
htab->toc_first_sec = isec; |
@@ -10372,7 +10584,8 @@ ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) |
/* Die if someone uses a linker script that doesn't keep input |
file .toc and .got together. */ |
- if (elf_gp (isec->owner) != 0 |
+ if (new_bfd |
+ && elf_gp (isec->owner) != 0 |
&& elf_gp (isec->owner) != off) |
return FALSE; |
@@ -10741,7 +10954,8 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) |
sym_value += adjust; |
} |
- dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL); |
+ dest = opd_entry_value (sym_sec, sym_value, |
+ &sym_sec, NULL, FALSE); |
if (dest == (bfd_vma) -1) |
continue; |
} |
@@ -11098,7 +11312,8 @@ maybe_strip_output (struct bfd_link_info *info, asection *isec) |
bfd_boolean |
ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
- bfd_boolean plt_static_chain) |
+ bfd_boolean plt_static_chain, int plt_thread_safe, |
+ int plt_stub_align) |
{ |
bfd_size_type stub_group_size; |
bfd_boolean stubs_always_before_branch; |
@@ -11108,6 +11323,40 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
return FALSE; |
htab->plt_static_chain = plt_static_chain; |
+ htab->plt_stub_align = plt_stub_align; |
+ if (plt_thread_safe == -1) |
+ { |
+ const char *const thread_starter[] = |
+ { |
+ "pthread_create", |
+ /* libstdc++ */ |
+ "_ZNSt6thread15_M_start_threadESt10shared_ptrINS_10_Impl_baseEE", |
+ /* librt */ |
+ "aio_init", "aio_read", "aio_write", "aio_fsync", "lio_listio", |
+ "mq_notify", "create_timer", |
+ /* libanl */ |
+ "getaddrinfo_a", |
+ /* libgomp */ |
+ "GOMP_parallel_start", |
+ "GOMP_parallel_loop_static_start", |
+ "GOMP_parallel_loop_dynamic_start", |
+ "GOMP_parallel_loop_guided_start", |
+ "GOMP_parallel_loop_runtime_start", |
+ "GOMP_parallel_sections_start", |
+ }; |
+ unsigned i; |
+ |
+ for (i = 0; i < sizeof (thread_starter)/ sizeof (thread_starter[0]); i++) |
+ { |
+ struct elf_link_hash_entry *h; |
+ h = elf_link_hash_lookup (&htab->elf, thread_starter[i], |
+ FALSE, FALSE, TRUE); |
+ plt_thread_safe = h != NULL && h->ref_regular; |
+ if (plt_thread_safe) |
+ break; |
+ } |
+ } |
+ htab->plt_thread_safe = plt_thread_safe; |
stubs_always_before_branch = group_size < 0; |
if (group_size < 0) |
stub_group_size = -group_size; |
@@ -11281,7 +11530,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
sym_value += adjust; |
} |
dest = opd_entry_value (sym_sec, sym_value, |
- &code_sec, &code_value); |
+ &code_sec, &code_value, FALSE); |
if (dest != (bfd_vma) -1) |
{ |
destination = dest; |
@@ -11342,10 +11591,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
if (stub_type == ppc_stub_plt_call |
&& irela + 1 < irelaend |
&& irela[1].r_offset == irela->r_offset + 4 |
- && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE |
- && !tocsave_find (htab, INSERT, |
- &local_syms, irela + 1, input_bfd)) |
- goto error_ret_free_internal; |
+ && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE) |
+ { |
+ if (!tocsave_find (htab, INSERT, |
+ &local_syms, irela + 1, input_bfd)) |
+ goto error_ret_free_internal; |
+ } |
+ else if (stub_type == ppc_stub_plt_call) |
+ stub_type = ppc_stub_plt_call_r2save; |
/* Support for grouping stub sections. */ |
id_sec = htab->stub_group[section->id].link_sec; |
@@ -11361,6 +11614,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
{ |
/* The proper stub has already been created. */ |
free (stub_name); |
+ if (stub_type == ppc_stub_plt_call_r2save) |
+ stub_entry->stub_type = stub_type; |
continue; |
} |
@@ -11380,7 +11635,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
} |
stub_entry->stub_type = stub_type; |
- if (stub_type != ppc_stub_plt_call) |
+ if (stub_type != ppc_stub_plt_call |
+ && stub_type != ppc_stub_plt_call_r2save) |
{ |
stub_entry->target_value = code_value; |
stub_entry->target_section = code_sec; |
@@ -11443,9 +11699,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
if (htab->glink_eh_frame != NULL |
&& !bfd_is_abs_section (htab->glink_eh_frame->output_section) |
- && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0) |
+ && htab->glink_eh_frame->output_section->size != 0) |
{ |
- bfd_size_type size = 0; |
+ size_t size = 0, align; |
for (stub_sec = htab->stub_bfd->sections; |
stub_sec != NULL; |
@@ -11456,10 +11712,22 @@ ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size, |
size += 24; |
if (size != 0) |
size += sizeof (glink_eh_frame_cie); |
+ align = 1; |
+ align <<= htab->glink_eh_frame->output_section->alignment_power; |
+ align -= 1; |
+ size = (size + align) & ~align; |
htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; |
htab->glink_eh_frame->size = size; |
} |
+ if (htab->plt_stub_align != 0) |
+ for (stub_sec = htab->stub_bfd->sections; |
+ stub_sec != NULL; |
+ stub_sec = stub_sec->next) |
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) |
+ stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) |
+ & (-1 << htab->plt_stub_align)); |
+ |
for (stub_sec = htab->stub_bfd->sections; |
stub_sec != NULL; |
stub_sec = stub_sec->next) |
@@ -11689,17 +11957,21 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
&& 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). */ |
- bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); |
+ 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->stub_bfd->sections; |
@@ -11707,6 +11979,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
stub_sec = stub_sec->next) |
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) |
{ |
+ last_fde = p; |
+ last_fde_len = 16; |
/* FDE length. */ |
bfd_put_32 (htab->elf.dynobj, 16, p); |
p += 4; |
@@ -11739,6 +12013,8 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
} |
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; |
@@ -11776,7 +12052,16 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
*p++ = DW_CFA_restore_extended; |
*p++ = 65; |
} |
- htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents; |
+ /* 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. */ |
@@ -11785,6 +12070,14 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
if (htab->relbrlt != NULL) |
htab->relbrlt->reloc_count = 0; |
+ if (htab->plt_stub_align != 0) |
+ for (stub_sec = htab->stub_bfd->sections; |
+ stub_sec != NULL; |
+ stub_sec = stub_sec->next) |
+ if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) |
+ stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1) |
+ & (-1 << htab->plt_stub_align)); |
+ |
for (stub_sec = htab->stub_bfd->sections; |
stub_sec != NULL; |
stub_sec = stub_sec->next) |
@@ -11818,14 +12111,16 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, |
" toc adjust %lu\n" |
" long branch %lu\n" |
" long toc adj %lu\n" |
- " plt call %lu"), |
+ " plt call %lu\n" |
+ " plt call toc %lu"), |
stub_sec_count, |
stub_sec_count == 1 ? "" : "s", |
htab->stub_count[ppc_stub_long_branch - 1], |
htab->stub_count[ppc_stub_long_branch_r2off - 1], |
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 - 1], |
+ htab->stub_count[ppc_stub_plt_call_r2save - 1]); |
} |
return TRUE; |
} |
@@ -11925,8 +12220,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
bfd_vma TOCstart; |
bfd_boolean ret = TRUE; |
bfd_boolean is_opd; |
- /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ |
- bfd_boolean is_power4 = FALSE; |
+ /* Assume 'at' branch hints. */ |
+ bfd_boolean is_isa_v2 = TRUE; |
bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); |
/* Initialize howto table if needed. */ |
@@ -12036,10 +12331,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
} |
h = (struct ppc_link_hash_entry *) h_elf; |
- if (sec != NULL && elf_discarded_section (sec)) |
+ if (sec != NULL && discarded_section (sec)) |
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, |
- rel, relend, |
- ppc64_elf_howto_table[r_type], |
+ rel, 1, relend, |
+ ppc64_elf_howto_table[r_type], 0, |
contents); |
if (info->relocatable) |
@@ -12558,6 +12853,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab); |
if (stub_entry != NULL |
&& (stub_entry->stub_type == ppc_stub_plt_call |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save |
|| stub_entry->stub_type == ppc_stub_plt_branch_r2off |
|| stub_entry->stub_type == ppc_stub_long_branch_r2off)) |
{ |
@@ -12586,7 +12882,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
if (!can_plt_call) |
{ |
- if (stub_entry->stub_type == ppc_stub_plt_call) |
+ if (stub_entry->stub_type == ppc_stub_plt_call |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
{ |
/* If this is a plain branch rather than a branch |
and link, don't require a nop. However, don't |
@@ -12633,7 +12930,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
} |
if (can_plt_call |
- && stub_entry->stub_type == ppc_stub_plt_call) |
+ && (stub_entry->stub_type == ppc_stub_plt_call |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save)) |
unresolved_reloc = FALSE; |
} |
@@ -12646,7 +12944,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
bfd_vma off = (relocation + addend |
- sec->output_section->vma |
- sec->output_offset); |
- bfd_vma dest = opd_entry_value (sec, off, NULL, NULL); |
+ bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE); |
if (dest != (bfd_vma) -1) |
{ |
relocation = dest; |
@@ -12679,7 +12977,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
+ stub_entry->stub_sec->output_section->vma); |
addend = 0; |
- if (stub_entry->stub_type == ppc_stub_plt_call |
+ if ((stub_entry->stub_type == ppc_stub_plt_call |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
+ && (ALWAYS_EMIT_R2SAVE |
+ || stub_entry->stub_type == ppc_stub_plt_call_r2save) |
&& rel + 1 < relend |
&& rel[1].r_offset == rel->r_offset + 4 |
&& ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE) |
@@ -12688,7 +12989,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, |
if (insn != 0) |
{ |
- if (is_power4) |
+ if (is_isa_v2) |
{ |
/* Set 'a' bit. This is 0b00010 in BO field for branch |
on CR(BI) insns (BO == 001at or 011at), and 0b01000 |
@@ -13626,7 +13927,7 @@ static bfd_boolean |
ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, |
struct bfd_link_info *info, |
struct elf_link_hash_entry *h, |
- Elf_Internal_Sym *sym) |
+ Elf_Internal_Sym *sym ATTRIBUTE_UNUSED) |
{ |
struct ppc_link_hash_table *htab; |
struct plt_entry *ent; |
@@ -13695,10 +13996,6 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, |
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); |
} |
- /* Mark some specially defined symbols as absolute. */ |
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0) |
- sym->st_shndx = SHN_ABS; |
- |
return TRUE; |
} |
@@ -13739,7 +14036,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, |
return FALSE; |
dynobj = htab->elf.dynobj; |
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); |
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic"); |
if (htab->elf.dynamic_sections_created) |
{ |
@@ -13867,7 +14164,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, |
if (htab->glink_eh_frame != NULL |
- && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME |
+ && 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)) |