#define elf_backend_notice_as_needed ppc64_elf_notice_as_needed
#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup
#define elf_backend_check_relocs ppc64_elf_check_relocs
+#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible
#define elf_backend_gc_keep ppc64_elf_gc_keep
#define elf_backend_gc_mark_dynamic_ref ppc64_elf_gc_mark_dynamic_ref
#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook
-#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
return 0;
}
- symcount = static_count;
- if (!relocatable)
- symcount += dyn_count;
- if (symcount == 0)
- return 0;
-
- syms = bfd_malloc ((symcount + 1) * sizeof (*syms));
- if (syms == NULL)
- return -1;
-
- if (!relocatable && static_count != 0 && dyn_count != 0)
+ syms = NULL;
+ codesecsym = 0;
+ codesecsymend = 0;
+ secsymend = 0;
+ opdsymend = 0;
+ symcount = 0;
+ if (opd != NULL)
{
- /* Use both symbol tables. */
- memcpy (syms, static_syms, static_count * sizeof (*syms));
- memcpy (syms + static_count, dyn_syms, (dyn_count + 1) * sizeof (*syms));
- }
- else if (!relocatable && static_count == 0)
- memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms));
- else
- memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
-
- synthetic_relocatable = relocatable;
- synthetic_opd = opd;
- qsort (syms, symcount, sizeof (*syms), compare_symbols);
-
- if (!relocatable && symcount > 1)
- {
- long j;
- /* Trim duplicate syms, since we may have merged the normal and
- dynamic symbols. Actually, we only care about syms that have
- different values, so trim any with the same value. */
- for (i = 1, j = 1; i < symcount; ++i)
- if (syms[i - 1]->value + syms[i - 1]->section->vma
- != syms[i]->value + syms[i]->section->vma)
- syms[j++] = syms[i];
- symcount = j;
- }
-
- i = 0;
- /* Note that here and in compare_symbols we can't compare opd and
- sym->section directly. With separate debug info files, the
- symbols will be extracted from the debug file while abfd passed
- to this function is the real binary. */
- if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
- ++i;
- codesecsym = i;
-
- for (; i < symcount; ++i)
- if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
- != (SEC_CODE | SEC_ALLOC))
- || (syms[i]->flags & BSF_SECTION_SYM) == 0)
- break;
- codesecsymend = i;
+ symcount = static_count;
+ if (!relocatable)
+ symcount += dyn_count;
+ if (symcount == 0)
+ return 0;
- for (; i < symcount; ++i)
- if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
- break;
- secsymend = i;
+ syms = bfd_malloc ((symcount + 1) * sizeof (*syms));
+ if (syms == NULL)
+ return -1;
- if (opd != NULL)
- for (; i < symcount; ++i)
- if (strcmp (syms[i]->section->name, ".opd") != 0)
- break;
- opdsymend = i;
+ if (!relocatable && static_count != 0 && dyn_count != 0)
+ {
+ /* Use both symbol tables. */
+ memcpy (syms, static_syms, static_count * sizeof (*syms));
+ memcpy (syms + static_count, dyn_syms,
+ (dyn_count + 1) * sizeof (*syms));
+ }
+ else if (!relocatable && static_count == 0)
+ memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms));
+ else
+ memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
+
+ synthetic_relocatable = relocatable;
+ synthetic_opd = opd;
+ qsort (syms, symcount, sizeof (*syms), compare_symbols);
+
+ if (!relocatable && symcount > 1)
+ {
+ long j;
+ /* Trim duplicate syms, since we may have merged the normal and
+ dynamic symbols. Actually, we only care about syms that have
+ different values, so trim any with the same value. */
+ for (i = 1, j = 1; i < symcount; ++i)
+ if (syms[i - 1]->value + syms[i - 1]->section->vma
+ != syms[i]->value + syms[i]->section->vma)
+ syms[j++] = syms[i];
+ symcount = j;
+ }
+
+ i = 0;
+ /* Note that here and in compare_symbols we can't compare opd and
+ sym->section directly. With separate debug info files, the
+ symbols will be extracted from the debug file while abfd passed
+ to this function is the real binary. */
+ if (opd != NULL && strcmp (syms[i]->section->name, ".opd") == 0)
+ ++i;
+ codesecsym = i;
+
+ for (; i < symcount; ++i)
+ if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC
+ | SEC_THREAD_LOCAL))
+ != (SEC_CODE | SEC_ALLOC))
+ || (syms[i]->flags & BSF_SECTION_SYM) == 0)
+ break;
+ codesecsymend = i;
- for (; i < symcount; ++i)
- if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
- != (SEC_CODE | SEC_ALLOC))
- break;
- symcount = i;
+ for (; i < symcount; ++i)
+ if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
+ break;
+ secsymend = i;
+ for (; i < symcount; ++i)
+ if (strcmp (syms[i]->section->name, ".opd") != 0)
+ break;
+ opdsymend = i;
+
+ for (; i < symcount; ++i)
+ if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
+ != (SEC_CODE | SEC_ALLOC))
+ break;
+ symcount = i;
+ }
count = 0;
if (relocatable)
}
}
-/* Whether an undefined weak symbol should resolve to its link-time
- value, even in PIC or PIE objects. */
-#define UNDEFWEAK_NO_DYNAMIC_RELOC(INFO, H) \
- ((H)->root.type == bfd_link_hash_undefweak \
- && (ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT \
- || (INFO)->dynamic_undefined_weak == 0))
-
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
copying dynamic variables from a shared lib into an app's dynbss
section, and instead use a dynamic relocation to point into the
if (opd != NULL && opd->size != 0)
{
+ BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal);
+ ppc64_elf_section_data (opd)->sec_type = sec_opd;
+
if (abiversion (ibfd) == 0)
set_abiversion (ibfd, 1);
else if (abiversion (ibfd) >= 2)
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
+ }
- if ((ibfd->flags & DYNAMIC) == 0
- && (opd->flags & SEC_RELOC) != 0
- && opd->reloc_count != 0
- && !bfd_is_abs_section (opd->output_section))
- {
- /* Garbage collection needs some extra help with .opd sections.
- We don't want to necessarily keep everything referenced by
- relocs in .opd, as that would keep all functions. Instead,
- if we reference an .opd symbol (a function descriptor), we
- want to keep the function code symbol's section. This is
- easy for global symbols, but for local syms we need to keep
- information about the associated function section. */
- bfd_size_type amt;
- asection **opd_sym_map;
-
- amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map);
- opd_sym_map = bfd_zalloc (ibfd, amt);
- if (opd_sym_map == NULL)
- return FALSE;
- ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map;
- BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal);
- ppc64_elf_section_data (opd)->sec_type = sec_opd;
- }
+ if (is_ppc64_elf (info->output_bfd))
+ {
+ /* For input files without an explicit abiversion in e_flags
+ we should have flagged any with symbol st_other bits set
+ as ELFv1 and above flagged those with .opd as ELFv2.
+ Set the output abiversion if not yet set, and for any input
+ still ambiguous, take its abiversion from the output.
+ Differences in ABI are reported later. */
+ if (abiversion (info->output_bfd) == 0)
+ set_abiversion (info->output_bfd, abiversion (ibfd));
+ else if (abiversion (ibfd) == 0)
+ set_abiversion (ibfd, abiversion (info->output_bfd));
}
- if (!is_ppc64_elf (info->output_bfd))
- return TRUE;
htab = ppc_hash_table (info);
if (htab == NULL)
- return FALSE;
+ return TRUE;
- /* For input files without an explicit abiversion in e_flags
- we should have flagged any with symbol st_other bits set
- as ELFv1 and above flagged those with .opd as ELFv2.
- Set the output abiversion if not yet set, and for any input
- still ambiguous, take its abiversion from the output.
- Differences in ABI are reported later. */
- if (abiversion (info->output_bfd) == 0)
- set_abiversion (info->output_bfd, abiversion (ibfd));
- else if (abiversion (ibfd) == 0)
- set_abiversion (ibfd, abiversion (info->output_bfd));
+ if (opd != NULL && opd->size != 0
+ && (ibfd->flags & DYNAMIC) == 0
+ && (opd->flags & SEC_RELOC) != 0
+ && opd->reloc_count != 0
+ && !bfd_is_abs_section (opd->output_section)
+ && info->gc_sections)
+ {
+ /* Garbage collection needs some extra help with .opd sections.
+ We don't want to necessarily keep everything referenced by
+ relocs in .opd, as that would keep all functions. Instead,
+ if we reference an .opd symbol (a function descriptor), we
+ want to keep the function code symbol's section. This is
+ easy for global symbols, but for local syms we need to keep
+ information about the associated function section. */
+ bfd_size_type amt;
+ asection **opd_sym_map;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Rela *relocs, *rel_end, *rel;
+
+ amt = OPD_NDX (opd->size) * sizeof (*opd_sym_map);
+ opd_sym_map = bfd_zalloc (ibfd, amt);
+ if (opd_sym_map == NULL)
+ return FALSE;
+ ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map;
+ relocs = _bfd_elf_link_read_relocs (ibfd, opd, NULL, NULL,
+ info->keep_memory);
+ if (relocs == NULL)
+ return FALSE;
+ symtab_hdr = &elf_symtab_hdr (ibfd);
+ rel_end = relocs + opd->reloc_count - 1;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
+ unsigned long r_symndx = ELF64_R_SYM (rel->r_info);
+
+ if (r_type == R_PPC64_ADDR64
+ && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC
+ && r_symndx < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isym;
+ asection *s;
+
+ isym = bfd_sym_from_r_symndx (&htab->sym_cache, ibfd, r_symndx);
+ if (isym == NULL)
+ {
+ if (elf_section_data (opd)->relocs != relocs)
+ free (relocs);
+ return FALSE;
+ }
+
+ s = bfd_section_from_elf_index (ibfd, isym->st_shndx);
+ if (s != NULL && s != opd)
+ opd_sym_map[OPD_NDX (rel->r_offset)] = s;
+ }
+ }
+ if (elf_section_data (opd)->relocs != relocs)
+ free (relocs);
+ }
p = &htab->dot_syms;
while ((eh = *p) != NULL)
const Elf_Internal_Rela *rel;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
- asection **opd_sym_map;
struct elf_link_hash_entry *tga, *dottga;
+ bfd_boolean is_opd;
if (bfd_link_relocatable (info))
return TRUE;
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
- opd_sym_map = NULL;
- if (ppc64_elf_section_data (sec) != NULL
- && ppc64_elf_section_data (sec)->sec_type == sec_opd)
- opd_sym_map = ppc64_elf_section_data (sec)->u.opd.func_sec;
-
+ is_opd = ppc64_elf_section_data (sec)->sec_type == sec_opd;
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
{
goto dodyn;
case R_PPC64_ADDR64:
- if (opd_sym_map != NULL
+ if (is_opd
&& rel + 1 < rel_end
&& ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC)
{
if (h != NULL)
((struct ppc_link_hash_entry *) h)->is_func = 1;
- else
- {
- asection *s;
- Elf_Internal_Sym *isym;
-
- isym = bfd_sym_from_r_symndx (&htab->sym_cache,
- abfd, r_symndx);
- if (isym == NULL)
- return FALSE;
-
- s = bfd_section_from_elf_index (abfd, isym->st_shndx);
- if (s != NULL && s != sec)
- opd_sym_map[OPD_NDX (rel->r_offset)] = s;
- }
}
/* Fall through. */
h->non_got_ref = 1;
/* Don't propagate .opd relocs. */
- if (NO_OPD_RELOCS && opd_sym_map != NULL)
+ if (NO_OPD_RELOCS && is_opd)
break;
/* If we are creating a shared library, and this is a reloc
return rsec;
}
-/* Update the .got, .plt. and dynamic reloc reference counts for the
- section being removed. */
-
-static bfd_boolean
-ppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
- asection *sec, const Elf_Internal_Rela *relocs)
-{
- struct ppc_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr;
- struct elf_link_hash_entry **sym_hashes;
- struct got_entry **local_got_ents;
- const Elf_Internal_Rela *rel, *relend;
-
- if (bfd_link_relocatable (info))
- return TRUE;
-
- if ((sec->flags & SEC_ALLOC) == 0)
- return TRUE;
-
- elf_section_data (sec)->local_dynrel = NULL;
-
- htab = ppc_hash_table (info);
- if (htab == NULL)
- return FALSE;
-
- symtab_hdr = &elf_symtab_hdr (abfd);
- sym_hashes = elf_sym_hashes (abfd);
- local_got_ents = elf_local_got_ents (abfd);
-
- relend = relocs + sec->reloc_count;
- for (rel = relocs; rel < relend; rel++)
- {
- unsigned long r_symndx;
- enum elf_ppc64_reloc_type r_type;
- struct elf_link_hash_entry *h = NULL;
- struct plt_entry **plt_list = NULL;
- unsigned char tls_type = 0;
-
- r_symndx = ELF64_R_SYM (rel->r_info);
- r_type = ELF64_R_TYPE (rel->r_info);
- if (r_symndx >= symtab_hdr->sh_info)
- {
- struct ppc_link_hash_entry *eh;
- struct elf_dyn_relocs **pp;
- struct elf_dyn_relocs *p;
-
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- h = elf_follow_link (h);
- eh = (struct ppc_link_hash_entry *) h;
-
- for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
- if (p->sec == sec)
- {
- /* Everything must go for SEC. */
- *pp = p->next;
- break;
- }
- }
-
- switch (r_type)
- {
- case R_PPC64_GOT_TLSLD16:
- case R_PPC64_GOT_TLSLD16_LO:
- case R_PPC64_GOT_TLSLD16_HI:
- case R_PPC64_GOT_TLSLD16_HA:
- tls_type = TLS_TLS | TLS_LD;
- goto dogot;
-
- case R_PPC64_GOT_TLSGD16:
- case R_PPC64_GOT_TLSGD16_LO:
- case R_PPC64_GOT_TLSGD16_HI:
- case R_PPC64_GOT_TLSGD16_HA:
- tls_type = TLS_TLS | TLS_GD;
- goto dogot;
-
- case R_PPC64_GOT_TPREL16_DS:
- case R_PPC64_GOT_TPREL16_LO_DS:
- case R_PPC64_GOT_TPREL16_HI:
- case R_PPC64_GOT_TPREL16_HA:
- tls_type = TLS_TLS | TLS_TPREL;
- goto dogot;
-
- case R_PPC64_GOT_DTPREL16_DS:
- case R_PPC64_GOT_DTPREL16_LO_DS:
- case R_PPC64_GOT_DTPREL16_HI:
- case R_PPC64_GOT_DTPREL16_HA:
- tls_type = TLS_TLS | TLS_DTPREL;
- goto dogot;
-
- case R_PPC64_GOT16:
- case R_PPC64_GOT16_DS:
- case R_PPC64_GOT16_HA:
- case R_PPC64_GOT16_HI:
- case R_PPC64_GOT16_LO:
- case R_PPC64_GOT16_LO_DS:
- dogot:
- {
- struct got_entry *ent;
-
- if (h != NULL)
- ent = h->got.glist;
- else
- ent = local_got_ents[r_symndx];
-
- for (; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend
- && ent->owner == abfd
- && ent->tls_type == tls_type)
- break;
- if (ent == NULL)
- abort ();
- if (ent->got.refcount > 0)
- ent->got.refcount -= 1;
- }
- if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
- plt_list = &h->plt.plist;
- break;
-
- case R_PPC64_PLT16_HA:
- case R_PPC64_PLT16_HI:
- case R_PPC64_PLT16_LO:
- case R_PPC64_PLT32:
- case R_PPC64_PLT64:
- case R_PPC64_REL14:
- case R_PPC64_REL14_BRNTAKEN:
- case R_PPC64_REL14_BRTAKEN:
- case R_PPC64_REL24:
- if (h != NULL)
- plt_list = &h->plt.plist;
- else if (local_got_ents != NULL)
- {
- struct plt_entry **local_plt = (struct plt_entry **)
- (local_got_ents + symtab_hdr->sh_info);
- unsigned char *local_got_tls_masks = (unsigned char *)
- (local_plt + symtab_hdr->sh_info);
- if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
- plt_list = local_plt + r_symndx;
- }
- break;
-
- case R_PPC64_ADDR64:
- case R_PPC64_ADDR16:
- case R_PPC64_ADDR16_DS:
- case R_PPC64_ADDR16_HA:
- case R_PPC64_ADDR16_HI:
- case R_PPC64_ADDR16_HIGH:
- case R_PPC64_ADDR16_HIGHA:
- case R_PPC64_ADDR16_HIGHER:
- case R_PPC64_ADDR16_HIGHERA:
- case R_PPC64_ADDR16_HIGHEST:
- case R_PPC64_ADDR16_HIGHESTA:
- case R_PPC64_ADDR16_LO:
- case R_PPC64_ADDR16_LO_DS:
- if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
- && rel->r_addend == 0)
- plt_list = &h->plt.plist;
- break;
-
- default:
- break;
- }
- if (plt_list != NULL)
- {
- struct plt_entry *ent;
-
- for (ent = *plt_list; ent != NULL; ent = ent->next)
- if (ent->addend == rel->r_addend)
- break;
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- }
- }
- return TRUE;
-}
-
/* The maximum size of .sfpr. */
#define SFPR_MAX (218*4)
opd->adjust = bfd_zalloc (sec->owner, amt);
if (opd->adjust == NULL)
return FALSE;
- ppc64_elf_section_data (sec)->sec_type = sec_opd;
/* This seems a waste of time as input .opd sections are all
zeros as generated by gcc, but I suppose there's no reason
return size;
}
-/* If this stub would cross fewer 2**plt_stub_align boundaries if we align,
- then return the padding needed to do so. */
+/* Depending on the sign of plt_stub_align:
+ If positive, return the padding to align to a 2**plt_stub_align
+ boundary.
+ If negative, 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->params->plt_stub_align;
+ int stub_align;
unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
bfd_vma stub_off = stub_entry->group->stub_sec->size;
+ if (htab->params->plt_stub_align >= 0)
+ {
+ stub_align = 1 << htab->params->plt_stub_align;
+ if ((stub_off & (stub_align - 1)) != 0)
+ return stub_align - (stub_off & (stub_align - 1));
+ return 0;
+ }
+
+ stub_align = 1 << -htab->params->plt_stub_align;
if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
> ((stub_size - 1) & -stub_align))
return stub_align - (stub_off & (stub_align - 1));
break;
}
- /* Note that the glink_eh_frame check here is not only testing that
- the generated size matched the calculated size but also that
- bfd_elf_discard_info didn't make any changes to the section. */
- if (group != NULL
- || (htab->glink_eh_frame != NULL
- && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size))
+ if (group != NULL)
{
htab->stub_error = TRUE;
info->callbacks->einfo (_("%P: stubs don't match calculated size\n"));
wrel->r_addend = 0;
/* For ld -r, remove relocations in debug sections against
- sections defined in discarded sections. Not done for
+ symbols defined in discarded sections. Not done for
non-debug to preserve relocs in .eh_frame which the
eh_frame editing code expects to be present. */
if (bfd_link_relocatable (info)