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"
{
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
return FALSE;
/* pr_cursig */
- elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+ elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12);
/* pr_pid */
- elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32);
+ elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32);
/* pr_reg */
offset = 112;
if (note->descsz != 136)
return FALSE;
- elf_tdata (abfd)->core_pid
+ elf_tdata (abfd)->core->pid
= bfd_get_32 (abfd, note->descdata + 24);
- elf_tdata (abfd)->core_program
+ elf_tdata (abfd)->core->program
= _bfd_elfcore_strndup (abfd, note->descdata + 40, 16);
- elf_tdata (abfd)->core_command
+ elf_tdata (abfd)->core->command
= _bfd_elfcore_strndup (abfd, note->descdata + 56, 80);
return TRUE;
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
goto free_contents_and_exit;
-
+
plt_count = relplt->size / sizeof (Elf64_External_Rela);
size += plt_count * sizeof (asymbol);
unsigned int iter;
};
+/* Used to track dynamic relocations for local symbols. */
+struct ppc_dyn_relocs
+{
+ struct ppc_dyn_relocs *next;
+
+ /* The input section of the reloc. */
+ asection *sec;
+
+ /* Total number of relocs copied for the input section. */
+ unsigned int count : 31;
+
+ /* Whether this entry is for STT_GNU_IFUNC symbols. */
+ unsigned int ifunc : 1;
+};
+
struct ppc_link_hash_entry
{
struct elf_link_hash_entry elf;
struct ppc_link_hash_entry *tls_get_addr;
struct ppc_link_hash_entry *tls_get_addr_fd;
+ /* The special .TOC. symbol. */
+ struct ppc_link_hash_entry *dot_toc_dot;
+
/* The size of reliplt used by got entry relocs. */
bfd_size_type got_reli_size;
bfd_hash_table_free (&htab->branch_hash_table);
if (htab->tocsave_htab)
htab_delete (htab->tocsave_htab);
- _bfd_generic_link_hash_table_free (hash);
+ _bfd_elf_link_hash_table_free (hash);
+}
+
+/* Create sections for linker generated code. */
+
+static bfd_boolean
+create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
+{
+ struct ppc_link_hash_table *htab;
+ flagword flags;
+
+ 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;
+
+ /* Create .glink for lazy dynamic linking support. */
+ htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
+ flags);
+ if (htab->glink == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
+ return FALSE;
+
+ if (!info->no_ld_generated_unwind_info)
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
+ ".eh_frame",
+ flags);
+ if (htab->glink_eh_frame == NULL
+ || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
+ return FALSE;
+ }
+
+ flags = SEC_ALLOC | SEC_LINKER_CREATED;
+ htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
+ if (htab->iplt == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
+ return FALSE;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
+ ".rela.iplt",
+ flags);
+ if (htab->reliplt == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
+ return FALSE;
+
+ /* Create branch lookup table for plt_branch stubs. */
+ flags = (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
+ flags);
+ if (htab->brlt == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
+ return FALSE;
+
+ if (!info->shared)
+ return TRUE;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
+ ".rela.branch_lt",
+ flags);
+ if (htab->relbrlt == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+ return FALSE;
+
+ return TRUE;
}
/* Satisfy the ELF linker by filling in some fields in our fake bfd. */
-void
+bfd_boolean
ppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
the start of the output TOC section. */
htab = ppc_hash_table (info);
if (htab == NULL)
- return;
+ return FALSE;
htab->stub_bfd = abfd;
htab->elf.dynobj = abfd;
+
+ if (info->relocatable)
+ return TRUE;
+
+ return create_linkage_sections (htab->elf.dynobj, info);
}
/* Build a name for an entry in the stub hash table. */
const Elf_Internal_Rela *rel)
{
char *stub_name;
- bfd_size_type len;
+ ssize_t len;
/* rel->r_addend is actually 64 bit, but who uses more than +/- 2^31
offsets from a sym as a branch target? In fact, we could
if (stub_name == NULL)
return stub_name;
- sprintf (stub_name, "%08x.%s+%x",
- input_section->id & 0xffffffff,
- h->elf.root.root.string,
- (int) rel->r_addend & 0xffffffff);
+ len = sprintf (stub_name, "%08x.%s+%x",
+ input_section->id & 0xffffffff,
+ h->elf.root.root.string,
+ (int) rel->r_addend & 0xffffffff);
}
else
{
if (stub_name == NULL)
return stub_name;
- sprintf (stub_name, "%08x.%x:%x+%x",
- input_section->id & 0xffffffff,
- sym_sec->id & 0xffffffff,
- (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
- (int) rel->r_addend & 0xffffffff);
+ len = sprintf (stub_name, "%08x.%x:%x+%x",
+ input_section->id & 0xffffffff,
+ sym_sec->id & 0xffffffff,
+ (int) ELF64_R_SYM (rel->r_info) & 0xffffffff,
+ (int) rel->r_addend & 0xffffffff);
}
- if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
+ if (len > 2 && stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
stub_name[len - 2] = 0;
return stub_name;
}
return stub_entry;
}
-/* Create sections for linker generated code. */
-
-static bfd_boolean
-create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
-{
- struct ppc_link_hash_table *htab;
- flagword flags;
-
- htab = ppc_hash_table (info);
- if (htab == NULL)
- return FALSE;
-
- /* 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;
-
- /* Create .glink for lazy dynamic linking support. */
- htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
- flags);
- if (htab->glink == NULL
- || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
- return FALSE;
-
- if (!info->no_ld_generated_unwind_info)
- {
- flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj,
- ".eh_frame",
- flags);
- if (htab->glink_eh_frame == NULL
- || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2))
- return FALSE;
- }
-
- flags = SEC_ALLOC | SEC_LINKER_CREATED;
- htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
- if (htab->iplt == NULL
- || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
- return FALSE;
-
- flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
- ".rela.iplt",
- flags);
- if (htab->reliplt == NULL
- || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
- return FALSE;
-
- /* Create branch lookup table for plt_branch stubs. */
- flags = (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
- flags);
- if (htab->brlt == NULL
- || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
- return FALSE;
-
- if (!info->shared)
- return TRUE;
-
- flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
- ".rela.branch_lt",
- flags);
- if (htab->relbrlt == NULL
- || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
- return FALSE;
-
- return TRUE;
-}
-
/* Create .got and .rela.got sections in ABFD, and .got in dynobj if
not already done. */
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 ();
}
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))
/* If we were called to copy over info for a weak sym, that's all.
You might think dyn_relocs need not be copied over; After all,
both syms will be dynamic or both non-dynamic so we're just
- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
+ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
code in ppc64_elf_adjust_dynamic_symbol needs to check for
dyn_relocs in read-only sections, and it does so on what is the
DIR sym here. */
ppc64_elf_section_data (sec)->sec_type = sec_opd;
}
- if (htab->sfpr == NULL
- && !create_linkage_sections (htab->elf.dynobj, info))
- return FALSE;
-
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
{
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
h = elf_follow_link (h);
+
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.non_ir_ref = 1;
}
tls_type = 0;
if ((info->shared
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
- && (! info->symbolic
+ && (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
|| (!info->shared
&& ifunc != NULL))
{
- struct elf_dyn_relocs *p;
- struct elf_dyn_relocs **head;
-
/* We must copy these reloc types into the output file.
Create a reloc section in dynobj and make room for
this reloc. */
relocations we need for this symbol. */
if (h != NULL)
{
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **head;
+
head = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
+ p = *head;
+ if (p == NULL || p->sec != sec)
+ {
+ p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+ if (p == NULL)
+ return FALSE;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ p->count = 0;
+ p->pc_count = 0;
+ }
+ p->count += 1;
+ if (!must_be_dyn_reloc (info, r_type))
+ p->pc_count += 1;
}
else
{
/* Track dynamic relocs needed for local syms too.
We really need local syms available to do this
easily. Oh well. */
+ struct ppc_dyn_relocs *p;
+ struct ppc_dyn_relocs **head;
+ bfd_boolean is_ifunc;
asection *s;
void *vpp;
Elf_Internal_Sym *isym;
s = sec;
vpp = &elf_section_data (s)->local_dynrel;
- head = (struct elf_dyn_relocs **) vpp;
- }
-
- p = *head;
- if (p == NULL || p->sec != sec)
- {
- p = bfd_alloc (htab->elf.dynobj, sizeof *p);
- if (p == NULL)
- return FALSE;
- p->next = *head;
- *head = p;
- p->sec = sec;
- p->count = 0;
- p->pc_count = 0;
+ head = (struct ppc_dyn_relocs **) vpp;
+ is_ifunc = ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC;
+ p = *head;
+ if (p != NULL && p->sec == sec && p->ifunc != is_ifunc)
+ p = p->next;
+ if (p == NULL || p->sec != sec || p->ifunc != is_ifunc)
+ {
+ p = bfd_alloc (htab->elf.dynobj, sizeof *p);
+ if (p == NULL)
+ return FALSE;
+ p->next = *head;
+ *head = p;
+ p->sec = sec;
+ p->ifunc = is_ifunc;
+ p->count = 0;
+ }
+ p->count += 1;
}
-
- p->count += 1;
- if (!must_be_dyn_reloc (info, r_type))
- p->pc_count += 1;
}
break;
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;
at a final linked executable with addr2line or somesuch. */
if (opd_sec->reloc_count == 0)
{
- /* PR 13897: Cache the loaded section to speed up the search. */
- static asection * buf_sec = NULL;
- static char buf[8];
- static bfd_vma buf_val = 0;
- static asection * buf_likely = NULL;
-
- if (buf_sec == opd_sec)
- {
- if (code_sec != NULL)
- * code_sec = buf_likely;
- if (code_off != NULL && buf_likely != NULL)
- * code_off = buf_val - buf_likely->vma;
- return buf_val;
- }
-
+ char buf[8];
+
if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
return (bfd_vma) -1;
- buf_sec = opd_sec;
- buf_val = bfd_get_64 (opd_bfd, buf);
+ val = bfd_get_64 (opd_bfd, buf);
if (code_sec != NULL)
{
- asection *sec;
+ asection *sec, *likely = NULL;
- buf_likely = NULL;
- for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
- if (sec->vma <= buf_val
- && (sec->flags & SEC_LOAD) != 0
- && (sec->flags & SEC_ALLOC) != 0)
- buf_likely = sec;
- if (buf_likely != NULL)
+ if (in_code_sec)
{
- *code_sec = buf_likely;
+ 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;
if (code_off != NULL)
- *code_off = buf_val - buf_likely->vma;
+ *code_off = val - likely->vma;
}
}
- else
- buf_likely = NULL;
- return buf_val;
+ return val;
}
BFD_ASSERT (is_ppc64_elf (opd_bfd));
sym_hashes = elf_sym_hashes (opd_bfd);
rh = sym_hashes[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;
+ if (rh != NULL)
+ {
+ 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;
+ }
+ 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);
+ if (sym == NULL)
+ break;
+
+ val = sym->st_value;
+ sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
+ free (sym);
+ }
}
val += look->r_addend;
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;
}
return val;
}
-/* Return TRUE iff the ELF symbol SYM might be a function. Set *CODE_SEC
- and *CODE_OFF to the function's entry point. */
+/* 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_boolean
-ppc64_elf_maybe_function_sym (const asymbol *sym,
- asection **code_sec, bfd_vma *code_off)
+static bfd_size_type
+ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
{
- if (_bfd_elf_maybe_function_sym (sym, code_sec, 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 (strcmp (sym->section->name, ".opd") == 0)
- opd_entry_value (sym->section, sym->value, code_sec, code_off);
- return TRUE;
+ 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;
}
- return FALSE;
+ 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. */
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;
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;
}
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;
&& 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;
{
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 },
/* 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);
sections. Allow them to proceed, but warn that this might
break at runtime. */
info->callbacks->einfo
- (_("%P: copy reloc against `%s' requires lazy plt linking; "
+ (_("%P: copy reloc against `%T' requires lazy plt linking; "
"avoid setting LD_BIND_NOW=1 or upgrade gcc\n"),
h->root.root.string);
}
}
/* Handles decrementing dynamic reloc counts for the reloc specified by
- R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM_SEC
+ R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM
have already been determined. */
static bfd_boolean
struct bfd_link_info *info,
Elf_Internal_Sym **local_syms,
struct elf_link_hash_entry *h,
- asection *sym_sec)
+ Elf_Internal_Sym *sym)
{
enum elf_ppc64_reloc_type r_type;
- struct elf_dyn_relocs *p;
- struct elf_dyn_relocs **pp;
+ asection *sym_sec = NULL;
/* Can this reloc be dynamic? This switch, and later tests here
should be kept in sync with the code in check_relocs. */
if (local_syms != NULL)
{
unsigned long r_symndx;
- Elf_Internal_Sym *sym;
bfd *ibfd = sec->owner;
r_symndx = ELF64_R_SYM (r_info);
if ((info->shared
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
- && (!info->symbolic
+ && (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
return TRUE;
if (h != NULL)
- pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
- else
{
- if (sym_sec != NULL)
- {
- void *vpp = &elf_section_data (sym_sec)->local_dynrel;
- pp = (struct elf_dyn_relocs **) vpp;
- }
- else
- {
- void *vpp = &elf_section_data (sec)->local_dynrel;
- pp = (struct elf_dyn_relocs **) vpp;
- }
+ struct elf_dyn_relocs *p;
+ struct elf_dyn_relocs **pp;
+ pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs;
/* elf_gc_sweep may have already removed all dyn relocs associated
- with local syms for a given section. Don't report a dynreloc
- miscount. */
- if (*pp == NULL)
+ with local syms for a given section. Also, symbol flags are
+ changed by elf_gc_sweep_symbol, confusing the test above. Don't
+ report a dynreloc miscount. */
+ if (*pp == NULL && info->gc_sections)
return TRUE;
- }
- while ((p = *pp) != NULL)
+ while ((p = *pp) != NULL)
+ {
+ if (p->sec == sec)
+ {
+ if (!must_be_dyn_reloc (info, r_type))
+ p->pc_count -= 1;
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ return TRUE;
+ }
+ pp = &p->next;
+ }
+ }
+ else
{
- if (p->sec == sec)
+ struct ppc_dyn_relocs *p;
+ struct ppc_dyn_relocs **pp;
+ void *vpp;
+ bfd_boolean is_ifunc;
+
+ if (local_syms == NULL)
+ sym_sec = bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+ if (sym_sec == NULL)
+ sym_sec = sec;
+
+ vpp = &elf_section_data (sym_sec)->local_dynrel;
+ pp = (struct ppc_dyn_relocs **) vpp;
+
+ if (*pp == NULL && info->gc_sections)
+ return TRUE;
+
+ is_ifunc = ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC;
+ while ((p = *pp) != NULL)
{
- if (!must_be_dyn_reloc (info, r_type))
- p->pc_count -= 1;
- p->count -= 1;
- if (p->count == 0)
- *pp = p->next;
- return TRUE;
+ if (p->sec == sec && p->ifunc == is_ifunc)
+ {
+ p->count -= 1;
+ if (p->count == 0)
+ *pp = p->next;
+ return TRUE;
+ }
+ pp = &p->next;
}
- pp = &p->next;
}
info->callbacks->einfo (_("%P: dynreloc miscount for %B, section %A\n"),
if (!NO_OPD_RELOCS
&& !info->relocatable
&& !dec_dynrel_count (rel->r_info, sec, info,
- NULL, h, sym_sec))
+ NULL, h, sym))
goto error_ret;
}
else
/* If we got rid of a DTPMOD/DTPREL reloc pair then
we'll lose one or two dyn relocs. */
if (!dec_dynrel_count (rel->r_info, sec, info,
- NULL, h, sym_sec))
+ NULL, h, sym))
return FALSE;
if (tls_set == (TLS_EXPLICIT | TLS_GD))
{
if (!dec_dynrel_count ((rel + 1)->r_info, sec, info,
- NULL, h, sym_sec))
+ NULL, h, sym))
return FALSE;
}
}
. addi ry,rx,addr@toc@l
when addr is within 2G of the toc pointer. This then means
that the word storing "addr" in the toc is no longer needed. */
-
+
if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
&& toc->output_section->rawsize < (bfd_vma) 1 << 31
&& toc->reloc_count != 0)
goto error_ret;
/* Mark toc entries referenced as used. */
- repeat = 0;
do
- for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
- {
- enum elf_ppc64_reloc_type r_type;
- unsigned long r_symndx;
- asection *sym_sec;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
- bfd_vma val;
- enum {no_check, check_lo, check_ha} insn_check;
-
- r_type = ELF64_R_TYPE (rel->r_info);
- switch (r_type)
- {
- default:
- insn_check = no_check;
- break;
+ {
+ repeat = 0;
+ for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+ {
+ enum elf_ppc64_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ bfd_vma val;
+ enum {no_check, check_lo, check_ha} insn_check;
- case R_PPC64_GOT_TLSLD16_HA:
- case R_PPC64_GOT_TLSGD16_HA:
- case R_PPC64_GOT_TPREL16_HA:
- case R_PPC64_GOT_DTPREL16_HA:
- case R_PPC64_GOT16_HA:
- case R_PPC64_TOC16_HA:
- insn_check = check_ha;
- break;
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ insn_check = no_check;
+ break;
- case R_PPC64_GOT_TLSLD16_LO:
- case R_PPC64_GOT_TLSGD16_LO:
- case R_PPC64_GOT_TPREL16_LO_DS:
- case R_PPC64_GOT_DTPREL16_LO_DS:
- case R_PPC64_GOT16_LO:
- case R_PPC64_GOT16_LO_DS:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_LO_DS:
- insn_check = check_lo;
- break;
- }
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_TOC16_HA:
+ insn_check = check_ha;
+ break;
- if (insn_check != no_check)
- {
- bfd_vma off = rel->r_offset & ~3;
- unsigned char buf[4];
- unsigned int insn;
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ insn_check = check_lo;
+ break;
+ }
- if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
- {
- free (used);
- goto error_ret;
- }
- insn = bfd_get_32 (ibfd, buf);
- if (insn_check == check_lo
- ? !ok_lo_toc_insn (insn)
- : ((insn & ((0x3f << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
- {
- char str[12];
-
- ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
- sprintf (str, "%#08x", insn);
- info->callbacks->einfo
- (_("%P: %H: toc optimization is not supported for"
- " %s instruction.\n"),
- ibfd, sec, rel->r_offset & ~3, str);
- }
- }
+ if (insn_check != no_check)
+ {
+ bfd_vma off = rel->r_offset & ~3;
+ unsigned char buf[4];
+ unsigned int insn;
- switch (r_type)
- {
- case R_PPC64_TOC16:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_HI:
- case R_PPC64_TOC16_HA:
- case R_PPC64_TOC16_DS:
- case R_PPC64_TOC16_LO_DS:
- /* In case we're taking addresses of toc entries. */
- case R_PPC64_ADDR64:
- break;
+ if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+ {
+ free (used);
+ goto error_ret;
+ }
+ insn = bfd_get_32 (ibfd, buf);
+ if (insn_check == check_lo
+ ? !ok_lo_toc_insn (insn)
+ : ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+ {
+ char str[12];
- default:
- continue;
- }
+ ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+ sprintf (str, "%#08x", insn);
+ info->callbacks->einfo
+ (_("%P: %H: toc optimization is not supported for"
+ " %s instruction.\n"),
+ ibfd, sec, rel->r_offset & ~3, str);
+ }
+ }
- r_symndx = ELF64_R_SYM (rel->r_info);
- if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
- r_symndx, ibfd))
- {
- free (used);
- goto error_ret;
- }
+ switch (r_type)
+ {
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO_DS:
+ /* In case we're taking addresses of toc entries. */
+ case R_PPC64_ADDR64:
+ break;
- if (sym_sec != toc)
- continue;
+ default:
+ continue;
+ }
- if (h != NULL)
- val = h->root.u.def.value;
- else
- val = sym->st_value;
- val += rel->r_addend;
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ {
+ free (used);
+ goto error_ret;
+ }
- if (val >= toc->size)
- continue;
+ if (sym_sec != toc)
+ continue;
- if ((skip[val >> 3] & can_optimize) != 0)
- {
- bfd_vma off;
- unsigned char opc;
+ if (h != NULL)
+ val = h->root.u.def.value;
+ else
+ val = sym->st_value;
+ val += rel->r_addend;
- switch (r_type)
- {
- case R_PPC64_TOC16_HA:
- break;
+ if (val >= toc->size)
+ continue;
- case R_PPC64_TOC16_LO_DS:
- off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
- if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
- {
- free (used);
- goto error_ret;
- }
- if ((opc & (0x3f << 2)) == (58u << 2))
+ if ((skip[val >> 3] & can_optimize) != 0)
+ {
+ bfd_vma off;
+ unsigned char opc;
+
+ switch (r_type)
+ {
+ case R_PPC64_TOC16_HA:
break;
- /* Fall thru */
- default:
- /* Wrong sort of reloc, or not a ld. We may
- as well clear ref_from_discarded too. */
- skip[val >> 3] = 0;
- }
- }
+ case R_PPC64_TOC16_LO_DS:
+ off = rel->r_offset;
+ off += (bfd_big_endian (ibfd) ? -2 : 3);
+ if (!bfd_get_section_contents (ibfd, sec, &opc,
+ off, 1))
+ {
+ free (used);
+ goto error_ret;
+ }
+ if ((opc & (0x3f << 2)) == (58u << 2))
+ break;
+ /* Fall thru */
- /* For the toc section, we only mark as used if
- this entry itself isn't unused. */
- if (sec == toc
- && !used[val >> 3]
- && (used[rel->r_offset >> 3]
- || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
- /* Do all the relocs again, to catch reference
- chains. */
- repeat = 1;
-
- used[val >> 3] = 1;
- }
+ default:
+ /* Wrong sort of reloc, or not a ld. We may
+ as well clear ref_from_discarded too. */
+ skip[val >> 3] = 0;
+ }
+ }
+
+ if (sec != toc)
+ used[val >> 3] = 1;
+ /* For the toc section, we only mark as used if this
+ entry itself isn't unused. */
+ else if ((used[rel->r_offset >> 3]
+ || !(skip[rel->r_offset >> 3] & ref_from_discarded))
+ && !used[val >> 3])
+ {
+ /* Do all the relocs again, to catch reference
+ chains. */
+ repeat = 1;
+ used[val >> 3] = 1;
+ }
+ }
+ }
while (repeat);
if (elf_section_data (sec)->relocs != relstart)
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
info->callbacks->einfo
- (_("%P: %H: %s relocation references "
+ (_("%P: %H: %s references "
"optimized away TOC entry\n"),
ibfd, sec, rel->r_offset,
ppc64_elf_howto_table[r_type]->name);
got->size += entsize;
dyn = htab->elf.dynamic_sections_created;
- if ((info->shared
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
- && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ if (h->type == STT_GNU_IFUNC)
{
- asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
- relgot->size += rentsize;
+ htab->reliplt->size += rentsize;
+ htab->got_reli_size += rentsize;
}
- else if (h->type == STT_GNU_IFUNC)
+ else if ((info->shared
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
{
- asection *relgot = htab->reliplt;
+ asection *relgot = ppc64_elf_tdata (gent->owner)->relgot;
relgot->size += rentsize;
- htab->got_reli_size += rentsize;
}
}
for (p = eh->dyn_relocs; p != NULL; p = p->next)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
- if (!htab->elf.dynamic_sections_created)
+ if (eh->elf.type == STT_GNU_IFUNC)
sreloc = htab->reliplt;
sreloc->size += p->count * sizeof (Elf64_External_Rela);
}
/* 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;
unsigned char *lgot_masks;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
- asection *srel;
if (!is_ppc64_elf (ibfd))
continue;
for (s = ibfd->sections; s != NULL; s = s->next)
{
- struct elf_dyn_relocs *p;
+ struct ppc_dyn_relocs *p;
for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
{
}
else if (p->count != 0)
{
- srel = elf_section_data (p->sec)->sreloc;
- if (!htab->elf.dynamic_sections_created)
+ asection *srel = elf_section_data (p->sec)->sreloc;
+ if (p->ifunc)
srel = htab->reliplt;
srel->size += p->count * sizeof (Elf64_External_Rela);
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
end_local_plt = local_plt + locsymcount;
lgot_masks = (unsigned char *) end_local_plt;
s = ppc64_elf_tdata (ibfd)->got;
- srel = ppc64_elf_tdata (ibfd)->relgot;
for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
{
struct got_entry **pent, *ent;
}
else
{
- unsigned int num = 1;
+ unsigned int ent_size = 8;
+ unsigned int rel_size = sizeof (Elf64_External_Rela);
+
ent->got.offset = s->size;
if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
- num = 2;
- s->size += num * 8;
- if (info->shared)
- srel->size += num * sizeof (Elf64_External_Rela);
- else if ((*lgot_masks & PLT_IFUNC) != 0)
{
- htab->reliplt->size
- += num * sizeof (Elf64_External_Rela);
- htab->got_reli_size
- += num * sizeof (Elf64_External_Rela);
+ ent_size *= 2;
+ rel_size *= 2;
+ }
+ s->size += ent_size;
+ if ((*lgot_masks & PLT_IFUNC) != 0)
+ {
+ htab->reliplt->size += rel_size;
+ htab->got_reli_size += rel_size;
+ }
+ else if (info->shared)
+ {
+ asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+ srel->size += rel_size;
}
pent = &ent->next;
}
bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
bfd_vma to, from;
- if (pltindex > 32767)
- glinkoff += (pltindex - 32767) * 4;
+ if (pltindex > 32768)
+ glinkoff += (pltindex - 32768) * 4;
to = (glinkoff
+ htab->glink->output_offset
+ htab->glink->output_section->vma);
{
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;
+ bfd_put_32 (obfd, B_DOT | (cmp_branch_off & 0x3fffffc), p), p += 4;
}
else
bfd_put_32 (obfd, BCTR, p), p += 4;
if (strcmp (opd->name, ".opd") != 0
|| opd->reloc_count != 0)
{
- info->callbacks->einfo (_("%P: cannot find opd entry toc for %s\n"),
+ 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;
if (off + (1 << 25) >= (bfd_vma) (1 << 26))
{
- info->callbacks->einfo (_("%P: long branch stub `%s' offset overflow\n"),
- stub_entry->root.string);
+ info->callbacks->einfo
+ (_("%P: long branch stub `%s' offset overflow\n"),
+ stub_entry->root.string);
htab->stub_error = TRUE;
return FALSE;
}
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
info->callbacks->einfo
- (_("%P: linkage table error against `%s'\n"),
+ (_("%P: linkage table error against `%T'\n"),
stub_entry->root.string);
bfd_set_error (bfd_error_bad_value);
htab->stub_error = TRUE;
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
info->callbacks->einfo
- (_("%P: linkage table error against `%s'\n"),
+ (_("%P: linkage table error against `%T'\n"),
stub_entry->h != NULL
? stub_entry->h->elf.root.root.string
: "<local sym>");
htab->add_stub_section = add_stub_section;
htab->layout_sections_again = layout_sections_again;
- if (htab->brlt == NULL)
- return 0;
-
/* Find the top input section id. */
for (input_bfd = info->input_bfds, top_id = 3;
input_bfd != NULL;
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;
/* 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;
unsigned char *lgot_masks;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
- asection *s, *srel;
+ asection *s;
if (!is_ppc64_elf (ibfd))
continue;
end_local_plt = local_plt + locsymcount;
lgot_masks = (unsigned char *) end_local_plt;
s = ppc64_elf_tdata (ibfd)->got;
- srel = ppc64_elf_tdata (ibfd)->relgot;
for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
{
struct got_entry *ent;
for (ent = *lgot_ents; ent != NULL; ent = ent->next)
{
- unsigned int num = 1;
+ unsigned int ent_size = 8;
+ unsigned int rel_size = sizeof (Elf64_External_Rela);
+
ent->got.offset = s->size;
if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
- num = 2;
- s->size += num * 8;
- if (info->shared)
- srel->size += num * sizeof (Elf64_External_Rela);
- else if ((*lgot_masks & PLT_IFUNC) != 0)
{
- htab->reliplt->size
- += num * sizeof (Elf64_External_Rela);
- htab->got_reli_size
- += num * sizeof (Elf64_External_Rela);
+ ent_size *= 2;
+ rel_size *= 2;
+ }
+ s->size += ent_size;
+ if ((*lgot_masks & PLT_IFUNC) != 0)
+ {
+ htab->reliplt->size += rel_size;
+ htab->got_reli_size += rel_size;
+ }
+ else if (info->shared)
+ {
+ asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+ srel->size += rel_size;
}
}
}
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;
}
{
if (isec->size == 0
&& isec->output_section->size == 0
+ && !(isec->output_section->flags & SEC_KEEP)
&& !bfd_section_removed_from_list (info->output_bfd,
isec->output_section)
&& elf_section_data (isec->output_section)->dynindx == 0)
htab->plt_static_chain = plt_static_chain;
htab->plt_stub_align = plt_stub_align;
+ if (plt_thread_safe == -1 && !info->executable)
+ plt_thread_safe = 1;
if (plt_thread_safe == -1)
{
- const char *const thread_starter[] =
+ static const char *const thread_starter[] =
{
"pthread_create",
/* libstdc++ */
"GOMP_parallel_loop_dynamic_start",
"GOMP_parallel_loop_guided_start",
"GOMP_parallel_loop_runtime_start",
- "GOMP_parallel_sections_start",
+ "GOMP_parallel_sections_start",
};
unsigned i;
}
}
htab->plt_thread_safe = plt_thread_safe;
+ htab->dot_toc_dot = ((struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, ".TOC.",
+ FALSE, FALSE, TRUE));
stubs_always_before_branch = group_size < 0;
if (group_size < 0)
stub_group_size = -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;
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;
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;
}
&& 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;
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;
}
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;
*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. */
for (; rel < relend; rel++)
{
enum elf_ppc64_reloc_type r_type;
- bfd_vma addend, orig_addend;
+ bfd_vma addend;
bfd_reloc_status_type r;
Elf_Internal_Sym *sym;
asection *sec;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
bfd_boolean warned;
+ enum { DEST_NORMAL, DEST_OPD, DEST_STUB } reloc_dest;
unsigned int insn;
unsigned int mask;
struct ppc_stub_hash_entry *stub_entry;
bfd_vma max_br_offset;
bfd_vma from;
+ const Elf_Internal_Rela orig_rel = *rel;
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
sym_name = NULL;
unresolved_reloc = FALSE;
warned = FALSE;
- orig_addend = rel->r_addend;
if (r_symndx < symtab_hdr->sh_info)
{
unresolved_reloc, warned);
sym_name = h_elf->root.root.string;
sym_type = h_elf->type;
+ if (sec != NULL
+ && sec->owner == output_bfd
+ && strcmp (sec->name, ".opd") == 0)
+ {
+ /* This is a symbol defined in a linker script. All
+ such are defined in output sections, even those
+ defined by simple assignment from a symbol defined in
+ an input section. Transfer the symbol to an
+ appropriate input .opd section, so that a branch to
+ this symbol will be mapped to the location specified
+ by the opd entry. */
+ struct bfd_link_order *lo;
+ for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
+ if (lo->type == bfd_indirect_link_order)
+ {
+ asection *isec = lo->u.indirect.section;
+ if (h_elf->root.u.def.value >= isec->output_offset
+ && h_elf->root.u.def.value < (isec->output_offset
+ + isec->size))
+ {
+ h_elf->root.u.def.value -= isec->output_offset;
+ h_elf->root.u.def.section = isec;
+ sec = isec;
+ break;
+ }
+ }
+ }
+ if (h_elf == &htab->dot_toc_dot->elf)
+ {
+ relocation = (TOCstart
+ + htab->stub_group[input_section->id].toc_off);
+ sec = bfd_abs_section_ptr;
+ unresolved_reloc = FALSE;
+ }
}
h = (struct ppc_link_hash_entry *) h_elf;
else
info->callbacks->einfo
(!IS_PPC64_TLS_RELOC (r_type)
- ? _("%P: %H: %s used with TLS symbol %s\n")
- : _("%P: %H: %s used with non-TLS symbol %s\n"),
+ ? _("%P: %H: %s used with TLS symbol `%T'\n")
+ : _("%P: %H: %s used with non-TLS symbol `%T'\n"),
input_bfd, input_section, rel->r_offset,
ppc64_elf_howto_table[r_type]->name,
sym_name);
insn = 0;
max_br_offset = 1 << 25;
addend = rel->r_addend;
+ reloc_dest = DEST_NORMAL;
switch (r_type)
{
default:
&& h->oh != NULL
&& h->oh->is_func_descriptor)
fdh = ppc_follow_link (h->oh);
- stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
+ stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
+ htab);
if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save
}
else
{
- if (strcmp (input_section->output_section->name,
- ".init") == 0
- || strcmp (input_section->output_section->name,
- ".fini") == 0)
- info->callbacks->einfo
- (_("%P: %H: automatic multiple TOCs "
- "not supported using your crt files; "
- "recompile with -mminimal-toc or upgrade gcc\n"),
- input_bfd, input_section, rel->r_offset);
- else
- info->callbacks->einfo
- (_("%P: %H: sibling call optimization to `%s' "
- "does not allow automatic multiple TOCs; "
- "recompile with -mminimal-toc or "
- "-fno-optimize-sibling-calls, "
- "or make `%s' extern\n"),
- input_bfd, input_section, rel->r_offset,
- sym_name,
- sym_name);
+ info->callbacks->einfo
+ (_("%P: %H: call to `%T' lacks nop, can't restore toc; "
+ "recompile with -fPIC"),
+ input_bfd, input_section, rel->r_offset, sym_name);
+
bfd_set_error (bfd_error_bad_value);
ret = FALSE;
}
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;
addend = 0;
+ reloc_dest = DEST_OPD;
}
}
+ stub_entry->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma);
addend = 0;
+ reloc_dest = DEST_STUB;
if ((stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
{
default:
info->callbacks->einfo
- (_("%P: %B: unknown relocation type %d for symbol %s\n"),
+ (_("%P: %B: unknown relocation type %d for `%T'\n"),
input_bfd, (int) r_type, sym_name);
bfd_set_error (bfd_error_bad_value);
;
else
{
+ BFD_ASSERT (h->elf.dynindx != -1);
indx = h->elf.dynindx;
unresolved_reloc = FALSE;
}
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == orig_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
ifunc = (h != NULL
? h->elf.type == STT_GNU_IFUNC
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
- if ((info->shared || indx != 0)
- && (h == NULL
- || (tls_type == (TLS_TLS | TLS_LD)
- && !h->elf.def_dynamic)
- || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
- || h->elf.root.type != bfd_link_hash_undefweak))
- relgot = ppc64_elf_tdata (ent->owner)->relgot;
- else if (ifunc)
+ if (ifunc)
relgot = htab->reliplt;
+ else if ((info->shared || indx != 0)
+ && (h == NULL
+ || (tls_type == (TLS_TLS | TLS_LD)
+ && !h->elf.def_dynamic)
+ || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
+ || h->elf.root.type != bfd_link_hash_undefweak))
+ relgot = ppc64_elf_tdata (ent->owner)->relgot;
if (relgot != NULL)
{
outrel.r_offset = (got->output_section->vma
{
struct plt_entry *ent;
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->addend == orig_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->plt.offset != (bfd_vma) -1)
{
relocation = (htab->plt->output_section->vma
else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
&& !is_opd
&& r_type != R_PPC64_TOC)
- outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+ {
+ BFD_ASSERT (h->elf.dynindx != -1);
+ outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+ }
else
{
/* This symbol is local, or marked to become local,
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
info->callbacks->einfo
- (_("%P: %H: relocation %s for indirect "
- "function %s unsupported\n"),
+ (_("%P: %H: %s for indirect "
+ "function `%T' unsupported\n"),
input_bfd, input_section, rel->r_offset,
ppc64_elf_howto_table[r_type]->name,
sym_name);
}
sreloc = elf_section_data (input_section)->sreloc;
- if (!htab->elf.dynamic_sections_created)
+ if (h != NULL
+ ? h->elf.type == STT_GNU_IFUNC
+ : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
sreloc = htab->reliplt;
if (sreloc == NULL)
abort ();
/* These ones haven't been implemented yet. */
info->callbacks->einfo
- (_("%P: %B: relocation %s is not supported for symbol %s\n"),
+ (_("%P: %B: %s is not supported for `%T'\n"),
input_bfd,
ppc64_elf_howto_table[r_type]->name, sym_name);
rel->r_offset) != (bfd_vma) -1)
{
info->callbacks->einfo
- (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
+ (_("%P: %H: unresolvable %s against `%T'\n"),
input_bfd, input_section, rel->r_offset,
ppc64_elf_howto_table[(int) r_type]->name,
h->elf.root.root.string);
if (r != bfd_reloc_ok)
{
- if (sym_name == NULL)
- sym_name = "(null)";
+ char *more_info = NULL;
+ const char *reloc_name = ppc64_elf_howto_table[r_type]->name;
+
+ if (reloc_dest != DEST_NORMAL)
+ {
+ more_info = bfd_malloc (strlen (reloc_name) + 8);
+ if (more_info != NULL)
+ {
+ strcpy (more_info, reloc_name);
+ strcat (more_info, (reloc_dest == DEST_OPD
+ ? " (OPD)" : " (stub)"));
+ reloc_name = more_info;
+ }
+ }
+
if (r == bfd_reloc_overflow)
{
if (warned)
}
if (!((*info->callbacks->reloc_overflow)
- (info, (h ? &h->elf.root : NULL), sym_name,
- ppc64_elf_howto_table[r_type]->name,
- orig_addend, input_bfd, input_section, rel->r_offset)))
+ (info, &h->elf.root, sym_name,
+ reloc_name, orig_rel.r_addend,
+ input_bfd, input_section, rel->r_offset)))
return FALSE;
}
else
{
info->callbacks->einfo
- (_("%P: %H: %s reloc against `%s': error %d\n"),
+ (_("%P: %H: %s against `%T': error %d\n"),
input_bfd, input_section, rel->r_offset,
- ppc64_elf_howto_table[r_type]->name,
- sym_name,
- (int) r);
+ reloc_name, sym_name, (int) r);
ret = FALSE;
}
+ if (more_info != NULL)
+ free (more_info);
}
}
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;
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;
}
dynamic linker, before writing them out. */
static enum elf_reloc_type_class
-ppc64_elf_reloc_type_class (const Elf_Internal_Rela *rela)
+ppc64_elf_reloc_type_class (const struct bfd_link_info *info,
+ const asection *rel_sec,
+ const Elf_Internal_Rela *rela)
{
enum elf_ppc64_reloc_type r_type;
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+
+ if (rel_sec == htab->reliplt)
+ return reloc_class_ifunc;
r_type = ELF64_R_TYPE (rela->r_info);
switch (r_type)
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)
{