#define LIS_R0_0 0x3c000000 /* lis %r0,0 */
#define ORI_R0_R0_0 0x60000000 /* ori %r0,%r0,0 */
-/* Instructions to save and restore floating point regs. */
+/* Instructions used by the save and restore reg functions. */
+#define STD_R0_0R1 0xf8010000 /* std %r0,0(%r1) */
+#define STD_R0_0R12 0xf80c0000 /* std %r0,0(%r12) */
+#define LD_R0_0R1 0xe8010000 /* ld %r0,0(%r1) */
+#define LD_R0_0R12 0xe80c0000 /* ld %r0,0(%r12) */
#define STFD_FR0_0R1 0xd8010000 /* stfd %fr0,0(%r1) */
#define LFD_FR0_0R1 0xc8010000 /* lfd %fr0,0(%r1) */
+#define LI_R12_0 0x39800000 /* li %r12,0 */
+#define STVX_VR0_R12_R0 0x7c0c01ce /* stvx %v0,%r12,%r0 */
+#define LVX_VR0_R12_R0 0x7c0c00ce /* lvx %v0,%r12,%r0 */
+#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */
#define BLR 0x4e800020 /* blr */
/* Since .opd is an array of descriptors and each entry will end up
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
- if (strcmp (symbol->section->name, ".opd") == 0)
+ if (strcmp (symbol->section->name, ".opd") == 0
+ && (symbol->section->owner->flags & DYNAMIC) == 0)
{
bfd_vma dest = opd_entry_value (symbol->section,
symbol->value + reloc_entry->addend,
return TRUE;
}
+static bfd_boolean
+is_ppc64_target (const struct bfd_target *targ)
+{
+ extern const bfd_target bfd_elf64_powerpc_vec;
+ extern const bfd_target bfd_elf64_powerpcle_vec;
+
+ return targ == &bfd_elf64_powerpc_vec || targ == &bfd_elf64_powerpcle_vec;
+}
+
/* Fix bad default arch selected for a 64 bit input bfd when the
default is 32 bit. */
static asection *synthetic_opd;
static bfd_boolean synthetic_relocatable;
-/* Helper routine for ppc64_elf_get_synthetic_symtab. */
+/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
static int
compare_symbols (const void *ap, const void *bp)
const asymbol *a = * (const asymbol **) ap;
const asymbol *b = * (const asymbol **) bp;
- if ((a->flags & BSF_SECTION_SYM) == 0 && (b->flags & BSF_SECTION_SYM))
+ /* Section symbols first. */
+ if ((a->flags & BSF_SECTION_SYM) && !(b->flags & BSF_SECTION_SYM))
return -1;
- if ((a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM) == 0)
+ if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM))
return 1;
+ /* then .opd symbols. */
if (a->section == synthetic_opd && b->section != synthetic_opd)
return -1;
if (a->section != synthetic_opd && b->section == synthetic_opd)
return 1;
+ /* then other code symbols. */
if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
== (SEC_CODE | SEC_ALLOC)
&& (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
return 0;
}
-/* Helper routine for ppc64_elf_get_synthetic_symtab. */
+/* Search SYMS for a symbol of the given VALUE. */
-static int
-compare_relocs (const void *ap, const void *bp)
+static asymbol *
+sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
{
- const arelent *a = * (const arelent **) ap;
- const arelent *b = * (const arelent **) bp;
-
- if (a->address < b->address)
- return -1;
+ long mid;
- if (a->address > b->address)
- return 1;
-
- return 0;
+ if (id == -1)
+ {
+ while (lo < hi)
+ {
+ mid = (lo + hi) >> 1;
+ if (syms[mid]->value + syms[mid]->section->vma < value)
+ lo = mid + 1;
+ else if (syms[mid]->value + syms[mid]->section->vma > value)
+ hi = mid;
+ else
+ return syms[mid];
+ }
+ }
+ else
+ {
+ while (lo < hi)
+ {
+ mid = (lo + hi) >> 1;
+ if (syms[mid]->section->id < id)
+ lo = mid + 1;
+ else if (syms[mid]->section->id > id)
+ hi = mid;
+ else if (syms[mid]->value < value)
+ lo = mid + 1;
+ else if (syms[mid]->value > value)
+ hi = mid;
+ else
+ return syms[mid];
+ }
+ }
+ return NULL;
}
-/* Create synthetic symbols. */
+/* Create synthetic symbols, effectively restoring "dot-symbol" function
+ entry syms. */
static long
-ppc64_elf_get_synthetic_symtab (bfd *abfd, asymbol **relsyms, asymbol **ret)
+ppc64_elf_get_synthetic_symtab (bfd *abfd,
+ long static_count, asymbol **static_syms,
+ long dyn_count, asymbol **dyn_syms,
+ asymbol **ret)
{
asymbol *s;
- bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
- arelent **relocs, **r;
- long count, i;
- size_t size;
+ long i;
+ long count;
char *names;
- asymbol **syms = NULL;
- long symcount = 0, opdsymcount, relcount;
- asection *relopd, *opd;
+ long symcount, codesecsym, codesecsymend, secsymend, opdsymend;
+ asection *opd;
bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
+ asymbol **syms;
*ret = NULL;
if (opd == NULL)
return 0;
- if ((bfd_get_file_flags (abfd) & HAS_SYMS))
- {
- long storage;
- storage = bfd_get_symtab_upper_bound (abfd);
- if (storage < 0)
- return 0;
-
- if (storage)
- {
- syms = bfd_malloc (storage);
- if (syms == NULL)
- return 0;
- }
-
- symcount = bfd_canonicalize_symtab (abfd, syms);
- if (symcount < 0)
- {
- free (syms);
- return 0;
- }
-
- if (symcount == 0)
- {
- free (syms);
- syms = NULL;
- }
- }
-
+ symcount = static_count;
+ if (!relocatable)
+ symcount += dyn_count;
if (symcount == 0)
- {
- long storage;
-
- storage = bfd_get_dynamic_symtab_upper_bound (abfd);
- if (storage < 0)
- return 0;
+ return 0;
- if (storage)
- {
- syms = bfd_malloc (storage);
- if (syms == NULL)
- return 0;
- }
+ syms = bfd_malloc ((symcount + 1) * sizeof (*syms));
+ if (syms == NULL)
+ return 0;
- symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
- if (symcount < 0)
- {
- free (syms);
- return 0;
- }
+ 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_opd = opd;
synthetic_relocatable = relocatable;
- qsort (syms, symcount, sizeof (asymbol *), compare_symbols);
+ qsort (syms, symcount, sizeof (*syms), compare_symbols);
- opdsymcount = symcount;
- for (i = 0; i < symcount; ++i)
+ if (!relocatable && symcount > 1)
{
- if (syms[i]->flags & BSF_SECTION_SYM)
- {
- if (opdsymcount == symcount)
- opdsymcount = i;
- symcount = i;
- break;
- }
+ 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;
+ }
- if (syms[i]->section == opd)
- continue;
+ i = 0;
+ if (syms[i]->section == opd)
+ ++i;
+ codesecsym = i;
- if (opdsymcount == symcount)
- opdsymcount = 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;
- if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
- != (SEC_CODE | SEC_ALLOC))
- {
- symcount = i;
- break;
- }
- }
+ for (; i < symcount; ++i)
+ if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
+ break;
+ secsymend = i;
- if (opdsymcount == 0)
- {
- free (syms);
- return 0;
- }
+ for (; i < symcount; ++i)
+ if (syms[i]->section != opd)
+ break;
+ opdsymend = i;
- slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
- if (! relocatable)
- {
- relopd = bfd_get_section_by_name (abfd, ".rela.opd");
- if (relopd == NULL)
- {
- relopd = bfd_get_section_by_name (abfd, ".rela.dyn");
- if (relopd == NULL)
- {
- free (syms);
- return 0;
- }
- }
- relcount = relopd->size / 24;
+ for (; i < symcount; ++i)
+ if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
+ != (SEC_CODE | SEC_ALLOC))
+ break;
+ symcount = i;
- if (! relcount
- || ! (*slurp_relocs) (abfd, relopd, relsyms, TRUE))
- {
- free (syms);
- return 0;
- }
- }
- else
+ count = 0;
+ if (opdsymend == secsymend)
+ goto done;
+
+ if (relocatable)
{
- relopd = opd;
+ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+ arelent *r;
+ size_t size;
+ long relcount;
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
if (! relcount
- || ! (*slurp_relocs) (abfd, relopd, relsyms, FALSE))
+ || ! (*slurp_relocs) (abfd, opd, static_syms, FALSE))
+ goto done;
+
+ size = 0;
+ for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
{
- free (syms);
- return 0;
- }
- }
+ asymbol *sym;
- relocs = bfd_malloc (relcount * sizeof (arelent **));
- if (relocs == NULL)
- {
- free (syms);
- return 0;
- }
+ while (r < opd->relocation + relcount
+ && r->address < syms[i]->value + opd->vma)
+ ++r;
- for (i = 0; i < relcount; ++i)
- relocs[i] = &relopd->relocation[i];
+ if (r == opd->relocation + relcount)
+ break;
- qsort (relocs, relcount, sizeof (*relocs), compare_relocs);
+ if (r->address != syms[i]->value + opd->vma)
+ continue;
- size = 0;
- count = 0;
- for (i = 0, r = relocs; i < opdsymcount; ++i)
- {
- long lo, hi, mid;
- asymbol *sym;
+ if (r->howto->type != R_PPC64_ADDR64)
+ continue;
- while (r < relocs + relcount
- && (*r)->address < syms[i]->value + opd->vma)
- ++r;
+ sym = *r->sym_ptr_ptr;
+ if (!sym_exists_at (syms, opdsymend, symcount,
+ sym->section->id, sym->value + r->addend))
+ {
+ ++count;
+ size += sizeof (asymbol);
+ size += strlen (syms[i]->name) + 2;
+ }
+ }
- if (r == relocs + relcount)
- continue;
+ s = *ret = bfd_malloc (size);
+ if (s == NULL)
+ {
+ count = 0;
+ goto done;
+ }
- if ((*r)->address != syms[i]->value + opd->vma)
- continue;
+ names = (char *) (s + count);
- if ((*r)->howto->type != (relocatable
- ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
- continue;
+ for (i = secsymend, r = opd->relocation; i < opdsymend; ++i)
+ {
+ asymbol *sym;
- lo = opdsymcount;
- hi = symcount;
- sym = *((*r)->sym_ptr_ptr);
- if (relocatable)
- while (lo < hi)
- {
- mid = (lo + hi) >> 1;
- if (syms[mid]->section->id < sym->section->id)
- lo = mid + 1;
- else if (syms[mid]->section->id > sym->section->id)
- hi = mid;
- else if (syms[mid]->value < sym->value + (*r)->addend)
- lo = mid + 1;
- else if (syms[mid]->value > sym->value + (*r)->addend)
- hi = mid;
- else
- break;
- }
- else
- while (lo < hi)
- {
- mid = (lo + hi) >> 1;
- if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
- lo = mid + 1;
- else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
- hi = mid;
- else
- break;
- }
+ while (r < opd->relocation + relcount
+ && r->address < syms[i]->value + opd->vma)
+ ++r;
- if (lo >= hi)
- {
- ++count;
- size += sizeof (asymbol);
- size += strlen (syms[i]->name) + 1;
- }
- }
+ if (r == opd->relocation + relcount)
+ break;
- s = *ret = bfd_malloc (size);
- if (s == NULL)
- {
- free (syms);
- free (relocs);
- return 0;
- }
+ if (r->address != syms[i]->value + opd->vma)
+ continue;
+
+ if (r->howto->type != R_PPC64_ADDR64)
+ continue;
- names = (char *) (s + count);
+ sym = *r->sym_ptr_ptr;
+ if (!sym_exists_at (syms, opdsymend, symcount,
+ sym->section->id, sym->value + r->addend))
+ {
+ size_t len;
- for (i = 0, r = relocs; i < opdsymcount; ++i)
+ *s = *syms[i];
+ s->section = sym->section;
+ s->value = sym->value + r->addend;
+ s->name = names;
+ *names++ = '.';
+ len = strlen (syms[i]->name);
+ memcpy (names, syms[i]->name, len + 1);
+ names += len + 1;
+ s++;
+ }
+ }
+ }
+ else
{
- long lo, hi, mid;
- asymbol *sym;
+ bfd_byte *contents;
+ size_t size;
- while (r < relocs + relcount
- && (*r)->address < syms[i]->value + opd->vma)
- ++r;
+ if (!bfd_malloc_and_get_section (abfd, opd, &contents))
+ {
+ if (contents)
+ {
+ free_contents_and_exit:
+ free (contents);
+ }
+ goto done;
+ }
- if (r == relocs + relcount)
- continue;
+ size = 0;
+ for (i = secsymend; i < opdsymend; ++i)
+ {
+ bfd_vma ent;
- if ((*r)->address != syms[i]->value + opd->vma)
- continue;
+ ent = bfd_get_64 (abfd, contents + syms[i]->value);
+ if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
+ {
+ ++count;
+ size += sizeof (asymbol);
+ size += strlen (syms[i]->name) + 2;
+ }
+ }
- if ((*r)->howto->type != (relocatable
- ? R_PPC64_ADDR64 : R_PPC64_RELATIVE))
- continue;
+ s = *ret = bfd_malloc (size);
+ if (s == NULL)
+ {
+ count = 0;
+ goto free_contents_and_exit;
+ }
- lo = opdsymcount;
- hi = symcount;
- sym = *((*r)->sym_ptr_ptr);
- if (relocatable)
- while (lo < hi)
- {
- mid = (lo + hi) >> 1;
- if (syms[mid]->section->id < sym->section->id)
- lo = mid + 1;
- else if (syms[mid]->section->id > sym->section->id)
- hi = mid;
- else if (syms[mid]->value < sym->value + (*r)->addend)
- lo = mid + 1;
- else if (syms[mid]->value > sym->value + (*r)->addend)
- hi = mid;
- else
- break;
- }
- else
- while (lo < hi)
- {
- mid = (lo + hi) >> 1;
- if (syms[mid]->value + syms[mid]->section->vma < (*r)->addend)
- lo = mid + 1;
- else if (syms[mid]->value + syms[mid]->section->vma > (*r)->addend)
- hi = mid;
- else
- break;
- }
+ names = (char *) (s + count);
- if (lo >= hi)
+ for (i = secsymend; i < opdsymend; ++i)
{
- size_t len;
+ bfd_vma ent;
- *s = *syms[i];
-
- if (! relocatable)
+ ent = bfd_get_64 (abfd, contents + syms[i]->value);
+ if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
{
- asection *sec;
+ long lo, hi;
+ size_t len;
+ asection *sec = abfd->sections;
+
+ *s = *syms[i];
+ lo = codesecsym;
+ hi = codesecsymend;
+ while (lo < hi)
+ {
+ long mid = (lo + hi) >> 1;
+ if (syms[mid]->section->vma < ent)
+ lo = mid + 1;
+ else if (syms[mid]->section->vma > ent)
+ hi = mid;
+ else
+ {
+ sec = syms[mid]->section;
+ break;
+ }
+ }
- s->section = &bfd_abs_section;
- for (sec = abfd->sections; sec; sec = sec->next)
- if ((sec->flags & (SEC_ALLOC | SEC_CODE))
- == (SEC_ALLOC | SEC_CODE)
- && (*r)->addend >= sec->vma
- && (*r)->addend < sec->vma + sec->size)
- {
- s->section = sec;
+ if (lo >= hi && lo > codesecsym)
+ sec = syms[lo - 1]->section;
+
+ for (; sec != NULL; sec = sec->next)
+ {
+ if (sec->vma > ent)
break;
- }
- s->value = (*r)->addend - sec->vma;
- }
- else
- {
- s->section = sym->section;
- s->value = sym->value + (*r)->addend;
+ if ((sec->flags & SEC_ALLOC) == 0
+ || (sec->flags & SEC_LOAD) == 0)
+ break;
+ if ((sec->flags & SEC_CODE) != 0)
+ s->section = sec;
+ }
+ s->value = ent - s->section->vma;
+ s->name = names;
+ *names++ = '.';
+ len = strlen (syms[i]->name);
+ memcpy (names, syms[i]->name, len + 1);
+ names += len + 1;
+ s++;
}
- s->name = names;
- len = strlen (syms[i]->name);
- memcpy (names, syms[i]->name, len + 1);
- names += len + 1;
- s++;
}
+ free (contents);
}
+ done:
free (syms);
- free (relocs);
return count;
}
-
\f
/* The following functions are specific to the ELF linker, while
functions above are used generally. Those named ppc64_elf_* are
static struct ppc_stub_hash_entry *
ppc_get_stub_entry (const asection *input_section,
const asection *sym_sec,
- struct elf_link_hash_entry *hash,
+ struct ppc_link_hash_entry *h,
const Elf_Internal_Rela *rel,
struct ppc_link_hash_table *htab)
{
struct ppc_stub_hash_entry *stub_entry;
- struct ppc_link_hash_entry *h = (struct ppc_link_hash_entry *) hash;
const asection *id_sec;
/* If this input section is part of a group of sections sharing one
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- extern const bfd_target bfd_elf64_powerpc_vec;
- extern const bfd_target bfd_elf64_powerpcle_vec;
htab = ppc_hash_table (info);
- if (htab->elf.root.creator != &bfd_elf64_powerpc_vec
- && htab->elf.root.creator != &bfd_elf64_powerpcle_vec)
+ if (!is_ppc64_target (htab->elf.root.creator))
return TRUE;
elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
return TRUE;
}
+/* The maximum size of .sfpr. */
+#define SFPR_MAX (218*4)
+
+struct sfpr_def_parms
+{
+ const char name[12];
+ unsigned char lo, hi;
+ bfd_byte * (*write_ent) (bfd *, bfd_byte *, int);
+ bfd_byte * (*write_tail) (bfd *, bfd_byte *, int);
+};
+
+/* Auto-generate _save*, _rest* functions in .sfpr. */
+
+static unsigned int
+sfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm)
+{
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ unsigned int i;
+ size_t len = strlen (parm->name);
+ bfd_boolean writing = FALSE;
+ char sym[16];
+
+ memcpy (sym, parm->name, len);
+ sym[len + 2] = 0;
+
+ for (i = parm->lo; i <= parm->hi; i++)
+ {
+ struct elf_link_hash_entry *h;
+
+ sym[len + 0] = i / 10 + '0';
+ sym[len + 1] = i % 10 + '0';
+ h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
+ if (h != NULL
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ h->root.type = bfd_link_hash_defined;
+ h->root.u.def.section = htab->sfpr;
+ h->root.u.def.value = htab->sfpr->size;
+ h->type = STT_FUNC;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
+ writing = TRUE;
+ if (htab->sfpr->contents == NULL)
+ {
+ htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX);
+ if (htab->sfpr->contents == NULL)
+ return FALSE;
+ }
+ }
+ if (writing)
+ {
+ bfd_byte *p = htab->sfpr->contents + htab->sfpr->size;
+ if (i != parm->hi)
+ p = (*parm->write_ent) (htab->elf.dynobj, p, i);
+ else
+ p = (*parm->write_tail) (htab->elf.dynobj, p, i);
+ htab->sfpr->size = p - htab->sfpr->contents;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_byte *
+savegpr0 (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, STD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savegpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = savegpr0 (abfd, p, r);
+ bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+ p = p + 4;
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restgpr0 (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restgpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+ p = p + 4;
+ p = restgpr0 (abfd, p, r);
+ bfd_put_32 (abfd, MTLR_R0, p);
+ p = p + 4;
+ if (r == 29)
+ {
+ p = restgpr0 (abfd, p, 30);
+ p = restgpr0 (abfd, p, 31);
+ }
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savegpr1 (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, STD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savegpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = savegpr1 (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restgpr1 (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restgpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = restgpr1 (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savefpr (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, STFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savefpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = savefpr (abfd, p, r);
+ bfd_put_32 (abfd, STD_R0_0R1 + 16, p);
+ p = p + 4;
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restfpr (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restfpr0_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LD_R0_0R1 + 16, p);
+ p = p + 4;
+ p = restfpr (abfd, p, r);
+ bfd_put_32 (abfd, MTLR_R0, p);
+ p = p + 4;
+ if (r == 29)
+ {
+ p = restfpr (abfd, p, 30);
+ p = restfpr (abfd, p, 31);
+ }
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savefpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = savefpr (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restfpr1_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = restfpr (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+savevr (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p);
+ p = p + 4;
+ bfd_put_32 (abfd, STVX_VR0_R12_R0 + (r << 21), p);
+ return p + 4;
+}
+
+static bfd_byte *
+savevr_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = savevr (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
+static bfd_byte *
+restvr (bfd *abfd, bfd_byte *p, int r)
+{
+ bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p);
+ p = p + 4;
+ bfd_put_32 (abfd, LVX_VR0_R12_R0 + (r << 21), p);
+ return p + 4;
+}
+
+static bfd_byte *
+restvr_tail (bfd *abfd, bfd_byte *p, int r)
+{
+ p = restvr (abfd, p, r);
+ bfd_put_32 (abfd, BLR, p);
+ return p + 4;
+}
+
/* Called via elf_link_hash_traverse to transfer dynamic linking
information on function code symbol entries to their corresponding
function descriptor symbol entries. */
+
static bfd_boolean
func_desc_adjust (struct elf_link_hash_entry *h, void *inf)
{
return TRUE;
}
-#define MIN_SAVE_FPR 14
-#define MAX_SAVE_FPR 31
-
/* Called near the start of bfd_elf_size_dynamic_sections. We use
this hook to a) provide some gcc support functions, and b) transfer
dynamic linking information gathered so far on function code symbol
entries, to their corresponding function descriptor symbol entries. */
+
static bfd_boolean
ppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED,
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
- unsigned int lowest_savef = MAX_SAVE_FPR + 2;
- unsigned int lowest_restf = MAX_SAVE_FPR + 2;
unsigned int i;
- struct elf_link_hash_entry *h;
- bfd_byte *p;
- char sym[10];
+ const struct sfpr_def_parms funcs[] =
+ {
+ { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
+ { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
+ { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail },
+ { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail },
+ { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail },
+ { "_savefpr_", 14, 31, savefpr, savefpr0_tail },
+ { "_restfpr_", 14, 29, restfpr, restfpr0_tail },
+ { "_restfpr_", 30, 31, restfpr, restfpr0_tail },
+ { "._savef", 14, 31, savefpr, savefpr1_tail },
+ { "._restf", 14, 31, restfpr, restfpr1_tail },
+ { "_savevr_", 20, 31, savevr, savevr_tail },
+ { "_restvr_", 20, 31, restvr, restvr_tail }
+ };
htab = ppc_hash_table (info);
-
if (htab->sfpr == NULL)
/* We don't have any relocs. */
return TRUE;
- /* First provide any missing ._savef* and ._restf* functions. */
- memcpy (sym, "._savef14", 10);
- for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
- {
- sym[7] = i / 10 + '0';
- sym[8] = i % 10 + '0';
- h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
- if (h != NULL
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- {
- if (lowest_savef > i)
- lowest_savef = i;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = htab->sfpr;
- h->root.u.def.value = (i - lowest_savef) * 4;
- h->type = STT_FUNC;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
- }
- }
-
- memcpy (sym, "._restf14", 10);
- for (i = MIN_SAVE_FPR; i <= MAX_SAVE_FPR; i++)
- {
- sym[7] = i / 10 + '0';
- sym[8] = i % 10 + '0';
- h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE);
- if (h != NULL
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- {
- if (lowest_restf > i)
- lowest_restf = i;
- h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = htab->sfpr;
- h->root.u.def.value = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
- + (i - lowest_restf) * 4);
- h->type = STT_FUNC;
- h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- _bfd_elf_link_hash_hide_symbol (info, h, TRUE);
- }
- }
+ /* 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;
elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
- htab->sfpr->size = ((MAX_SAVE_FPR + 2 - lowest_savef) * 4
- + (MAX_SAVE_FPR + 2 - lowest_restf) * 4);
-
if (htab->sfpr->size == 0)
- {
- _bfd_strip_section_from_output (info, htab->sfpr);
- return TRUE;
- }
-
- p = bfd_alloc (htab->elf.dynobj, htab->sfpr->size);
- if (p == NULL)
- return FALSE;
- htab->sfpr->contents = p;
-
- for (i = lowest_savef; i <= MAX_SAVE_FPR; i++)
- {
- unsigned int fpr = i << 21;
- unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
- bfd_put_32 (htab->elf.dynobj, STFD_FR0_0R1 + fpr + stackoff, p);
- p += 4;
- }
- if (lowest_savef <= MAX_SAVE_FPR)
- {
- bfd_put_32 (htab->elf.dynobj, BLR, p);
- p += 4;
- }
-
- for (i = lowest_restf; i <= MAX_SAVE_FPR; i++)
- {
- unsigned int fpr = i << 21;
- unsigned int stackoff = (1 << 16) - (MAX_SAVE_FPR + 1 - i) * 8;
- bfd_put_32 (htab->elf.dynobj, LFD_FR0_0R1 + fpr + stackoff, p);
- p += 4;
- }
- if (lowest_restf <= MAX_SAVE_FPR)
- bfd_put_32 (htab->elf.dynobj, BLR, p);
+ _bfd_strip_section_from_output (info, htab->sfpr);
return TRUE;
}
p = bfd_malloc (need_pad->size + 8);
if (p == NULL)
return FALSE;
-
+
if (! bfd_get_section_contents (need_pad->owner, need_pad,
p, 0, need_pad->size))
return FALSE;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
+ if (!is_ppc64_target (ibfd->xvec))
continue;
if (ppc64_tlsld_got (ibfd)->refcount > 0)
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
+ if (!is_ppc64_target (ibfd->xvec))
+ continue;
+
s = ppc64_elf_tdata (ibfd)->got;
if (s != NULL && s != htab->got)
{
bfd_reloc_status_type r;
Elf_Internal_Sym *sym;
asection *sec;
- struct elf_link_hash_entry *h;
- struct elf_link_hash_entry *fdh;
+ struct elf_link_hash_entry *h_elf;
+ struct ppc_link_hash_entry *h;
+ struct ppc_link_hash_entry *fdh;
const char *sym_name;
unsigned long r_symndx, toc_symndx;
char tls_mask, tls_gd, tls_type;
sym = NULL;
sec = NULL;
- h = NULL;
+ h_elf = NULL;
sym_name = NULL;
unresolved_reloc = FALSE;
warned = FALSE;
{
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
- h, sec, relocation,
+ h_elf, sec, relocation,
unresolved_reloc, warned);
- sym_name = h->root.root.string;
- sym_type = h->type;
+ sym_name = h_elf->root.root.string;
+ sym_type = h_elf->type;
}
+ h = (struct ppc_link_hash_entry *) h_elf;
/* TLS optimizations. Replace instruction sequences and relocs
based on information we collected in tls_optimize. We edit
if (IS_PPC64_TLS_RELOC (r_type))
{
if (h != NULL)
- tls_mask = ((struct ppc_link_hash_entry *) h)->tls_mask;
+ tls_mask = h->tls_mask;
else if (local_got_ents != NULL)
{
char *lgot_masks;
if (r_symndx != 0
&& r_type != R_PPC64_NONE
&& (h == NULL
- || h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
+ || h->elf.root.type == bfd_link_hash_defined
+ || h->elf.root.type == bfd_link_hash_defweak)
&& IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS))
{
if (r_type == R_PPC64_TLS && tls_mask != 0)
stub_entry = NULL;
fdh = h;
if (((h != NULL
- && (((fdh = &((struct ppc_link_hash_entry *) h)->oh->elf) != NULL
- && fdh->plt.plist != NULL)
- || (fdh = h)->plt.plist != NULL))
+ && (((fdh = h->oh) != NULL
+ && fdh->elf.plt.plist != NULL)
+ || (fdh = h)->elf.plt.plist != NULL))
|| (sec != NULL
&& sec->output_section != NULL
&& sec->id <= htab->top_id
can_plt_call = TRUE;
}
else if (h != NULL
- && strcmp (h->root.root.string,
+ && strcmp (h->elf.root.root.string,
".__libc_start_main") == 0)
{
/* Allow crt1 branch to go via a toc adjusting stub. */
>= 2 * max_br_offset)
&& r_type != R_PPC64_ADDR14_BRTAKEN
&& r_type != R_PPC64_ADDR14_BRNTAKEN)
- stub_entry = ppc_get_stub_entry (input_section, sec, h, rel, htab);
+ stub_entry = ppc_get_stub_entry (input_section, sec, h, rel,
+ htab);
if (stub_entry != NULL)
{
We can thus call a weak function without first
checking whether the function is defined. */
else if (h != NULL
- && h->root.type == bfd_link_hash_undefweak
+ && h->elf.root.type == bfd_link_hash_undefweak
&& r_type == R_PPC64_REL24
&& relocation == 0
&& rel->r_addend == 0)
if (tls_type == (TLS_TLS | TLS_LD)
&& (h == NULL
- || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+ || (h->elf.elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_DYNAMIC) == 0))
offp = &ppc64_tlsld_got (input_bfd)->offset;
else
{
if (h != NULL)
{
bfd_boolean dyn = htab->elf.dynamic_sections_created;
- if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
+ &h->elf)
|| (info->shared
- && SYMBOL_REFERENCES_LOCAL (info, h)))
+ && SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
locally, or the symbol was forced to be local
;
else
{
- indx = h->dynindx;
+ indx = h->elf.dynindx;
unresolved_reloc = FALSE;
}
- ent = h->got.glist;
+ ent = h->elf.got.glist;
}
else
{
*offp = off | 1;
if ((info->shared || indx != 0)
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak))
+ || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
+ || h->elf.root.type != bfd_link_hash_undefweak))
{
outrel.r_offset = (got->output_section->vma
+ got->output_offset
if (htab->plt != NULL)
{
struct plt_entry *ent;
- for (ent = h->plt.plist; ent != NULL; ent = ent->next)
+ for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
if (ent->addend == rel->r_addend
&& ent->plt.offset != (bfd_vma) -1)
{
if ((info->shared
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
+ || h->elf.root.type != bfd_link_hash_undefweak)
&& (MUST_BE_DYN_RELOC (r_type)
- || !SYMBOL_CALLS_LOCAL (info, h)))
+ || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& h != NULL
- && h->dynindx != -1
- && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ && h->elf.dynindx != -1
+ && !(h->elf.elf_link_hash_flags & ELF_LINK_NON_GOT_REF)
+ && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)
+ && !(h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
{
Elf_Internal_Rela outrel;
bfd_boolean skip, relocate;
if (skip)
memset (&outrel, 0, sizeof outrel);
- else if (!SYMBOL_REFERENCES_LOCAL (info, h)
+ else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf)
&& !is_opd
&& r_type != R_PPC64_TOC)
- outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
+ outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
else
{
/* This symbol is local, or marked to become local,
not process them. */
if (unresolved_reloc
&& !((input_section->flags & SEC_DEBUGGING) != 0
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+ && (h->elf.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
{
(*_bfd_error_handler)
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_section,
(long) rel->r_offset,
ppc64_elf_howto_table[(int) r_type]->name,
- h->root.root.string);
+ h->elf.root.root.string);
ret = FALSE;
}
if (warned)
continue;
if (h != NULL
- && h->root.type == bfd_link_hash_undefweak
+ && h->elf.root.type == bfd_link_hash_undefweak
&& ppc64_elf_howto_table[r_type]->pc_relative)
{
/* Assume this is a call protected by other code that
}
/* We need to handle writing out multiple GOT sections ourselves,
- since we didn't add them to DYNOBJ. */
+ since we didn't add them to DYNOBJ. We know dynobj is the first
+ bfd. */
while ((dynobj = dynobj->link_next) != NULL)
{
asection *s;
+
+ if (!is_ppc64_target (dynobj->xvec))
+ continue;
+
s = ppc64_elf_tdata (dynobj)->got;
if (s != NULL
&& s->size != 0