* elf64-ppc.c (struct ppc_link_hash_table): Add stub_globals.

(is_ppc64_elf_target): Rename from is_ppc64_target.  Update all
	callers.
	(ppc_stub_name): Remove trailing "+0" on stub name.
	(create_linkage_sections): Create relocations for
	branch lookup table when --emit-relocs as well as when --shared.
	(ppc_build_one_stub): Emit relocs for long branch stubs.  Adjust
	relbrlt test.  For --emit-stub-syms, always output a sym even when
	one already exists on a plt call stub.  Put stub type in the stub
	symbol name.
	(ppc_size_one_stub): Size long branch stub relocs.  Adjust relbrlt
	test.
	(ppc64_elf_size_stubs): Count global sym stubs added.  Zero
	reloc_count in stub sections.  Adjust relbrlt test.
	(ppc64_elf_build_stubs): Adjust relbrlt test.  Tweak stats output.
	* elflink.c (bfd_elf_size_dynamic_sections): Fix comment typo.
	(elf_link_input_bfd): Ignore symbol index zero relocs when checking
	for relocs against discarded symbols.  Fix comments.
This commit is contained in:
Alan Modra
2004-09-07 13:40:37 +00:00
parent 1b882a91d0
commit ee75fd9567
3 changed files with 147 additions and 28 deletions

View File

@ -1,3 +1,24 @@
2004-09-07 Alan Modra <amodra@bigpond.net.au>
* elf64-ppc.c (struct ppc_link_hash_table): Add stub_globals.
(is_ppc64_elf_target): Rename from is_ppc64_target. Update all
callers.
(ppc_stub_name): Remove trailing "+0" on stub name.
(create_linkage_sections): Create relocations for
branch lookup table when --emit-relocs as well as when --shared.
(ppc_build_one_stub): Emit relocs for long branch stubs. Adjust
relbrlt test. For --emit-stub-syms, always output a sym even when
one already exists on a plt call stub. Put stub type in the stub
symbol name.
(ppc_size_one_stub): Size long branch stub relocs. Adjust relbrlt
test.
(ppc64_elf_size_stubs): Count global sym stubs added. Zero
reloc_count in stub sections. Adjust relbrlt test.
(ppc64_elf_build_stubs): Adjust relbrlt test. Tweak stats output.
* elflink.c (bfd_elf_size_dynamic_sections): Fix comment typo.
(elf_link_input_bfd): Ignore symbol index zero relocs when checking
for relocs against discarded symbols. Fix comments.
2004-09-06 Mark Mitchell <mark@codesourcery.com> 2004-09-06 Mark Mitchell <mark@codesourcery.com>
* elf-bfd.h (_bfd_elf_make_dynamic_segment): Declare it. * elf-bfd.h (_bfd_elf_make_dynamic_segment): Declare it.

View File

@ -2400,8 +2400,10 @@ ppc64_elf_mkobject (bfd *abfd)
return TRUE; return TRUE;
} }
/* Return 1 if target is one of ours. */
static bfd_boolean static bfd_boolean
is_ppc64_target (const struct bfd_target *targ) is_ppc64_elf_target (const struct bfd_target *targ)
{ {
extern const bfd_target bfd_elf64_powerpc_vec; extern const bfd_target bfd_elf64_powerpc_vec;
extern const bfd_target bfd_elf64_powerpcle_vec; extern const bfd_target bfd_elf64_powerpcle_vec;
@ -3290,6 +3292,9 @@ struct ppc_link_hash_table
/* Statistics. */ /* Statistics. */
unsigned long stub_count[ppc_stub_plt_call]; unsigned long stub_count[ppc_stub_plt_call];
/* Number of stubs against global syms. */
unsigned long stub_globals;
/* Set if we should emit symbols for stubs. */ /* Set if we should emit symbols for stubs. */
unsigned int emit_stub_syms:1; unsigned int emit_stub_syms:1;
@ -3533,6 +3538,8 @@ ppc_stub_name (const asection *input_section,
(int) rel->r_addend & 0xffffffff); (int) rel->r_addend & 0xffffffff);
} }
} }
if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0')
stub_name[len - 2] = 0;
return stub_name; return stub_name;
} }
@ -3671,7 +3678,7 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info)
|| ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) || ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE; return FALSE;
if (info->shared) if (info->shared || info->emitrelocations)
{ {
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
| SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
@ -4038,7 +4045,7 @@ ppc64_elf_check_directives (bfd *abfd ATTRIBUTE_UNUSED,
struct ppc_link_hash_table *htab; struct ppc_link_hash_table *htab;
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
if (!is_ppc64_target (htab->elf.root.creator)) if (!is_ppc64_elf_target (htab->elf.root.creator))
return TRUE; return TRUE;
elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info); elf_link_hash_traverse (&htab->elf, add_symbol_adjust, info);
@ -6898,7 +6905,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_hdr;
asection *srel; asection *srel;
if (!is_ppc64_target (ibfd->xvec)) if (!is_ppc64_elf_target (ibfd->xvec))
continue; continue;
if (ppc64_tlsld_got (ibfd)->refcount > 0) if (ppc64_tlsld_got (ibfd)->refcount > 0)
@ -7068,7 +7075,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{ {
if (!is_ppc64_target (ibfd->xvec)) if (!is_ppc64_elf_target (ibfd->xvec))
continue; continue;
s = ppc64_elf_tdata (ibfd)->got; s = ppc64_elf_tdata (ibfd)->got;
@ -7252,7 +7259,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
bfd_byte *p; bfd_byte *p;
unsigned int indx; unsigned int indx;
struct plt_entry *ent; struct plt_entry *ent;
bfd_vma off; bfd_vma dest, off;
int size; int size;
/* Massage our args to the form they really have. */ /* Massage our args to the form they really have. */
@ -7271,7 +7278,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
case ppc_stub_long_branch: case ppc_stub_long_branch:
case ppc_stub_long_branch_r2off: case ppc_stub_long_branch_r2off:
/* Branches are relative. This is where we are going to. */ /* Branches are relative. This is where we are going to. */
off = (stub_entry->target_value off = dest = (stub_entry->target_value
+ stub_entry->target_section->output_offset + stub_entry->target_section->output_offset
+ stub_entry->target_section->output_section->vma); + stub_entry->target_section->output_section->vma);
@ -7300,6 +7307,67 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc); bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26)); BFD_ASSERT (off + (1 << 25) < (bfd_vma) (1 << 26));
if (info->emitrelocations)
{
Elf_Internal_Rela *relocs, *r;
struct bfd_elf_section_data *elfsec_data;
elfsec_data = elf_section_data (stub_entry->stub_sec);
relocs = elfsec_data->relocs;
if (relocs == NULL)
{
bfd_size_type relsize;
relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs);
relocs = bfd_alloc (htab->stub_bfd, relsize);
if (relocs == NULL)
return FALSE;
elfsec_data->relocs = relocs;
elfsec_data->rel_hdr.sh_size = relsize;
elfsec_data->rel_hdr.sh_entsize = 24;
stub_entry->stub_sec->reloc_count = 0;
}
r = relocs + stub_entry->stub_sec->reloc_count;
stub_entry->stub_sec->reloc_count += 1;
r->r_offset = loc - stub_entry->stub_sec->contents;
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
r->r_addend = dest;
if (stub_entry->h != NULL)
{
struct elf_link_hash_entry **hashes;
unsigned long symndx;
struct ppc_link_hash_entry *h;
hashes = elf_sym_hashes (htab->stub_bfd);
if (hashes == NULL)
{
bfd_size_type hsize;
hsize = (htab->stub_globals + 1) * sizeof (*hashes);
hashes = bfd_zalloc (htab->stub_bfd, hsize);
if (hashes == NULL)
return FALSE;
elf_sym_hashes (htab->stub_bfd) = hashes;
htab->stub_globals = 1;
}
symndx = htab->stub_globals++;
h = stub_entry->h;
hashes[symndx] = &h->elf;
r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
if (h->oh != NULL && h->oh->is_func)
h = h->oh;
if (h->elf.root.u.def.section != stub_entry->target_section)
/* H is an opd symbol. The addend must be zero. */
r->r_addend = 0;
else
{
off = (h->elf.root.u.def.value
+ h->elf.root.u.def.section->output_offset
+ h->elf.root.u.def.section->output_section->vma);
r->r_addend -= off;
}
}
}
break; break;
case ppc_stub_plt_branch: case ppc_stub_plt_branch:
@ -7322,7 +7390,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
bfd_put_64 (htab->brlt->owner, off, bfd_put_64 (htab->brlt->owner, off,
htab->brlt->contents + br_entry->offset); htab->brlt->contents + br_entry->offset);
if (info->shared) if (htab->relbrlt != NULL)
{ {
/* Create a reloc for the branch lookup table entry. */ /* Create a reloc for the branch lookup table entry. */
Elf_Internal_Rela rela; Elf_Internal_Rela rela;
@ -7442,16 +7510,26 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
stub_entry->stub_sec->size += size; stub_entry->stub_sec->size += size;
if (htab->emit_stub_syms if (htab->emit_stub_syms)
&& !(stub_entry->stub_type == ppc_stub_plt_call
&& stub_entry->h->oh != NULL
&& stub_entry->h->oh->elf.root.type == bfd_link_hash_defined
&& stub_entry->h->oh->elf.root.u.def.section == stub_entry->stub_sec
&& stub_entry->h->oh->elf.root.u.def.value == stub_entry->stub_offset))
{ {
struct elf_link_hash_entry *h; struct elf_link_hash_entry *h;
h = elf_link_hash_lookup (&htab->elf, stub_entry->root.string, size_t len1, len2;
TRUE, FALSE, FALSE); char *name;
const char *const stub_str[] = { "long_branch",
"long_branch_r2off",
"plt_branch",
"plt_branch_r2off",
"plt_call" };
len1 = strlen (stub_str[stub_entry->stub_type - 1]);
len2 = strlen (stub_entry->root.string);
name = bfd_malloc (len1 + len2 + 2);
if (name == NULL)
return FALSE;
memcpy (name, stub_entry->root.string, 9);
memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1);
memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1);
h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE);
if (h == NULL) if (h == NULL)
return FALSE; return FALSE;
if (h->root.type == bfd_link_hash_new) if (h->root.type == bfd_link_hash_new)
@ -7554,7 +7632,7 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
br_entry->offset = htab->brlt->size; br_entry->offset = htab->brlt->size;
htab->brlt->size += 8; htab->brlt->size += 8;
if (info->shared) if (htab->relbrlt != NULL)
htab->relbrlt->size += sizeof (Elf64_External_Rela); htab->relbrlt->size += sizeof (Elf64_External_Rela);
} }
@ -7563,6 +7641,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (stub_entry->stub_type != ppc_stub_plt_branch) if (stub_entry->stub_type != ppc_stub_plt_branch)
size = 28; size = 28;
} }
if (info->emitrelocations
&& (stub_entry->stub_type == ppc_stub_long_branch
|| stub_entry->stub_type == ppc_stub_long_branch_r2off))
stub_entry->stub_sec->reloc_count += 1;
} }
stub_entry->stub_sec->size += size; stub_entry->stub_sec->size += size;
@ -8149,6 +8232,10 @@ ppc64_elf_size_stubs (bfd *output_bfd,
stub_entry->target_section = code_sec; stub_entry->target_section = code_sec;
stub_entry->h = hash; stub_entry->h = hash;
stub_entry->addend = irela->r_addend; stub_entry->addend = irela->r_addend;
if (stub_entry->h != NULL)
htab->stub_globals += 1;
stub_changed = TRUE; stub_changed = TRUE;
} }
@ -8176,10 +8263,13 @@ ppc64_elf_size_stubs (bfd *output_bfd,
stub_sec != NULL; stub_sec != NULL;
stub_sec = stub_sec->next) stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
stub_sec->size = 0; stub_sec->size = 0;
stub_sec->reloc_count = 0;
}
htab->brlt->size = 0; htab->brlt->size = 0;
if (info->shared) if (htab->relbrlt != NULL)
htab->relbrlt->size = 0; htab->relbrlt->size = 0;
bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info); bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
@ -8384,7 +8474,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
if (htab->brlt->contents == NULL) if (htab->brlt->contents == NULL)
return FALSE; return FALSE;
} }
if (info->shared && htab->relbrlt->size != 0) if (htab->relbrlt != NULL && htab->relbrlt->size != 0)
{ {
htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner, htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner,
htab->relbrlt->size); htab->relbrlt->size);
@ -8421,13 +8511,14 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms,
if (*stats == NULL) if (*stats == NULL)
return FALSE; return FALSE;
sprintf (*stats, _("linker stubs in %u groups\n" sprintf (*stats, _("linker stubs in %u group%s\n"
" branch %lu\n" " branch %lu\n"
" toc adjust %lu\n" " toc adjust %lu\n"
" long branch %lu\n" " long branch %lu\n"
" long toc adj %lu\n" " long toc adj %lu\n"
" plt call %lu"), " plt call %lu"),
stub_sec_count, stub_sec_count,
stub_sec_count == 1 ? "" : "s",
htab->stub_count[ppc_stub_long_branch - 1], htab->stub_count[ppc_stub_long_branch - 1],
htab->stub_count[ppc_stub_long_branch_r2off - 1], htab->stub_count[ppc_stub_long_branch_r2off - 1],
htab->stub_count[ppc_stub_plt_branch - 1], htab->stub_count[ppc_stub_plt_branch - 1],
@ -8526,6 +8617,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
ppc_howto_init (); ppc_howto_init ();
htab = ppc_hash_table (info); htab = ppc_hash_table (info);
/* Don't relocate stub sections. */
if (input_section->owner == htab->stub_bfd)
return TRUE;
local_got_ents = elf_local_got_ents (input_bfd); local_got_ents = elf_local_got_ents (input_bfd);
TOCstart = elf_gp (output_bfd); TOCstart = elf_gp (output_bfd);
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
@ -10116,7 +10212,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd,
{ {
asection *s; asection *s;
if (!is_ppc64_target (dynobj->xvec)) if (!is_ppc64_elf_target (dynobj->xvec))
continue; continue;
s = ppc64_elf_tdata (dynobj)->got; s = ppc64_elf_tdata (dynobj)->got;

View File

@ -4914,7 +4914,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
return FALSE; return FALSE;
/* Add some entries to the .dynamic section. We fill in some of the /* Add some entries to the .dynamic section. We fill in some of the
values later, in elf_bfd_final_link, but we must add the entries values later, in bfd_elf_final_link, but we must add the entries
now so that we know the final size of the .dynamic section. */ now so that we know the final size of the .dynamic section. */
/* If there are initialization and/or finalization functions to /* If there are initialization and/or finalization functions to
@ -6648,6 +6648,9 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
struct elf_link_hash_entry *h = NULL; struct elf_link_hash_entry *h = NULL;
const char *sym_name; const char *sym_name;
if (r_symndx == STN_UNDEF)
continue;
if (r_symndx >= locsymcount if (r_symndx >= locsymcount
|| (elf_bad_symtab (input_bfd) || (elf_bad_symtab (input_bfd)
&& finfo->sections[r_symndx] == NULL)) && finfo->sections[r_symndx] == NULL))
@ -6840,7 +6843,7 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd)
symbol. We set the rel_hash entry for this symbol. We set the rel_hash entry for this
reloc to point to the global hash table entry reloc to point to the global hash table entry
for this symbol. The symbol index is then for this symbol. The symbol index is then
set at the end of elf_bfd_final_link. */ set at the end of bfd_elf_final_link. */
indx = r_symndx - extsymoff; indx = r_symndx - extsymoff;
rh = elf_sym_hashes (input_bfd)[indx]; rh = elf_sym_hashes (input_bfd)[indx];
while (rh->root.type == bfd_link_hash_indirect while (rh->root.type == bfd_link_hash_indirect
@ -7580,8 +7583,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
if (! _bfd_elf_compute_section_file_positions (abfd, info)) if (! _bfd_elf_compute_section_file_positions (abfd, info))
goto error_return; goto error_return;
/* That created the reloc sections. Set their sizes, and assign /* Set sizes, and assign file positions for reloc sections. */
them file positions, and allocate some buffers. */
for (o = abfd->sections; o != NULL; o = o->next) for (o = abfd->sections; o != NULL; o = o->next)
{ {
if ((o->flags & SEC_RELOC) != 0) if ((o->flags & SEC_RELOC) != 0)