* elf32-hppa.c (struct elf32_hppa_link_hash_table): Add

bfd_count top_index, input_list, all_local_syms.
	(elf32_hppa_setup_section_lists): New function, split from
	elf32_hppa_size_stubs.
	(elf32_hppa_next_input_section): Likewise.
	(group_sections): Likewise.
	(get_local_syms): Likewise.
	(elf32_hppa_size_stubs): Adjust for split out functions.  Look for
	stubs on undefined syms too.
	(elf32_hppa_set_gp): Use bfd_link_hash* instead of elf_link_hash*.
	Only access htab elf fields when we have and elf hash table.
	* elf32-hppa.h (elf32_hppa_setup_section_lists): Declare.
	(elf32_hppa_next_input_section): Declare.
This commit is contained in:
Alan Modra 2002-05-04 02:06:22 +00:00
parent e58a75dc2d
commit b4655ea917
3 changed files with 224 additions and 123 deletions

View file

@ -1,3 +1,19 @@
2002-05-04 Alan Modra <amodra@bigpond.net.au>
* elf32-hppa.c (struct elf32_hppa_link_hash_table): Add
bfd_count top_index, input_list, all_local_syms.
(elf32_hppa_setup_section_lists): New function, split from
elf32_hppa_size_stubs.
(elf32_hppa_next_input_section): Likewise.
(group_sections): Likewise.
(get_local_syms): Likewise.
(elf32_hppa_size_stubs): Adjust for split out functions. Look for
stubs on undefined syms too.
(elf32_hppa_set_gp): Use bfd_link_hash* instead of elf_link_hash*.
Only access htab elf fields when we have and elf hash table.
* elf32-hppa.h (elf32_hppa_setup_section_lists): Declare.
(elf32_hppa_next_input_section): Declare.
2002-05-04 Bob Byrnes <byrnes@curl.com> 2002-05-04 Bob Byrnes <byrnes@curl.com>
* opncls.c (_bfd_new_bfd_contained_in): Check return value of * opncls.c (_bfd_new_bfd_contained_in): Check return value of

View file

@ -236,6 +236,12 @@ struct elf32_hppa_link_hash_table {
asection *stub_sec; asection *stub_sec;
} *stub_group; } *stub_group;
/* Assorted information used by elf32_hppa_size_stubs. */
unsigned int bfd_count;
int top_index;
asection **input_list;
Elf_Internal_Sym **all_local_syms;
/* Short-cuts to get to dynamic linker sections. */ /* Short-cuts to get to dynamic linker sections. */
asection *sgot; asection *sgot;
asection *srelgot; asection *srelgot;
@ -359,6 +365,12 @@ static boolean clobber_millicode_symbols
static boolean elf32_hppa_size_dynamic_sections static boolean elf32_hppa_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *)); PARAMS ((bfd *, struct bfd_link_info *));
static void group_sections
PARAMS ((struct elf32_hppa_link_hash_table *, bfd_size_type, boolean));
static int get_local_syms
PARAMS ((bfd *, bfd *, struct bfd_link_info *));
static boolean elf32_hppa_final_link static boolean elf32_hppa_final_link
PARAMS ((bfd *, struct bfd_link_info *)); PARAMS ((bfd *, struct bfd_link_info *));
@ -2544,57 +2556,25 @@ elf32_hppa_size_dynamic_sections (output_bfd, info)
/* External entry points for sizing and building linker stubs. */ /* External entry points for sizing and building linker stubs. */
/* Determine and set the size of the stub section for a final link. /* Set up various things so that we can make a list of input sections
for each output section included in the link. Returns -1 on error,
0 when no stubs will be needed, and 1 on success. */
The basic idea here is to examine all the relocations looking for int
PC-relative calls to a target that is unreachable with a "bl" elf32_hppa_setup_section_lists (output_bfd, info)
instruction. */
boolean
elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
add_stub_section, layout_sections_again)
bfd *output_bfd; bfd *output_bfd;
bfd *stub_bfd;
struct bfd_link_info *info; struct bfd_link_info *info;
boolean multi_subspace;
bfd_signed_vma group_size;
asection * (*add_stub_section) PARAMS ((const char *, asection *));
void (*layout_sections_again) PARAMS ((void));
{ {
bfd *input_bfd; bfd *input_bfd;
unsigned int bfd_count;
int top_id, top_index;
asection *section; asection *section;
asection **input_list, **list; asection **input_list, **list;
Elf_Internal_Sym *local_syms, **all_local_syms;
unsigned int bfd_indx, bfd_count;
int top_id, top_index;
struct elf32_hppa_link_hash_table *htab;
bfd_size_type stub_group_size;
boolean stubs_always_before_branch;
boolean stub_changed = 0;
boolean ret = 0;
bfd_size_type amt; bfd_size_type amt;
struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
htab = hppa_link_hash_table (info); if (htab->elf.root.creator->flavour != bfd_target_elf_flavour)
return 0;
/* Stash our params away. */
htab->stub_bfd = stub_bfd;
htab->multi_subspace = multi_subspace;
htab->add_stub_section = add_stub_section;
htab->layout_sections_again = layout_sections_again;
stubs_always_before_branch = group_size < 0;
if (group_size < 0)
stub_group_size = -group_size;
else
stub_group_size = group_size;
if (stub_group_size == 1)
{
/* Default values. */
stub_group_size = 7680000;
if (htab->has_17bit_branch || htab->multi_subspace)
stub_group_size = 240000;
if (htab->has_12bit_branch)
stub_group_size = 7500;
}
/* Count the number of input BFDs and find the top input section id. */ /* Count the number of input BFDs and find the top input section id. */
for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0; for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
@ -2610,16 +2590,14 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
top_id = section->id; top_id = section->id;
} }
} }
htab->bfd_count = bfd_count;
amt = sizeof (struct map_stub) * (top_id + 1); amt = sizeof (struct map_stub) * (top_id + 1);
htab->stub_group = (struct map_stub *) bfd_zmalloc (amt); htab->stub_group = (struct map_stub *) bfd_zmalloc (amt);
if (htab->stub_group == NULL) if (htab->stub_group == NULL)
return false; return -1;
/* Make a list of input sections for each output section included in /* We can't use output_bfd->section_count here to find the top output
the link.
We can't use output_bfd->section_count here to find the top output
section index as some sections may have been removed, and section index as some sections may have been removed, and
_bfd_strip_section_from_output doesn't renumber the indices. */ _bfd_strip_section_from_output doesn't renumber the indices. */
for (section = output_bfd->sections, top_index = 0; for (section = output_bfd->sections, top_index = 0;
@ -2630,10 +2608,12 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
top_index = section->index; top_index = section->index;
} }
htab->top_index = top_index;
amt = sizeof (asection *) * (top_index + 1); amt = sizeof (asection *) * (top_index + 1);
input_list = (asection **) bfd_malloc (amt); input_list = (asection **) bfd_malloc (amt);
htab->input_list = input_list;
if (input_list == NULL) if (input_list == NULL)
return false; return -1;
/* For sections we aren't interested in, mark their entries with a /* For sections we aren't interested in, mark their entries with a
value we can check later. */ value we can check later. */
@ -2650,40 +2630,50 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
input_list[section->index] = NULL; input_list[section->index] = NULL;
} }
/* Now actually build the lists. */ return 1;
for (input_bfd = info->input_bfds; }
input_bfd != NULL;
input_bfd = input_bfd->link_next) /* The linker repeatedly calls this function for each input section,
in the order that input sections are linked into output sections.
Build lists of input sections to determine groupings between which
we may insert linker stubs. */
void
elf32_hppa_next_input_section (info, isec)
struct bfd_link_info *info;
asection *isec;
{
struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
if (isec->output_section->index <= htab->top_index)
{ {
for (section = input_bfd->sections; asection **list = htab->input_list + isec->output_section->index;
section != NULL; if (*list != bfd_abs_section_ptr)
section = section->next)
{ {
if (section->output_section != NULL /* Steal the link_sec pointer for our list. */
&& section->output_section->owner == output_bfd
&& section->output_section->index <= top_index)
{
list = input_list + section->output_section->index;
if (*list != bfd_abs_section_ptr)
{
/* Steal the link_sec pointer for our list. */
#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) #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 (section) = *list; PREV_SEC (isec) = *list;
*list = section; *list = isec;
}
}
} }
} }
}
/* See whether we can group stub sections together. Grouping stub /* See whether we can group stub sections together. Grouping stub
sections may result in fewer stubs. More importantly, we need to sections may result in fewer stubs. More importantly, we need to
put all .init* and .fini* stubs at the beginning of the .init or put all .init* and .fini* stubs at the beginning of the .init or
.fini output sections respectively, because glibc splits the .fini output sections respectively, because glibc splits the
_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. */
list = input_list + top_index;
static void
group_sections (htab, stub_group_size, stubs_always_before_branch)
struct elf32_hppa_link_hash_table *htab;
bfd_size_type stub_group_size;
boolean stubs_always_before_branch;
{
asection **list = htab->input_list + htab->top_index;
do do
{ {
asection *tail = *list; asection *tail = *list;
@ -2743,22 +2733,39 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
tail = prev; tail = prev;
} }
} }
while (list-- != input_list); while (list-- != htab->input_list);
free (input_list); free (htab->input_list);
#undef PREV_SEC #undef PREV_SEC
}
/* Read in all local syms for all input bfds, and create hash entries
for export stubs if we are building a multi-subspace shared lib.
Returns -1 on error, 1 if export stubs created, 0 otherwise. */
static int
get_local_syms (output_bfd, input_bfd, info)
bfd *output_bfd;
bfd *input_bfd;
struct bfd_link_info *info;
{
unsigned int bfd_indx;
Elf_Internal_Sym *local_syms, **all_local_syms;
int stub_changed = 0;
struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
/* We want to read in symbol extension records only once. To do this /* We want to read in symbol extension records only once. To do this
we need to read in the local symbols in parallel and save them for we need to read in the local symbols in parallel and save them for
later use; so hold pointers to the local symbols in an array. */ later use; so hold pointers to the local symbols in an array. */
amt = sizeof (Elf_Internal_Sym *) * bfd_count; bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt); all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
htab->all_local_syms = all_local_syms;
if (all_local_syms == NULL) if (all_local_syms == NULL)
return false; return -1;
/* Walk over all the input BFDs, swapping in local symbols. /* Walk over all the input BFDs, swapping in local symbols.
If we are creating a shared library, create hash entries for the If we are creating a shared library, create hash entries for the
export stubs. */ export stubs. */
for (input_bfd = info->input_bfds, bfd_indx = 0; for (bfd_indx = 0;
input_bfd != NULL; input_bfd != NULL;
input_bfd = input_bfd->link_next, bfd_indx++) input_bfd = input_bfd->link_next, bfd_indx++)
{ {
@ -2780,21 +2787,21 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
sec_size *= sizeof (Elf_Internal_Sym); sec_size *= sizeof (Elf_Internal_Sym);
local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size); local_syms = (Elf_Internal_Sym *) bfd_malloc (sec_size);
if (local_syms == NULL) if (local_syms == NULL)
goto error_ret_free_local; return -1;
all_local_syms[bfd_indx] = local_syms; all_local_syms[bfd_indx] = local_syms;
sec_size = symtab_hdr->sh_info; sec_size = symtab_hdr->sh_info;
sec_size *= sizeof (Elf32_External_Sym); sec_size *= sizeof (Elf32_External_Sym);
ext_syms = (Elf32_External_Sym *) bfd_malloc (sec_size); ext_syms = (Elf32_External_Sym *) bfd_malloc (sec_size);
if (ext_syms == NULL) if (ext_syms == NULL)
goto error_ret_free_local; return -1;
if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0 if (bfd_seek (input_bfd, symtab_hdr->sh_offset, SEEK_SET) != 0
|| bfd_bread ((PTR) ext_syms, sec_size, input_bfd) != sec_size) || bfd_bread ((PTR) ext_syms, sec_size, input_bfd) != sec_size)
{ {
error_ret_free_ext_syms: error_ret_free_ext_syms:
free (ext_syms); free (ext_syms);
goto error_ret_free_local; return -1;
} }
shndx_buf = NULL; shndx_buf = NULL;
@ -2877,7 +2884,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
{ {
stub_entry = hppa_add_stub (stub_name, sec, htab); stub_entry = hppa_add_stub (stub_name, sec, htab);
if (!stub_entry) if (!stub_entry)
goto error_ret_free_local; return -1;
stub_entry->target_value = hash->elf.root.u.def.value; stub_entry->target_value = hash->elf.root.u.def.value;
stub_entry->target_section = hash->elf.root.u.def.section; stub_entry->target_section = hash->elf.root.u.def.section;
@ -2896,8 +2903,74 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
} }
} }
return stub_changed;
}
/* Determine and set the size of the stub section for a final link.
The basic idea here is to examine all the relocations looking for
PC-relative calls to a target that is unreachable with a "bl"
instruction. */
boolean
elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
add_stub_section, layout_sections_again)
bfd *output_bfd;
bfd *stub_bfd;
struct bfd_link_info *info;
boolean multi_subspace;
bfd_signed_vma group_size;
asection * (*add_stub_section) PARAMS ((const char *, asection *));
void (*layout_sections_again) PARAMS ((void));
{
bfd_size_type stub_group_size;
boolean stubs_always_before_branch;
boolean stub_changed;
boolean ret = 0;
struct elf32_hppa_link_hash_table *htab = hppa_link_hash_table (info);
/* Stash our params away. */
htab->stub_bfd = stub_bfd;
htab->multi_subspace = multi_subspace;
htab->add_stub_section = add_stub_section;
htab->layout_sections_again = layout_sections_again;
stubs_always_before_branch = group_size < 0;
if (group_size < 0)
stub_group_size = -group_size;
else
stub_group_size = group_size;
if (stub_group_size == 1)
{
/* Default values. */
stub_group_size = 7680000;
if (htab->has_17bit_branch || htab->multi_subspace)
stub_group_size = 240000;
if (htab->has_12bit_branch)
stub_group_size = 7500;
}
group_sections (htab, stub_group_size, stubs_always_before_branch);
switch (get_local_syms (output_bfd, info->input_bfds, info))
{
default:
if (htab->all_local_syms)
goto error_ret_free_local;
return false;
case 0:
stub_changed = false;
break;
case 1:
stub_changed = true;
break;
}
while (1) while (1)
{ {
bfd *input_bfd;
unsigned int bfd_indx;
asection *stub_sec; asection *stub_sec;
for (input_bfd = info->input_bfds, bfd_indx = 0; for (input_bfd = info->input_bfds, bfd_indx = 0;
@ -2905,13 +2978,15 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
input_bfd = input_bfd->link_next, bfd_indx++) input_bfd = input_bfd->link_next, bfd_indx++)
{ {
Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_hdr;
asection *section;
Elf_Internal_Sym *local_syms;
/* We'll need the symbol table in a second. */ /* We'll need the symbol table in a second. */
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
if (symtab_hdr->sh_info == 0) if (symtab_hdr->sh_info == 0)
continue; continue;
local_syms = all_local_syms[bfd_indx]; local_syms = htab->all_local_syms[bfd_indx];
/* Walk over each section attached to the input bfd. */ /* Walk over each section attached to the input bfd. */
for (section = input_bfd->sections; for (section = input_bfd->sections;
@ -2921,6 +2996,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
Elf_Internal_Shdr *input_rel_hdr; Elf_Internal_Shdr *input_rel_hdr;
Elf32_External_Rela *external_relocs, *erelaend, *erela; Elf32_External_Rela *external_relocs, *erelaend, *erela;
Elf_Internal_Rela *internal_relocs, *irelaend, *irela; Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
bfd_size_type amt;
/* If there aren't any relocs, then there's nothing more /* If there aren't any relocs, then there's nothing more
to do. */ to do. */
@ -3052,19 +3128,9 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
+ sym_sec->output_section->vma); + sym_sec->output_section->vma);
} }
else if (hash->elf.root.type == bfd_link_hash_undefweak) else if (hash->elf.root.type == bfd_link_hash_undefweak)
{ ;
if (! info->shared)
continue;
}
else if (hash->elf.root.type == bfd_link_hash_undefined) else if (hash->elf.root.type == bfd_link_hash_undefined)
{ ;
if (! (info->shared
&& !info->no_undefined
&& (ELF_ST_VISIBILITY (hash->elf.other)
== STV_DEFAULT)
&& hash->elf.type != STT_PARISC_MILLI))
continue;
}
else else
{ {
bfd_set_error (bfd_error_bad_value); bfd_set_error (bfd_error_bad_value);
@ -3114,7 +3180,7 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
stub_entry->stub_type = hppa_stub_long_branch_shared; stub_entry->stub_type = hppa_stub_long_branch_shared;
} }
stub_entry->h = hash; stub_entry->h = hash;
stub_changed = 1; stub_changed = true;
} }
/* We're done with the internal relocs, free them. */ /* We're done with the internal relocs, free them. */
@ -3139,16 +3205,16 @@ elf32_hppa_size_stubs (output_bfd, stub_bfd, info, multi_subspace, group_size,
/* Ask the linker to do its stuff. */ /* Ask the linker to do its stuff. */
(*htab->layout_sections_again) (); (*htab->layout_sections_again) ();
stub_changed = 0; stub_changed = false;
} }
ret = 1; ret = true;
error_ret_free_local: error_ret_free_local:
while (bfd_count-- > 0) while (htab->bfd_count-- > 0)
if (all_local_syms[bfd_count]) if (htab->all_local_syms[htab->bfd_count])
free (all_local_syms[bfd_count]); free (htab->all_local_syms[htab->bfd_count]);
free (all_local_syms); free (htab->all_local_syms);
return ret; return ret;
} }
@ -3161,23 +3227,39 @@ elf32_hppa_set_gp (abfd, info)
bfd *abfd; bfd *abfd;
struct bfd_link_info *info; struct bfd_link_info *info;
{ {
struct bfd_link_hash_entry *h;
asection *sec = NULL;
bfd_vma gp_val = 0;
struct elf32_hppa_link_hash_table *htab; struct elf32_hppa_link_hash_table *htab;
struct elf_link_hash_entry *h;
asection *sec;
bfd_vma gp_val;
htab = hppa_link_hash_table (info); htab = hppa_link_hash_table (info);
h = elf_link_hash_lookup (&htab->elf, "$global$", false, false, false); h = bfd_link_hash_lookup (&htab->elf.root, "$global$", false, false, false);
if (h != NULL if (h != NULL
&& (h->root.type == bfd_link_hash_defined && (h->type == bfd_link_hash_defined
|| h->root.type == bfd_link_hash_defweak)) || h->type == bfd_link_hash_defweak))
{ {
gp_val = h->root.u.def.value; gp_val = h->u.def.value;
sec = h->root.u.def.section; sec = h->u.def.section;
} }
else else
{ {
asection *splt;
asection *sgot;
if (htab->elf.root.creator->flavour == bfd_target_elf_flavour)
{
splt = htab->splt;
sgot = htab->sgot;
}
else
{
/* If we're not elf, look up the output sections in the
hope we may actually find them. */
splt = bfd_get_section_by_name (abfd, ".plt");
sgot = bfd_get_section_by_name (abfd, ".got");
}
/* Choose to point our LTP at, in this order, one of .plt, .got, /* Choose to point our LTP at, in this order, one of .plt, .got,
or .data, if these sections exist. In the case of choosing or .data, if these sections exist. In the case of choosing
.plt try to make the LTP ideal for addressing anywhere in the .plt try to make the LTP ideal for addressing anywhere in the
@ -3186,21 +3268,18 @@ elf32_hppa_set_gp (abfd, info)
if either the .plt or .got is larger than 0x2000. If both if either the .plt or .got is larger than 0x2000. If both
the .plt and .got are smaller than 0x2000, choose the end of the .plt and .got are smaller than 0x2000, choose the end of
the .plt section. */ the .plt section. */
sec = splt;
sec = htab->splt;
if (sec != NULL) if (sec != NULL)
{ {
gp_val = sec->_raw_size; gp_val = sec->_raw_size;
if (gp_val > 0x2000 if (gp_val > 0x2000 || (sgot && sgot->_raw_size > 0x2000))
|| (htab->sgot && htab->sgot->_raw_size > 0x2000))
{ {
gp_val = 0x2000; gp_val = 0x2000;
} }
} }
else else
{ {
gp_val = 0; sec = sgot;
sec = htab->sgot;
if (sec != NULL) if (sec != NULL)
{ {
/* We know we don't have a .plt. If .got is large, /* We know we don't have a .plt. If .got is large,
@ -3217,12 +3296,12 @@ elf32_hppa_set_gp (abfd, info)
if (h != NULL) if (h != NULL)
{ {
h->root.type = bfd_link_hash_defined; h->type = bfd_link_hash_defined;
h->root.u.def.value = gp_val; h->u.def.value = gp_val;
if (sec != NULL) if (sec != NULL)
h->root.u.def.section = sec; h->u.def.section = sec;
else else
h->root.u.def.section = bfd_abs_section_ptr; h->u.def.section = bfd_abs_section_ptr;
} }
} }

View file

@ -36,6 +36,12 @@
#include "libhppa.h" #include "libhppa.h"
#include "elf/hppa.h" #include "elf/hppa.h"
int elf32_hppa_setup_section_lists
PARAMS ((bfd *, struct bfd_link_info *));
void elf32_hppa_next_input_section
PARAMS ((struct bfd_link_info *, asection *));
boolean elf32_hppa_size_stubs boolean elf32_hppa_size_stubs
PARAMS ((bfd *, bfd *, struct bfd_link_info *, boolean, bfd_signed_vma, PARAMS ((bfd *, bfd *, struct bfd_link_info *, boolean, bfd_signed_vma,
asection * (*) PARAMS ((const char *, asection *)), asection * (*) PARAMS ((const char *, asection *)),