You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* The 64-bit PowerPC ELF ABI may be found at
http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and
#define elf_backend_want_plt_sym 0
#define elf_backend_plt_alignment 3
#define elf_backend_plt_not_loaded 1
-#define elf_backend_got_symbol_offset 0
#define elf_backend_got_header_size 8
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
ppc_howto_init ();
type = ELF64_R_TYPE (dst->r_info);
- BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table)
- / sizeof (ppc64_elf_howto_table[0])));
+ if (type >= (sizeof (ppc64_elf_howto_table)
+ / sizeof (ppc64_elf_howto_table[0])))
+ {
+ (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
+ abfd, (int) type);
+ type = R_PPC64_NONE;
+ }
cache_ptr->howto = ppc64_elf_howto_table[type];
}
asection *got;
asection *relgot;
- /* Used during garbage collection. We attach global symbols defined
- on removed .opd entries to this section so that the sym is removed. */
- asection *deleted_section;
+ union {
+ /* Used during garbage collection. We attach global symbols defined
+ on removed .opd entries to this section so that the sym is removed. */
+ asection *deleted_section;
+
+ /* Used when adding symbols. */
+ bfd_boolean has_dotsym;
+ } u;
/* TLS local dynamic got entry handling. Suppose for multiple GOT
sections means we potentially need one of these for each input bfd. */
/* Add extra PPC sections. */
-static struct bfd_elf_special_section const ppc64_elf_special_sections[]=
+static const struct bfd_elf_special_section ppc64_elf_special_sections[]=
{
- { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ ".plt", 4, 0, SHT_NOBITS, 0 },
+ { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ ".toc", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ ".toc1", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ ".tocbss", 7, 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
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. */
+ 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)
/* Base hash table entry structure. */
struct bfd_hash_entry root;
- /* Offset within .branch_lt. */
+ /* Offset within branch lookup table. */
unsigned int offset;
/* Generation marker. */
only care about glist, but when compiled on a 32-bit host the
bfd_vma fields are larger. Setting the bfd_vma to zero makes
debugger inspection of these fields look nicer. */
- htab->elf.init_refcount.refcount = 0;
- htab->elf.init_refcount.glist = NULL;
- htab->elf.init_offset.offset = 0;
- htab->elf.init_offset.glist = NULL;
+ htab->elf.init_got_refcount.refcount = 0;
+ htab->elf.init_got_refcount.glist = NULL;
+ htab->elf.init_plt_refcount.refcount = 0;
+ htab->elf.init_plt_refcount.glist = NULL;
+ htab->elf.init_got_offset.offset = 0;
+ htab->elf.init_got_offset.glist = NULL;
+ htab->elf.init_plt_offset.offset = 0;
+ htab->elf.init_plt_offset.glist = NULL;
return &htab->elf.root;
}
{
len = 8 + 1 + strlen (h->elf.root.root.string) + 1 + 8 + 1;
stub_name = bfd_malloc (len);
- if (stub_name != NULL)
- {
- sprintf (stub_name, "%08x.%s+%x",
- input_section->id & 0xffffffff,
- h->elf.root.root.string,
- (int) rel->r_addend & 0xffffffff);
- }
+ 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);
}
else
{
len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1;
stub_name = bfd_malloc (len);
- if (stub_name != NULL)
- {
- 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 == 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);
}
if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
stub_name[len - 2] = 0;
/* 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 (dynobj, ".sfpr");
+ htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr",
+ flags);
if (htab->sfpr == NULL
- || ! bfd_set_section_flags (dynobj, htab->sfpr, flags)
|| ! bfd_set_section_alignment (dynobj, htab->sfpr, 2))
return FALSE;
/* Create .glink for lazy dynamic linking support. */
- htab->glink = bfd_make_section_anyway (dynobj, ".glink");
+ htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink",
+ flags);
if (htab->glink == NULL
- || ! bfd_set_section_flags (dynobj, htab->glink, flags)
|| ! bfd_set_section_alignment (dynobj, htab->glink, 2))
return FALSE;
- /* Create .branch_lt for plt_branch stubs. */
- flags = (SEC_ALLOC | SEC_LOAD
- | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->brlt = bfd_make_section_anyway (dynobj, ".branch_lt");
+ /* Create branch lookup table for plt_branch stubs. */
+ if (info->shared)
+ {
+ flags = (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->brlt
+ = bfd_make_section_anyway_with_flags (dynobj, ".data.rel.ro.brlt",
+ flags);
+ }
+ else
+ {
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+ htab->brlt
+ = bfd_make_section_anyway_with_flags (dynobj, ".rodata.brlt", flags);
+ }
+
if (htab->brlt == NULL
- || ! bfd_set_section_flags (dynobj, htab->brlt, flags)
|| ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE;
- if (info->shared || info->emitrelocations)
+ if (info->shared)
{
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- htab->relbrlt = bfd_make_section_anyway (dynobj, ".rela.branch_lt");
- if (!htab->relbrlt
- || ! bfd_set_section_flags (dynobj, htab->relbrlt, flags)
- || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
- return FALSE;
+ htab->relbrlt
+ = bfd_make_section_anyway_with_flags (dynobj, ".rela.data.rel.ro.brlt",
+ flags);
+ }
+ else if (info->emitrelocations)
+ {
+ 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.rodata.brlt",
+ flags);
}
+ else
+ return TRUE;
+
+ if (!htab->relbrlt
+ || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
+ return FALSE;
+
return TRUE;
}
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
- got = bfd_make_section (abfd, ".got");
+ got = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (!got
- || !bfd_set_section_flags (abfd, got, flags)
|| !bfd_set_section_alignment (abfd, got, 3))
return FALSE;
- relgot = bfd_make_section (abfd, ".rela.got");
+ relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got",
+ flags | SEC_READONLY);
if (!relgot
- || ! bfd_set_section_flags (abfd, relgot, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, relgot, 3))
return FALSE;
function type. */
static bfd_boolean
-ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
+ppc64_elf_add_symbol_hook (bfd *ibfd,
struct bfd_link_info *info ATTRIBUTE_UNUSED,
Elf_Internal_Sym *isym,
- const char **name ATTRIBUTE_UNUSED,
+ const char **name,
flagword *flags ATTRIBUTE_UNUSED,
asection **sec,
bfd_vma *value ATTRIBUTE_UNUSED)
if (*sec != NULL
&& strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
+
+ if ((*name)[0] == '.'
+ && ELF_ST_BIND (isym->st_info) == STB_GLOBAL
+ && ELF_ST_TYPE (isym->st_info) < STT_SECTION
+ && is_ppc64_elf_target (ibfd->xvec))
+ ppc64_elf_tdata (ibfd)->u.has_dotsym = 1;
+
return TRUE;
}
else
fdh->elf.ref_regular = 1;
}
- else if (fdh != NULL
- && (fdh->elf.root.type == bfd_link_hash_defined
- || fdh->elf.root.type == bfd_link_hash_defweak))
+ else if (fdh != NULL)
{
unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
else if (entry_vis > descr_vis)
eh->elf.other += descr_vis - entry_vis;
- if (eh->elf.root.type == bfd_link_hash_undefined)
+ if ((fdh->elf.root.type == bfd_link_hash_defined
+ || fdh->elf.root.type == bfd_link_hash_defweak)
+ && eh->elf.root.type == bfd_link_hash_undefined)
{
eh->elf.root.type = bfd_link_hash_undefweak;
eh->was_undefined = 1;
}
static bfd_boolean
-ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info)
+ppc64_elf_check_directives (bfd *abfd, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
struct add_symbol_adjust_data data;
+ if (!is_ppc64_elf_target (abfd->xvec))
+ return TRUE;
+
+ if (!ppc64_elf_tdata (abfd)->u.has_dotsym)
+ return TRUE;
+ ppc64_elf_tdata (abfd)->u.deleted_section = NULL;
+
htab = ppc_hash_table (info);
if (!is_ppc64_elf_target (htab->elf.root.creator))
return TRUE;
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
r_type = ELF64_R_TYPE (rel->r_info);
switch (r_type)
{
flagword flags;
- sreloc = bfd_make_section (dynobj, name);
flags = (SEC_HAS_CONTENTS | SEC_READONLY
| SEC_IN_MEMORY | SEC_LINKER_CREATED
| SEC_ALLOC | SEC_LOAD);
+ sreloc = bfd_make_section_with_flags (dynobj,
+ name,
+ flags);
if (sreloc == NULL
- || ! bfd_set_section_flags (dynobj, sreloc, flags)
|| ! bfd_set_section_alignment (dynobj, sreloc, 3))
return FALSE;
}
if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
return (bfd_vma) -1;
-
+
if (code_sec != NULL)
{
asection *sec, *likely = NULL;
if (!rsec->gc_mark)
_bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook);
- rsec = opd_sym_section[sym->st_value / 8];
+ rsec = opd_sym_section[(sym->st_value + rel->r_addend) / 8];
}
}
}
/* Fake function descriptors are made undefweak. If the function
- code symbol is strong undefined, make the fake sym the same. */
+ code symbol is strong undefined, make the fake sym the same.
+ If the function code symbol is defined, then force the fake
+ descriptor local; We can't support overriding of symbols in a
+ shared library on a fake descriptor. */
if (fdh != NULL
&& fdh->fake
- && fdh->elf.root.type == bfd_link_hash_undefweak
- && fh->elf.root.type == bfd_link_hash_undefined)
+ && fdh->elf.root.type == bfd_link_hash_undefweak)
{
- fdh->elf.root.type = bfd_link_hash_undefined;
- bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
+ if (fh->elf.root.type == bfd_link_hash_undefined)
+ {
+ fdh->elf.root.type = bfd_link_hash_undefined;
+ bfd_link_add_undef (&htab->elf.root, &fdh->elf.root);
+ }
+ else if (fh->elf.root.type == bfd_link_hash_defined
+ || fh->elf.root.type == bfd_link_hash_defweak)
+ {
+ _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE);
+ }
}
if (fdh != NULL
elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
if (htab->sfpr->size == 0)
- _bfd_strip_section_from_output (info, htab->sfpr);
+ htab->sfpr->flags |= SEC_EXCLUDE;
return TRUE;
}
if (adjust == -1)
{
/* This entry has been deleted. */
- asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section;
+ asection *dsec = ppc64_elf_tdata (sym_sec->owner)->u.deleted_section;
if (dsec == NULL)
{
for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next)
if (elf_discarded_section (dsec))
{
- ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec;
+ ppc64_elf_tdata (sym_sec->owner)->u.deleted_section = dsec;
break;
}
}
bfd_boolean
ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info,
+ bfd_boolean no_opd_opt,
bfd_boolean non_overlapping)
{
bfd *ibfd;
bfd_size_type cnt_16b = 0;
sec = bfd_get_section_by_name (ibfd, ".opd");
- if (sec == NULL)
+ if (sec == NULL || sec->size == 0)
continue;
amt = sec->size * sizeof (long) / 8;
{
/* check_relocs hasn't been called. Must be a ld -r link
or --just-symbols object. */
- opd_adjust = bfd_zalloc (obfd, amt);
+ opd_adjust = bfd_alloc (obfd, amt);
+ if (opd_adjust == NULL)
+ return FALSE;
ppc64_elf_section_data (sec)->opd.adjust = opd_adjust;
}
memset (opd_adjust, 0, amt);
+ if (no_opd_opt)
+ continue;
+
if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
continue;
if (h != NULL)
sym_name = h->root.root.string;
else
- sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym);
+ sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+ sym_sec);
(*_bfd_error_handler)
(_("%B: undefined sym `%s' in .opd section"),
elf_section_data (sec)->relocs = relstart;
- wptr = sec->contents;
- rptr = sec->contents;
new_contents = sec->contents;
-
if (add_aux_fields)
{
new_contents = bfd_malloc (sec->size + cnt_16b * 8);
if (new_contents == NULL)
return FALSE;
need_pad = FALSE;
- wptr = new_contents;
}
+ wptr = new_contents;
+ rptr = sec->contents;
write_rel = relstart;
skip = FALSE;
{
(*_bfd_error_handler)
(_("%s defined in removed toc entry"),
- bfd_elf_sym_name (ibfd, symtab_hdr, sym));
+ bfd_elf_sym_name (ibfd, symtab_hdr, sym,
+ NULL));
sym->st_value = 0;
sym->st_shndx = SHN_ABS;
}
continue;
else if (s == htab->got
|| s == htab->plt
- || s == htab->glink)
+ || s == htab->glink
+ || s == htab->dynbss)
{
/* Strip this section if we don't need it; see the
comment below. */
}
else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
{
- if (s->size == 0)
- {
- /* If we don't need this section, strip it from the
- output file. This is mostly to handle .rela.bss and
- .rela.plt. We must create both sections in
- create_dynamic_sections, because they must be created
- before the linker maps input sections to output
- sections. The linker does that before
- adjust_dynamic_symbol is called, and it is that
- function which decides whether anything needs to go
- into these sections. */
- }
- else
+ if (s->size != 0)
{
if (s != htab->relplt)
relocs = TRUE;
if (s->size == 0)
{
- _bfd_strip_section_from_output (info, s);
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ s->flags |= SEC_EXCLUDE;
continue;
}
- /* .plt is in the bss section. We don't initialise it. */
- if (s == htab->plt)
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
continue;
/* Allocate memory for the section contents. We use bfd_zalloc
if (s != NULL && s != htab->got)
{
if (s->size == 0)
- _bfd_strip_section_from_output (info, s);
+ s->flags |= SEC_EXCLUDE;
else
{
s->contents = bfd_zalloc (ibfd, s->size);
if (s != NULL)
{
if (s->size == 0)
- _bfd_strip_section_from_output (info, s);
+ s->flags |= SEC_EXCLUDE;
else
{
s->contents = bfd_zalloc (ibfd, s->size);
/* We can't use output_bfd->section_count here to find the top output
section index as some sections may have been removed, and
- _bfd_strip_section_from_output doesn't renumber the indices. */
+ strip_excluded_output_sections doesn't renumber the indices. */
for (section = output_bfd->sections, top_index = 0;
section != NULL;
section = section->next)
(*htab->layout_sections_again) ();
}
- /* It would be nice to strip .branch_lt from the output if the
+ /* It would be nice to strip htab->brlt from the output if the
section is empty, but it's too late. If we strip sections here,
the dynamic symbol table is corrupted since the section symbol
for the stripped section isn't written. */
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
- sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym);
+ sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
sym_type = ELF64_ST_TYPE (sym->st_info);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
opd_adjust = get_opd_info (sec);