ppc64 section group handling

Two organizational changes to the array of additional info kept for
sections.
1) Move group info into a per-group allocated struct, in preparation
for future changes that need per-group accounting.
2) Expand the array to include output sections, which simplifies
sizing and removes the need for a separate output section array.

	* section.c (section_id): Make file scope.
	(bfd_get_next_section_id): New function.
	* elf64-ppc.c (struct map_stub): Remove toc_off field.  Move decl.
	(struct ppc_stub_hash_entry): Delete stub_sec and id_sec.  Add
	group.  Update all uses.
	(struct ppc_link_hash_table): Delete top_id, top_index, and
	input_list.  Add sec_info_arr_size.  Rename stub_group to
	sec_info, and make group info indirect.  Update stub_group refs
	throughout file.
	(ppc_add_stub): Don't look for stub_sec on link_sec stub_group
	entry.
	(ppc_build_one_stub): Delete FIXME.
	(ppc64_elf_setup_section_lists): Size htab->sec_info for all
	sections, not just input sections.  Don't create htab->input_list.
	(ppc64_elf_next_input_section): Update to use sec_info union as
	list pointer.
	(PREV_SEC): Delete.
	(group_sections): Pass "info" param rather than "htab".  Iterate
	over output sections rather than input_list.  Use sec_info union
	as list pointers.  Alloc atruct map_stub, and return fail status.
	* bfd-in2.h: Regenerate.
This commit is contained in:
Alan Modra 2015-08-31 17:50:33 +09:30
parent 136765eab1
commit 6f20ed8a6b
4 changed files with 193 additions and 177 deletions

View file

@ -1,3 +1,27 @@
2015-08-31 Alan Modra <amodra@gmail.com>
* section.c (section_id): Make file scope.
(bfd_get_next_section_id): New function.
* elf64-ppc.c (struct map_stub): Remove toc_off field. Move decl.
(struct ppc_stub_hash_entry): Delete stub_sec and id_sec. Add
group. Update all uses.
(struct ppc_link_hash_table): Delete top_id, top_index, and
input_list. Add sec_info_arr_size. Rename stub_group to
sec_info, and make group info indirect. Update stub_group refs
throughout file.
(ppc_add_stub): Don't look for stub_sec on link_sec stub_group
entry.
(ppc_build_one_stub): Delete FIXME.
(ppc64_elf_setup_section_lists): Size htab->sec_info for all
sections, not just input sections. Don't create htab->input_list.
(ppc64_elf_next_input_section): Update to use sec_info union as
list pointer.
(PREV_SEC): Delete.
(group_sections): Pass "info" param rather than "htab". Iterate
over output sections rather than input_list. Use sec_info union
as list pointers. Alloc atruct map_stub, and return fail status.
* bfd-in2.h: Regenerate.
2015-08-31 Alan Modra <amodra@gmail.com> 2015-08-31 Alan Modra <amodra@gmail.com>
* elflink.c (elf_sort_symbol): Use correctly sized type for * elflink.c (elf_sort_symbol): Use correctly sized type for

View file

@ -1818,6 +1818,8 @@ asection *bfd_make_section_with_flags
asection *bfd_make_section (bfd *, const char *name); asection *bfd_make_section (bfd *, const char *name);
int bfd_get_next_section_id (void);
bfd_boolean bfd_set_section_flags bfd_boolean bfd_set_section_flags
(bfd *abfd, asection *sec, flagword flags); (bfd *abfd, asection *sec, flagword flags);

View file

@ -3799,6 +3799,15 @@ enum ppc_stub_type {
ppc_stub_global_entry ppc_stub_global_entry
}; };
/* Information on stub grouping. */
struct map_stub
{
/* The stub section. */
asection *stub_sec;
/* This is the section to which stubs in the group will be attached. */
asection *link_sec;
};
struct ppc_stub_hash_entry { struct ppc_stub_hash_entry {
/* Base hash table entry structure. */ /* Base hash table entry structure. */
@ -3806,8 +3815,8 @@ struct ppc_stub_hash_entry {
enum ppc_stub_type stub_type; enum ppc_stub_type stub_type;
/* The stub section. */ /* Group information. */
asection *stub_sec; struct map_stub *group;
/* Offset within stub_sec of the beginning of this stub. */ /* Offset within stub_sec of the beginning of this stub. */
bfd_vma stub_offset; bfd_vma stub_offset;
@ -3821,10 +3830,6 @@ struct ppc_stub_hash_entry {
struct ppc_link_hash_entry *h; struct ppc_link_hash_entry *h;
struct plt_entry *plt_ent; struct plt_entry *plt_ent;
/* Where this stub is being called from, or, in the case of combined
stub sections, the first input section in the group. */
asection *id_sec;
/* Symbol st_other. */ /* Symbol st_other. */
unsigned char other; unsigned char other;
}; };
@ -3925,34 +3930,34 @@ struct ppc_link_hash_table
/* Various options and other info passed from the linker. */ /* Various options and other info passed from the linker. */
struct ppc64_elf_params *params; struct ppc64_elf_params *params;
/* Array to keep track of which stub sections have been created, and /* The size of sec_info below. */
information on stub grouping. */ unsigned int sec_info_arr_size;
struct map_stub {
/* This is the section to which stubs in the group will be attached. */ /* Per-section array of extra section info. Done this way rather
asection *link_sec; than as part of ppc64_elf_section_data so we have the info for
/* The stub section. */ non-ppc64 sections. */
asection *stub_sec; struct
/* Along with elf_gp, specifies the TOC pointer used in this group. */ {
/* Along with elf_gp, specifies the TOC pointer used by this section. */
bfd_vma toc_off; bfd_vma toc_off;
} *stub_group;
union
{
/* The section group that this section belongs to. */
struct map_stub *group;
/* A temp section list pointer. */
asection *list;
} u;
} *sec_info;
/* Temp used when calculating TOC pointers. */ /* Temp used when calculating TOC pointers. */
bfd_vma toc_curr; bfd_vma toc_curr;
bfd *toc_bfd; bfd *toc_bfd;
asection *toc_first_sec; asection *toc_first_sec;
/* Highest input section id. */
unsigned int top_id;
/* Highest output section index. */
unsigned int top_index;
/* Used when adding symbols. */ /* Used when adding symbols. */
struct ppc_link_hash_entry *dot_syms; struct ppc_link_hash_entry *dot_syms;
/* List of input sections for each output section. */
asection **input_list;
/* Shortcuts to get to dynamic linker sections. */ /* Shortcuts to get to dynamic linker sections. */
asection *dynbss; asection *dynbss;
asection *relbss; asection *relbss;
@ -4056,13 +4061,12 @@ stub_hash_newfunc (struct bfd_hash_entry *entry,
/* Initialize the local fields. */ /* Initialize the local fields. */
eh = (struct ppc_stub_hash_entry *) entry; eh = (struct ppc_stub_hash_entry *) entry;
eh->stub_type = ppc_stub_none; eh->stub_type = ppc_stub_none;
eh->stub_sec = NULL; eh->group = NULL;
eh->stub_offset = 0; eh->stub_offset = 0;
eh->target_value = 0; eh->target_value = 0;
eh->target_section = NULL; eh->target_section = NULL;
eh->h = NULL; eh->h = NULL;
eh->plt_ent = NULL; eh->plt_ent = NULL;
eh->id_sec = NULL;
eh->other = 0; eh->other = 0;
} }
@ -4412,18 +4416,18 @@ ppc_get_stub_entry (const asection *input_section,
struct ppc_link_hash_table *htab) struct ppc_link_hash_table *htab)
{ {
struct ppc_stub_hash_entry *stub_entry; struct ppc_stub_hash_entry *stub_entry;
const asection *id_sec; struct map_stub *group;
/* If this input section is part of a group of sections sharing one /* If this input section is part of a group of sections sharing one
stub section, then use the id of the first section in the group. stub section, then use the id of the first section in the group.
Stub names need to include a section id, as there may well be Stub names need to include a section id, as there may well be
more than one stub used to reach say, printf, and we need to more than one stub used to reach say, printf, and we need to
distinguish between them. */ distinguish between them. */
id_sec = htab->stub_group[input_section->id].link_sec; group = htab->sec_info[input_section->id].u.group;
if (h != NULL && h->u.stub_cache != NULL if (h != NULL && h->u.stub_cache != NULL
&& h->u.stub_cache->h == h && h->u.stub_cache->h == h
&& h->u.stub_cache->id_sec == id_sec) && h->u.stub_cache->group == group)
{ {
stub_entry = h->u.stub_cache; stub_entry = h->u.stub_cache;
} }
@ -4431,7 +4435,7 @@ ppc_get_stub_entry (const asection *input_section,
{ {
char *stub_name; char *stub_name;
stub_name = ppc_stub_name (id_sec, sym_sec, h, rel); stub_name = ppc_stub_name (group->link_sec, sym_sec, h, rel);
if (stub_name == NULL) if (stub_name == NULL)
return NULL; return NULL;
@ -4455,35 +4459,32 @@ ppc_add_stub (const char *stub_name,
struct bfd_link_info *info) struct bfd_link_info *info)
{ {
struct ppc_link_hash_table *htab = ppc_hash_table (info); struct ppc_link_hash_table *htab = ppc_hash_table (info);
struct map_stub *group;
asection *link_sec; asection *link_sec;
asection *stub_sec; asection *stub_sec;
struct ppc_stub_hash_entry *stub_entry; struct ppc_stub_hash_entry *stub_entry;
link_sec = htab->stub_group[section->id].link_sec; group = htab->sec_info[section->id].u.group;
stub_sec = htab->stub_group[section->id].stub_sec; link_sec = group->link_sec;
stub_sec = group->stub_sec;
if (stub_sec == NULL) if (stub_sec == NULL)
{ {
stub_sec = htab->stub_group[link_sec->id].stub_sec; size_t namelen;
bfd_size_type len;
char *s_name;
namelen = strlen (link_sec->name);
len = namelen + sizeof (STUB_SUFFIX);
s_name = bfd_alloc (htab->params->stub_bfd, len);
if (s_name == NULL)
return NULL;
memcpy (s_name, link_sec->name, namelen);
memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
if (stub_sec == NULL) if (stub_sec == NULL)
{ return NULL;
size_t namelen; group->stub_sec = stub_sec;
bfd_size_type len;
char *s_name;
namelen = strlen (link_sec->name);
len = namelen + sizeof (STUB_SUFFIX);
s_name = bfd_alloc (htab->params->stub_bfd, len);
if (s_name == NULL)
return NULL;
memcpy (s_name, link_sec->name, namelen);
memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
if (stub_sec == NULL)
return NULL;
htab->stub_group[link_sec->id].stub_sec = stub_sec;
}
htab->stub_group[section->id].stub_sec = stub_sec;
} }
/* Enter this entry into the linker stub hash table. */ /* Enter this entry into the linker stub hash table. */
@ -4496,9 +4497,8 @@ ppc_add_stub (const char *stub_name,
return NULL; return NULL;
} }
stub_entry->stub_sec = stub_sec; stub_entry->group = group;
stub_entry->stub_offset = 0; stub_entry->stub_offset = 0;
stub_entry->id_sec = link_sec;
return stub_entry; return stub_entry;
} }
@ -10257,7 +10257,7 @@ plt_stub_pad (struct ppc_link_hash_table *htab,
{ {
int stub_align = 1 << htab->params->plt_stub_align; int stub_align = 1 << htab->params->plt_stub_align;
unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off); unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
bfd_vma stub_off = stub_entry->stub_sec->size; bfd_vma stub_off = stub_entry->group->stub_sec->size;
if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align) if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
> ((stub_size - 1) & -stub_align)) > ((stub_size - 1) & -stub_align))
@ -10300,7 +10300,7 @@ build_plt_stub (struct ppc_link_hash_table *htab,
to = (glinkoff to = (glinkoff
+ htab->glink->output_offset + htab->glink->output_offset
+ htab->glink->output_section->vma); + htab->glink->output_section->vma);
from = (p - stub_entry->stub_sec->contents from = (p - stub_entry->group->stub_sec->contents
+ 4 * (ALWAYS_EMIT_R2SAVE + 4 * (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save) || stub_entry->stub_type == ppc_stub_plt_call_r2save)
+ 4 * (PPC_HA (offset) != 0) + 4 * (PPC_HA (offset) != 0)
@ -10308,8 +10308,8 @@ build_plt_stub (struct ppc_link_hash_table *htab,
!= PPC_HA (offset)) != PPC_HA (offset))
+ 4 * (plt_static_chain != 0) + 4 * (plt_static_chain != 0)
+ 20 + 20
+ stub_entry->stub_sec->output_offset + stub_entry->group->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma); + stub_entry->group->stub_sec->output_section->vma);
cmp_branch_off = to - from; cmp_branch_off = to - from;
use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26); use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
} }
@ -10522,7 +10522,7 @@ get_r2off (struct bfd_link_info *info,
struct ppc_stub_hash_entry *stub_entry) struct ppc_stub_hash_entry *stub_entry)
{ {
struct ppc_link_hash_table *htab = ppc_hash_table (info); struct ppc_link_hash_table *htab = ppc_hash_table (info);
bfd_vma r2off = htab->stub_group[stub_entry->target_section->id].toc_off; bfd_vma r2off = htab->sec_info[stub_entry->target_section->id].toc_off;
if (r2off == 0) if (r2off == 0)
{ {
@ -10547,7 +10547,7 @@ get_r2off (struct bfd_link_info *info,
r2off = bfd_get_64 (opd->owner, buf); r2off = bfd_get_64 (opd->owner, buf);
r2off -= elf_gp (info->output_bfd); r2off -= elf_gp (info->output_bfd);
} }
r2off -= htab->stub_group[stub_entry->id_sec->id].toc_off; r2off -= htab->sec_info[stub_entry->group->link_sec->id].toc_off;
return r2off; return r2off;
} }
@ -10574,8 +10574,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
return FALSE; return FALSE;
/* Make a note of the offset within the stubs for this entry. */ /* Make a note of the offset within the stubs for this entry. */
stub_entry->stub_offset = stub_entry->stub_sec->size; stub_entry->stub_offset = stub_entry->group->stub_sec->size;
loc = stub_entry->stub_sec->contents + stub_entry->stub_offset; loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset;
htab->stub_count[stub_entry->stub_type - 1] += 1; htab->stub_count[stub_entry->stub_type - 1] += 1;
switch (stub_entry->stub_type) switch (stub_entry->stub_type)
@ -10591,8 +10591,8 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
/* And this is where we are coming from. */ /* And this is where we are coming from. */
off -= (stub_entry->stub_offset off -= (stub_entry->stub_offset
+ stub_entry->stub_sec->output_offset + stub_entry->group->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma); + stub_entry->group->stub_sec->output_section->vma);
size = 4; size = 4;
if (stub_entry->stub_type == ppc_stub_long_branch_r2off) if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
@ -10631,10 +10631,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (info->emitrelocations) if (info->emitrelocations)
{ {
r = get_relocs (stub_entry->stub_sec, 1); r = get_relocs (stub_entry->group->stub_sec, 1);
if (r == NULL) if (r == NULL)
return FALSE; return FALSE;
r->r_offset = loc - stub_entry->stub_sec->contents; r->r_offset = loc - stub_entry->group->stub_sec->contents;
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
r->r_addend = dest; r->r_addend = dest;
if (stub_entry->h != NULL) if (stub_entry->h != NULL)
@ -10741,7 +10741,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
off = (dest off = (dest
- elf_gp (htab->brlt->output_section->owner) - elf_gp (htab->brlt->output_section->owner)
- htab->stub_group[stub_entry->id_sec->id].toc_off); - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{ {
@ -10755,10 +10755,10 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (info->emitrelocations) if (info->emitrelocations)
{ {
r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0)); r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0));
if (r == NULL) if (r == NULL)
return FALSE; return FALSE;
r[0].r_offset = loc - stub_entry->stub_sec->contents; r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
if (bfd_big_endian (info->output_bfd)) if (bfd_big_endian (info->output_bfd))
r[0].r_offset += 2; r[0].r_offset += 2;
if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
@ -10847,11 +10847,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh); struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
/* If the old-ABI "dot-symbol" is undefined make it weak so /* If the old-ABI "dot-symbol" is undefined make it weak so
we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. */
FIXME: We used to define the symbol on one of the call
stubs instead, which is why we test symbol section id
against htab->top_id in various places. Likely all
these checks could now disappear. */
if (fh->elf.root.type == bfd_link_hash_undefined) if (fh->elf.root.type == bfd_link_hash_undefined)
fh->elf.root.type = bfd_link_hash_undefweak; fh->elf.root.type = bfd_link_hash_undefweak;
/* Stop undo_symbol_twiddle changing it back to undefined. */ /* Stop undo_symbol_twiddle changing it back to undefined. */
@ -10895,7 +10891,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
off = (dest off = (dest
- elf_gp (plt->output_section->owner) - elf_gp (plt->output_section->owner)
- htab->stub_group[stub_entry->id_sec->id].toc_off); - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{ {
@ -10913,15 +10909,15 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
{ {
unsigned pad = plt_stub_pad (htab, stub_entry, off); unsigned pad = plt_stub_pad (htab, stub_entry, off);
stub_entry->stub_sec->size += pad; stub_entry->group->stub_sec->size += pad;
stub_entry->stub_offset = stub_entry->stub_sec->size; stub_entry->stub_offset = stub_entry->group->stub_sec->size;
loc += pad; loc += pad;
} }
r = NULL; r = NULL;
if (info->emitrelocations) if (info->emitrelocations)
{ {
r = get_relocs (stub_entry->stub_sec, r = get_relocs (stub_entry->group->stub_sec,
((PPC_HA (off) != 0) ((PPC_HA (off) != 0)
+ (htab->opd_abi + (htab->opd_abi
? 2 + (htab->params->plt_static_chain ? 2 + (htab->params->plt_static_chain
@ -10929,7 +10925,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
: 1))); : 1)));
if (r == NULL) if (r == NULL)
return FALSE; return FALSE;
r[0].r_offset = loc - stub_entry->stub_sec->contents; r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
if (bfd_big_endian (info->output_bfd)) if (bfd_big_endian (info->output_bfd))
r[0].r_offset += 2; r[0].r_offset += 2;
r[0].r_addend = dest; r[0].r_addend = dest;
@ -10949,7 +10945,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
return FALSE; return FALSE;
} }
stub_entry->stub_sec->size += size; stub_entry->group->stub_sec->size += size;
if (htab->params->emit_stub_syms) if (htab->params->emit_stub_syms)
{ {
@ -10977,7 +10973,7 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
if (h->root.type == bfd_link_hash_new) if (h->root.type == bfd_link_hash_new)
{ {
h->root.type = bfd_link_hash_defined; h->root.type = bfd_link_hash_defined;
h->root.u.def.section = stub_entry->stub_sec; h->root.u.def.section = stub_entry->group->stub_sec;
h->root.u.def.value = stub_entry->stub_offset; h->root.u.def.value = stub_entry->stub_offset;
h->ref_regular = 1; h->ref_regular = 1;
h->def_regular = 1; h->def_regular = 1;
@ -11027,20 +11023,20 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
off += (plt->output_offset off += (plt->output_offset
+ plt->output_section->vma + plt->output_section->vma
- elf_gp (plt->output_section->owner) - elf_gp (plt->output_section->owner)
- htab->stub_group[stub_entry->id_sec->id].toc_off); - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
size = plt_stub_size (htab, stub_entry, off); size = plt_stub_size (htab, stub_entry, off);
if (htab->params->plt_stub_align) if (htab->params->plt_stub_align)
size += plt_stub_pad (htab, stub_entry, off); size += plt_stub_pad (htab, stub_entry, off);
if (info->emitrelocations) if (info->emitrelocations)
{ {
stub_entry->stub_sec->reloc_count stub_entry->group->stub_sec->reloc_count
+= ((PPC_HA (off) != 0) += ((PPC_HA (off) != 0)
+ (htab->opd_abi + (htab->opd_abi
? 2 + (htab->params->plt_static_chain ? 2 + (htab->params->plt_static_chain
&& PPC_HA (off + 16) == PPC_HA (off)) && PPC_HA (off + 16) == PPC_HA (off))
: 1)); : 1));
stub_entry->stub_sec->flags |= SEC_RELOC; stub_entry->group->stub_sec->flags |= SEC_RELOC;
} }
} }
else else
@ -11053,9 +11049,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
off = (stub_entry->target_value off = (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);
off -= (stub_entry->stub_sec->size off -= (stub_entry->group->stub_sec->size
+ stub_entry->stub_sec->output_offset + stub_entry->group->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma); + stub_entry->group->stub_sec->output_section->vma);
/* Reset the stub type from the plt variant in case we now /* Reset the stub type from the plt variant in case we now
can reach with a shorter stub. */ can reach with a shorter stub. */
@ -11118,12 +11114,13 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
+ htab->brlt->output_offset + htab->brlt->output_offset
+ htab->brlt->output_section->vma + htab->brlt->output_section->vma
- elf_gp (htab->brlt->output_section->owner) - elf_gp (htab->brlt->output_section->owner)
- htab->stub_group[stub_entry->id_sec->id].toc_off); - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (info->emitrelocations) if (info->emitrelocations)
{ {
stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0); stub_entry->group->stub_sec->reloc_count
stub_entry->stub_sec->flags |= SEC_RELOC; += 1 + (PPC_HA (off) != 0);
stub_entry->group->stub_sec->flags |= SEC_RELOC;
} }
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
@ -11146,12 +11143,12 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
} }
else if (info->emitrelocations) else if (info->emitrelocations)
{ {
stub_entry->stub_sec->reloc_count += 1; stub_entry->group->stub_sec->reloc_count += 1;
stub_entry->stub_sec->flags |= SEC_RELOC; stub_entry->group->stub_sec->flags |= SEC_RELOC;
} }
} }
stub_entry->stub_sec->size += size; stub_entry->group->stub_sec->size += size;
return TRUE; return TRUE;
} }
@ -11162,57 +11159,22 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
int int
ppc64_elf_setup_section_lists (struct bfd_link_info *info) ppc64_elf_setup_section_lists (struct bfd_link_info *info)
{ {
bfd *input_bfd; unsigned int id;
unsigned int top_id, top_index, id;
asection *section;
asection **input_list;
bfd_size_type amt; bfd_size_type amt;
struct ppc_link_hash_table *htab = ppc_hash_table (info); struct ppc_link_hash_table *htab = ppc_hash_table (info);
if (htab == NULL) if (htab == NULL)
return -1; return -1;
/* Find the top input section id. */ htab->sec_info_arr_size = bfd_get_next_section_id ();
for (input_bfd = info->input_bfds, top_id = 3; amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size);
input_bfd != NULL; htab->sec_info = bfd_zmalloc (amt);
input_bfd = input_bfd->link.next) if (htab->sec_info == NULL)
{
for (section = input_bfd->sections;
section != NULL;
section = section->next)
{
if (top_id < section->id)
top_id = section->id;
}
}
htab->top_id = top_id;
amt = sizeof (struct map_stub) * (top_id + 1);
htab->stub_group = bfd_zmalloc (amt);
if (htab->stub_group == NULL)
return -1; return -1;
/* Set toc_off for com, und, abs and ind sections. */ /* Set toc_off for com, und, abs and ind sections. */
for (id = 0; id < 3; id++) for (id = 0; id < 3; id++)
htab->stub_group[id].toc_off = TOC_BASE_OFF; htab->sec_info[id].toc_off = TOC_BASE_OFF;
/* We can't use output_bfd->section_count here to find the top output
section index as some sections may have been removed, and
strip_excluded_output_sections doesn't renumber the indices. */
for (section = info->output_bfd->sections, top_index = 0;
section != NULL;
section = section->next)
{
if (top_index < section->index)
top_index = section->index;
}
htab->top_index = top_index;
amt = sizeof (asection *) * (top_index + 1);
input_list = bfd_zmalloc (amt);
htab->input_list = input_list;
if (input_list == NULL)
return -1;
return 1; return 1;
} }
@ -11761,15 +11723,13 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
return FALSE; return FALSE;
if ((isec->output_section->flags & SEC_CODE) != 0 if ((isec->output_section->flags & SEC_CODE) != 0
&& isec->output_section->index <= htab->top_index) && isec->output_section->id < htab->sec_info_arr_size)
{ {
asection **list = htab->input_list + isec->output_section->index;
/* Steal the link_sec pointer for our list. */
#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
/* This happens to make the list in reverse order, /* This happens to make the list in reverse order,
which is what we want. */ which is what we want. */
PREV_SEC (isec) = *list; htab->sec_info[isec->id].u.list
*list = isec; = htab->sec_info[isec->output_section->id].u.list;
htab->sec_info[isec->output_section->id].u.list = isec;
} }
if (htab->multi_toc_needed) if (htab->multi_toc_needed)
@ -11793,7 +11753,7 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec)
htab->toc_curr = elf_gp (isec->owner); htab->toc_curr = elf_gp (isec->owner);
} }
htab->stub_group[isec->id].toc_off = htab->toc_curr; htab->sec_info[isec->id].toc_off = htab->toc_curr;
return TRUE; return TRUE;
} }
@ -11815,8 +11775,8 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
if (i->has_toc_reloc) if (i->has_toc_reloc)
{ {
if (toc_off == 0) if (toc_off == 0)
toc_off = htab->stub_group[i->id].toc_off; toc_off = htab->sec_info[i->id].toc_off;
else if (toc_off != htab->stub_group[i->id].toc_off) else if (toc_off != htab->sec_info[i->id].toc_off)
return FALSE; return FALSE;
} }
@ -11824,14 +11784,14 @@ check_pasted_section (struct bfd_link_info *info, const char *name)
for (i = o->map_head.s; i != NULL; i = i->map_head.s) for (i = o->map_head.s; i != NULL; i = i->map_head.s)
if (i->makes_toc_func_call) if (i->makes_toc_func_call)
{ {
toc_off = htab->stub_group[i->id].toc_off; toc_off = htab->sec_info[i->id].toc_off;
break; break;
} }
/* Make sure the whole pasted function uses the same toc offset. */ /* Make sure the whole pasted function uses the same toc offset. */
if (toc_off != 0) if (toc_off != 0)
for (i = o->map_head.s; i != NULL; i = i->map_head.s) for (i = o->map_head.s; i != NULL; i = i->map_head.s)
htab->stub_group[i->id].toc_off = toc_off; htab->sec_info[i->id].toc_off = toc_off;
} }
return TRUE; return TRUE;
} }
@ -11850,15 +11810,20 @@ ppc64_elf_check_init_fini (struct bfd_link_info *info)
_init and _fini functions into multiple parts. Putting a stub in _init and _fini functions into multiple parts. Putting a stub in
the middle of a function is not a good idea. */ the middle of a function is not a good idea. */
static void static bfd_boolean
group_sections (struct ppc_link_hash_table *htab, group_sections (struct bfd_link_info *info,
bfd_size_type stub_group_size, bfd_size_type stub_group_size,
bfd_boolean stubs_always_before_branch) bfd_boolean stubs_always_before_branch)
{ {
asection **list; struct ppc_link_hash_table *htab;
asection *osec;
bfd_size_type stub14_group_size; bfd_size_type stub14_group_size;
bfd_boolean suppress_size_errors; bfd_boolean suppress_size_errors;
htab = ppc_hash_table (info);
if (htab == NULL)
return FALSE;
suppress_size_errors = FALSE; suppress_size_errors = FALSE;
stub14_group_size = stub_group_size >> 10; stub14_group_size = stub_group_size >> 10;
if (stub_group_size == 1) if (stub_group_size == 1)
@ -11877,10 +11842,14 @@ group_sections (struct ppc_link_hash_table *htab,
suppress_size_errors = TRUE; suppress_size_errors = TRUE;
} }
list = htab->input_list + htab->top_index; for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next)
do
{ {
asection *tail = *list; asection *tail;
if (osec->id >= htab->sec_info_arr_size)
continue;
tail = htab->sec_info[osec->id].u.list;
while (tail != NULL) while (tail != NULL)
{ {
asection *curr; asection *curr;
@ -11888,6 +11857,7 @@ group_sections (struct ppc_link_hash_table *htab,
bfd_size_type total; bfd_size_type total;
bfd_boolean big_sec; bfd_boolean big_sec;
bfd_vma curr_toc; bfd_vma curr_toc;
struct map_stub *group;
curr = tail; curr = tail;
total = tail->size; total = tail->size;
@ -11897,14 +11867,14 @@ group_sections (struct ppc_link_hash_table *htab,
if (big_sec && !suppress_size_errors) if (big_sec && !suppress_size_errors)
(*_bfd_error_handler) (_("%B section %A exceeds stub group size"), (*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
tail->owner, tail); tail->owner, tail);
curr_toc = htab->stub_group[tail->id].toc_off; curr_toc = htab->sec_info[tail->id].toc_off;
while ((prev = PREV_SEC (curr)) != NULL while ((prev = htab->sec_info[curr->id].u.list) != NULL
&& ((total += curr->output_offset - prev->output_offset) && ((total += curr->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL < (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch && ppc64_elf_section_data (prev)->has_14bit_branch
? stub14_group_size : stub_group_size)) ? stub14_group_size : stub_group_size))
&& htab->stub_group[prev->id].toc_off == curr_toc) && htab->sec_info[prev->id].toc_off == curr_toc)
curr = prev; curr = prev;
/* OK, the size from the start of CURR to the end is less /* OK, the size from the start of CURR to the end is less
@ -11917,11 +11887,16 @@ group_sections (struct ppc_link_hash_table *htab,
only break if stubs added make the total size more than only break if stubs added make the total size more than
2^25, ie. for the default stub_group_size, if stubs total 2^25, ie. for the default stub_group_size, if stubs total
more than 2097152 bytes, or nearly 75000 plt call stubs. */ more than 2097152 bytes, or nearly 75000 plt call stubs. */
group = bfd_alloc (curr->owner, sizeof (*group));
if (group == NULL)
return FALSE;
group->link_sec = curr;
group->stub_sec = NULL;
do do
{ {
prev = PREV_SEC (tail); prev = htab->sec_info[tail->id].u.list;
/* Set up this stub group. */ /* Set up this stub group. */
htab->stub_group[tail->id].link_sec = curr; htab->sec_info[tail->id].u.group = group;
} }
while (tail != curr && (tail = prev) != NULL); while (tail != curr && (tail = prev) != NULL);
@ -11938,19 +11913,17 @@ group_sections (struct ppc_link_hash_table *htab,
< (ppc64_elf_section_data (prev) != NULL < (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch && ppc64_elf_section_data (prev)->has_14bit_branch
? stub14_group_size : stub_group_size)) ? stub14_group_size : stub_group_size))
&& htab->stub_group[prev->id].toc_off == curr_toc) && htab->sec_info[prev->id].toc_off == curr_toc)
{ {
tail = prev; tail = prev;
prev = PREV_SEC (tail); prev = htab->sec_info[tail->id].u.list;
htab->stub_group[tail->id].link_sec = curr; htab->sec_info[tail->id].u.group = group;
} }
} }
tail = prev; tail = prev;
} }
} }
while (list-- != htab->input_list); return TRUE;
free (htab->input_list);
#undef PREV_SEC
} }
static const unsigned char glink_eh_frame_cie[] = static const unsigned char glink_eh_frame_cie[] =
@ -12055,7 +12028,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
else else
stub_group_size = htab->params->group_size; stub_group_size = htab->params->group_size;
group_sections (htab, stub_group_size, stubs_always_before_branch); if (!group_sections (info, stub_group_size, stubs_always_before_branch))
return FALSE;
while (1) while (1)
{ {
@ -12258,8 +12232,8 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
fact a call needing a TOC adjustment. */ fact a call needing a TOC adjustment. */
if (code_sec != NULL if (code_sec != NULL
&& code_sec->output_section != NULL && code_sec->output_section != NULL
&& (htab->stub_group[code_sec->id].toc_off && (htab->sec_info[code_sec->id].toc_off
!= htab->stub_group[section->id].toc_off) != htab->sec_info[section->id].toc_off)
&& (code_sec->has_toc_reloc && (code_sec->has_toc_reloc
|| code_sec->makes_toc_func_call)) || code_sec->makes_toc_func_call))
stub_type = ppc_stub_long_branch_r2off; stub_type = ppc_stub_long_branch_r2off;
@ -12299,7 +12273,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
stub_type = ppc_stub_plt_call_r2save; stub_type = ppc_stub_plt_call_r2save;
/* Support for grouping stub sections. */ /* Support for grouping stub sections. */
id_sec = htab->stub_group[section->id].link_sec; id_sec = htab->sec_info[section->id].u.group->link_sec;
/* Get the name of this stub. */ /* Get the name of this stub. */
stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela); stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
@ -13234,8 +13208,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (h != NULL && &h->elf == htab->elf.hgot) if (h != NULL && &h->elf == htab->elf.hgot)
{ {
relocation = (TOCstart relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
+ htab->stub_group[input_section->id].toc_off);
sec = bfd_abs_section_ptr; sec = bfd_abs_section_ptr;
unresolved_reloc = FALSE; unresolved_reloc = FALSE;
} }
@ -13943,8 +13916,8 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Munge up the value and addend so that we call the stub /* Munge up the value and addend so that we call the stub
rather than the procedure directly. */ rather than the procedure directly. */
relocation = (stub_entry->stub_offset relocation = (stub_entry->stub_offset
+ stub_entry->stub_sec->output_offset + stub_entry->group->stub_sec->output_offset
+ stub_entry->stub_sec->output_section->vma); + stub_entry->group->stub_sec->output_section->vma);
addend = 0; addend = 0;
reloc_dest = DEST_STUB; reloc_dest = DEST_STUB;
@ -14241,7 +14214,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
abort (); abort ();
relocation = got->output_section->vma + got->output_offset + off; relocation = got->output_section->vma + got->output_offset + off;
addend = -(TOCstart + htab->stub_group[input_section->id].toc_off); addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
} }
break; break;
@ -14282,11 +14255,11 @@ ppc64_elf_relocate_section (bfd *output_bfd,
/* Relocation value is TOC base. */ /* Relocation value is TOC base. */
relocation = TOCstart; relocation = TOCstart;
if (r_symndx == STN_UNDEF) if (r_symndx == STN_UNDEF)
relocation += htab->stub_group[input_section->id].toc_off; relocation += htab->sec_info[input_section->id].toc_off;
else if (unresolved_reloc) else if (unresolved_reloc)
; ;
else if (sec != NULL && sec->id <= htab->top_id) else if (sec != NULL && sec->id < htab->sec_info_arr_size)
relocation += htab->stub_group[sec->id].toc_off; relocation += htab->sec_info[sec->id].toc_off;
else else
unresolved_reloc = TRUE; unresolved_reloc = TRUE;
goto dodyn; goto dodyn;
@ -14301,7 +14274,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_TOC16_DS: case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_LO_DS: case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_HA: case R_PPC64_TOC16_HA:
addend -= TOCstart + htab->stub_group[input_section->id].toc_off; addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
break; break;
/* Relocate against the beginning of the section. */ /* Relocate against the beginning of the section. */

View file

@ -821,13 +821,13 @@ _bfd_generic_new_section_hook (bfd *abfd, asection *newsect)
return TRUE; return TRUE;
} }
static unsigned int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */
/* Initializes a new section. NEWSECT->NAME is already set. */ /* Initializes a new section. NEWSECT->NAME is already set. */
static asection * static asection *
bfd_section_init (bfd *abfd, asection *newsect) bfd_section_init (bfd *abfd, asection *newsect)
{ {
static unsigned int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */
newsect->id = section_id; newsect->id = section_id;
newsect->index = abfd->section_count; newsect->index = abfd->section_count;
newsect->owner = abfd; newsect->owner = abfd;
@ -1273,6 +1273,23 @@ bfd_make_section (bfd *abfd, const char *name)
return bfd_make_section_with_flags (abfd, name, 0); return bfd_make_section_with_flags (abfd, name, 0);
} }
/*
FUNCTION
bfd_get_next_section_id
SYNOPSIS
int bfd_get_next_section_id (void);
DESCRIPTION
Returns the id that the next section created will have.
*/
int
bfd_get_next_section_id (void)
{
return section_id;
}
/* /*
FUNCTION FUNCTION
bfd_set_section_flags bfd_set_section_flags