Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3298)

Unified Diff: bfd/elf64-ppc.c

Issue 11969036: Merge GDB 7.5.1 (Closed) Base URL: http://git.chromium.org/native_client/nacl-gdb.git@master
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « bfd/elf64-ppc.h ('k') | bfd/elf64-s390.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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))
« no previous file with comments | « bfd/elf64-ppc.h ('k') | bfd/elf64-s390.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698