This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
resize alpha .plt, .rela.plt, .rela.got sections
- From: Richard Henderson <rth at redhat dot com>
- To: binutils at sources dot redhat dot com
- Date: Sat, 1 Jun 2002 21:00:24 -0700
- Subject: resize alpha .plt, .rela.plt, .rela.got sections
Relaxation was leaving all sorts of garbage in the .plt
sections, and the .rela.got section had relocations for
entries that had been removed.
r~
* elf64-alpha.c (elf64_alpha_relax_with_lituse): Reject undefined
symbols from JSR relaxation.
(elf64_alpha_size_plt_section_1): New.
(elf64_alpha_calc_dynrel_sizes): Split out .rela.got bits ...
(elf64_alpha_size_rela_got_1): ... here.
(elf64_alpha_size_dynamic_sections): Split out .rela.got bits ...
(elf64_alpha_size_rela_got_section): ... here.
(elf64_alpha_size_plt_section): New.
(elf64_alpha_relax_section): Call them.
(elf64_alpha_size_got_sections): Remove output_bfd arg.
(elf64_alpha_finish_dynamic_symbol): Check gotent use_count.
Index: elf64-alpha.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-alpha.c,v
retrieving revision 1.67
diff -c -p -d -r1.67 elf64-alpha.c
*** elf64-alpha.c 2 Jun 2002 02:28:44 -0000 1.67
--- elf64-alpha.c 2 Jun 2002 03:52:35 -0000
*************** static boolean elf64_alpha_calc_got_offs
*** 106,118 ****
PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static void elf64_alpha_calc_got_offsets PARAMS ((struct bfd_link_info *));
static boolean elf64_alpha_size_got_sections
! PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf64_alpha_always_size_sections
PARAMS ((bfd *, struct bfd_link_info *));
static int alpha_dynamic_entries_for_reloc
PARAMS ((int, int, int));
static boolean elf64_alpha_calc_dynrel_sizes
PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
static boolean elf64_alpha_add_symbol_hook
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
const char **, flagword *, asection **, bfd_vma *));
--- 106,126 ----
PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static void elf64_alpha_calc_got_offsets PARAMS ((struct bfd_link_info *));
static boolean elf64_alpha_size_got_sections
! PARAMS ((struct bfd_link_info *));
! static boolean elf64_alpha_size_plt_section
! PARAMS ((struct bfd_link_info *));
! static boolean elf64_alpha_size_plt_section_1
! PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static boolean elf64_alpha_always_size_sections
PARAMS ((bfd *, struct bfd_link_info *));
static int alpha_dynamic_entries_for_reloc
PARAMS ((int, int, int));
static boolean elf64_alpha_calc_dynrel_sizes
PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
+ static boolean elf64_alpha_size_rela_got_section
+ PARAMS ((struct bfd_link_info *));
+ static boolean elf64_alpha_size_rela_got_1
+ PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
static boolean elf64_alpha_add_symbol_hook
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
const char **, flagword *, asection **, bfd_vma *));
*************** elf64_alpha_relax_with_lituse (info, sym
*** 1388,1401 ****
case LITUSE_ALPHA_TLSGD:
case LITUSE_ALPHA_TLSLDM:
{
! /* If not zero, place to jump without needing pv. */
! bfd_vma optdest = elf64_alpha_relax_opt_call (info, symval);
! bfd_vma org = (info->sec->output_section->vma
! + info->sec->output_offset
! + urel->r_offset + 4);
bfd_signed_vma odisp;
odisp = (optdest ? optdest : symval) - org;
if (odisp >= -0x400000 && odisp < 0x400000)
{
Elf_Internal_Rela *xrel;
--- 1396,1420 ----
case LITUSE_ALPHA_TLSGD:
case LITUSE_ALPHA_TLSLDM:
{
! bfd_vma optdest, org;
bfd_signed_vma odisp;
+ /* If this symbol is undefined, we can't relax it to a branch. */
+ if (info->h
+ && (info->h->root.root.type == bfd_link_hash_undefweak
+ || info->h->root.root.type == bfd_link_hash_undefined))
+ {
+ all_optimized = false;
+ break;
+ }
+
+ /* If not zero, place to jump without needing pv. */
+ optdest = elf64_alpha_relax_opt_call (info, symval);
+ org = (info->sec->output_section->vma
+ + info->sec->output_offset
+ + urel->r_offset + 4);
odisp = (optdest ? optdest : symval) - org;
+
if (odisp >= -0x400000 && odisp < 0x400000)
{
Elf_Internal_Rela *xrel;
*************** elf64_alpha_relax_section (abfd, sec, li
*** 2251,2257 ****
}
}
! if (!elf64_alpha_size_got_sections (abfd, link_info))
return false;
if (info.changed_relocs)
--- 2270,2280 ----
}
}
! if (!elf64_alpha_size_plt_section (link_info))
! return false;
! if (!elf64_alpha_size_got_sections (link_info))
! return false;
! if (!elf64_alpha_size_rela_got_section (link_info))
return false;
if (info.changed_relocs)
*************** elf64_alpha_calc_got_offsets (info)
*** 3650,3657 ****
/* Constructs the gots. */
static boolean
! elf64_alpha_size_got_sections (output_bfd, info)
! bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
bfd *i, *got_list, *cur_got_obj = NULL;
--- 3673,3679 ----
/* Constructs the gots. */
static boolean
! elf64_alpha_size_got_sections (info)
struct bfd_link_info *info;
{
bfd *i, *got_list, *cur_got_obj = NULL;
*************** elf64_alpha_size_got_sections (output_bf
*** 3725,3733 ****
return true;
}
static boolean
elf64_alpha_always_size_sections (output_bfd, info)
! bfd *output_bfd;
struct bfd_link_info *info;
{
bfd *i;
--- 3747,3826 ----
return true;
}
+ /* Called from relax_section to rebuild the PLT in light of
+ potential changes in the function's status. */
+
+ static boolean
+ elf64_alpha_size_plt_section (info)
+ struct bfd_link_info *info;
+ {
+ asection *splt, *spltrel;
+ unsigned long entries;
+ bfd *dynobj;
+
+ dynobj = elf_hash_table(info)->dynobj;
+ splt = bfd_get_section_by_name(dynobj, ".plt");
+ if (splt == NULL)
+ return true;
+
+ splt->_raw_size = 0;
+
+ alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ elf64_alpha_size_plt_section_1, splt);
+
+ splt->_cooked_size = splt->_raw_size;
+
+ /* Every plt entry requires a JMP_SLOT relocation. */
+ spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ if (splt->_raw_size)
+ entries = (splt->_raw_size - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+ else
+ entries = 0;
+ spltrel->_raw_size = entries * sizeof (Elf64_External_Rela);
+ spltrel->_cooked_size = spltrel->_raw_size;
+
+ return true;
+ }
+
+ static boolean
+ elf64_alpha_size_plt_section_1 (h, data)
+ struct alpha_elf_link_hash_entry *h;
+ PTR data;
+ {
+ asection *splt = (asection *) data;
+ struct alpha_elf_got_entry *gotent;
+
+ /* If we didn't need an entry before, we still don't. */
+ if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT))
+ return true;
+
+ /* There must still be a LITERAL got entry for the function. */
+ for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+ if (gotent->reloc_type == R_ALPHA_LITERAL
+ && gotent->use_count > 0)
+ break;
+
+ /* If there is, reset the PLT offset. If not, there's no longer
+ a need for the PLT entry. */
+ if (gotent)
+ {
+ if (splt->_raw_size == 0)
+ splt->_raw_size = PLT_HEADER_SIZE;
+ h->root.plt.offset = splt->_raw_size;
+ splt->_raw_size += PLT_ENTRY_SIZE;
+ }
+ else
+ {
+ h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->root.plt.offset = -1;
+ }
+
+ return true;
+ }
+
static boolean
elf64_alpha_always_size_sections (output_bfd, info)
! bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
bfd *i;
*************** elf64_alpha_always_size_sections (output
*** 3740,3746 ****
elf64_alpha_merge_ind_symbols,
NULL);
! if (!elf64_alpha_size_got_sections (output_bfd, info))
return false;
/* Allocate space for all of the .got subsections. */
--- 3833,3839 ----
elf64_alpha_merge_ind_symbols,
NULL);
! if (!elf64_alpha_size_got_sections (info))
return false;
/* Allocate space for all of the .got subsections. */
*************** elf64_alpha_calc_dynrel_sizes (h, info)
*** 3802,3809 ****
{
boolean dynamic;
struct alpha_elf_reloc_entry *relent;
! struct alpha_elf_got_entry *gotent;
! int entries;
if (h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
--- 3895,3901 ----
{
boolean dynamic;
struct alpha_elf_reloc_entry *relent;
! unsigned long entries;
if (h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
*************** elf64_alpha_calc_dynrel_sizes (h, info)
*** 3823,3831 ****
&& (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
&& !(h->root.root.u.def.section->owner->flags & DYNAMIC))
! {
! h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
! }
/* If the symbol is dynamic, we'll need all the relocations in their
natural form. If this is a shared object, and it has been forced
--- 3915,3921 ----
&& (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
&& !(h->root.root.u.def.section->owner->flags & DYNAMIC))
! h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
/* If the symbol is dynamic, we'll need all the relocations in their
natural form. If this is a shared object, and it has been forced
*************** elf64_alpha_calc_dynrel_sizes (h, info)
*** 3846,3855 ****
}
}
entries = 0;
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
! entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
! dynamic, info->shared);
/* If we are using a .plt entry, subtract one, as the first
reference uses a .rela.plt entry instead. */
--- 3936,4025 ----
}
}
+ return true;
+ }
+
+ /* Set the sizes of the dynamic relocation sections. */
+
+ static boolean
+ elf64_alpha_size_rela_got_section (info)
+ struct bfd_link_info *info;
+ {
+ unsigned long entries;
+ bfd *i, *dynobj;
+ asection *srel;
+
+ /* Shared libraries often require RELATIVE relocs, and some relocs
+ require attention for the main application as well. */
+
+ entries = 0;
+ for (i = alpha_elf_hash_table(info)->got_list;
+ i ; i = alpha_elf_tdata(i)->got_link_next)
+ {
+ bfd *j;
+
+ for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
+ {
+ struct alpha_elf_got_entry **local_got_entries, *gotent;
+ int k, n;
+
+ local_got_entries = alpha_elf_tdata(j)->local_got_entries;
+ if (!local_got_entries)
+ continue;
+
+ for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
+ for (gotent = local_got_entries[k];
+ gotent ; gotent = gotent->next)
+ if (gotent->use_count > 0)
+ entries += (alpha_dynamic_entries_for_reloc
+ (gotent->reloc_type, 0, info->shared));
+ }
+ }
+
+ dynobj = elf_hash_table(info)->dynobj;
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (!srel)
+ {
+ BFD_ASSERT (entries == 0);
+ return true;
+ }
+ srel->_raw_size = sizeof (Elf64_External_Rela) * entries;
+
+ /* Now do the non-local symbols. */
+ alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ elf64_alpha_size_rela_got_1, info);
+
+ srel->_cooked_size = srel->_raw_size;
+
+ return true;
+ }
+
+ /* Subroutine of elf64_alpha_size_rela_got_section for doing the
+ global symbols. */
+
+ static boolean
+ elf64_alpha_size_rela_got_1 (h, info)
+ struct alpha_elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+ {
+ boolean dynamic;
+ struct alpha_elf_got_entry *gotent;
+ unsigned long entries;
+
+ if (h->root.root.type == bfd_link_hash_warning)
+ h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
+
+ /* If the symbol is dynamic, we'll need all the relocations in their
+ natural form. If this is a shared object, and it has been forced
+ local, we'll need the same number of RELATIVE relocations. */
+
+ dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
+
entries = 0;
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
! if (gotent->use_count > 0)
! entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
! dynamic, info->shared);
/* If we are using a .plt entry, subtract one, as the first
reference uses a .rela.plt entry instead. */
*************** elf64_alpha_size_dynamic_sections (outpu
*** 3883,3891 ****
if (elf_hash_table (info)->dynamic_sections_created)
{
- int entries;
- bfd *i;
-
/* Set the contents of the .interp section to the interpreter. */
if (!info->shared)
{
--- 4053,4058 ----
*************** elf64_alpha_size_dynamic_sections (outpu
*** 3900,3941 ****
collected information in check_relocs that we can now apply to
size the dynamic relocation sections. */
alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
! elf64_alpha_calc_dynrel_sizes,
! info);
!
! /* Shared libraries often require RELATIVE relocs, and some relocs
! require attention for the main application as well. */
!
! entries = 0;
! for (i = alpha_elf_hash_table(info)->got_list;
! i ; i = alpha_elf_tdata(i)->got_link_next)
! {
! bfd *j;
!
! for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
! {
! struct alpha_elf_got_entry **local_got_entries, *gotent;
! int k, n;
!
! local_got_entries = alpha_elf_tdata(j)->local_got_entries;
! if (!local_got_entries)
! continue;
!
! for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
! for (gotent = local_got_entries[k];
! gotent ; gotent = gotent->next)
! if (gotent->use_count > 0)
! entries += (alpha_dynamic_entries_for_reloc
! (gotent->reloc_type, 0, info->shared));
! }
! }
! if (entries > 0)
! {
! s = bfd_get_section_by_name (dynobj, ".rela.got");
! BFD_ASSERT (s != NULL);
! s->_raw_size += sizeof (Elf64_External_Rela) * entries;
! }
}
/* else we're not dynamic and by definition we don't need such things. */
--- 4067,4075 ----
collected information in check_relocs that we can now apply to
size the dynamic relocation sections. */
alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
! elf64_alpha_calc_dynrel_sizes, info);
! elf64_alpha_size_rela_got_section (info);
}
/* else we're not dynamic and by definition we don't need such things. */
*************** elf64_alpha_finish_dynamic_symbol (outpu
*** 4827,4835 ****
gotent != NULL;
gotent = gotent->next)
{
! asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
int r_type;
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ gotent->got_offset);
--- 4961,4973 ----
gotent != NULL;
gotent = gotent->next)
{
! asection *sgot;
int r_type;
+ if (gotent->use_count == 0)
+ continue;
+
+ sgot = alpha_elf_tdata (gotent->gotobj)->got;
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ gotent->got_offset);