summaryrefslogtreecommitdiff
path: root/bfd/elf64-hppa.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-hppa.c')
-rw-r--r--bfd/elf64-hppa.c279
1 files changed, 151 insertions, 128 deletions
diff --git a/bfd/elf64-hppa.c b/bfd/elf64-hppa.c
index c6ea4f43764..aef822a02f2 100644
--- a/bfd/elf64-hppa.c
+++ b/bfd/elf64-hppa.c
@@ -184,7 +184,7 @@ static boolean elf64_hppa_object_p
PARAMS ((bfd *));
static boolean elf64_hppa_section_from_shdr
- PARAMS ((bfd *, Elf64_Internal_Shdr *, char *));
+ PARAMS ((bfd *, Elf64_Internal_Shdr *, const char *));
static void elf64_hppa_post_process_headers
PARAMS ((bfd *, struct bfd_link_info *));
@@ -195,6 +195,9 @@ static boolean elf64_hppa_create_dynamic_sections
static boolean elf64_hppa_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf64_hppa_mark_milli_and_exported_functions
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+
static boolean elf64_hppa_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
@@ -210,6 +213,9 @@ static int elf64_hppa_additional_program_headers PARAMS ((bfd *));
static boolean elf64_hppa_modify_segment_map PARAMS ((bfd *));
+static enum elf_reloc_type_class elf64_hppa_reloc_type_class
+ PARAMS ((const Elf_Internal_Rela *));
+
static boolean elf64_hppa_finish_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
@@ -403,7 +409,7 @@ static boolean
elf64_hppa_section_from_shdr (abfd, hdr, name)
bfd *abfd;
Elf64_Internal_Shdr *hdr;
- char *name;
+ const char *name;
{
asection *newsect;
@@ -585,7 +591,6 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
struct elf64_hppa_link_hash_table *hppa_info;
const Elf_Internal_Rela *relend;
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
const Elf_Internal_Rela *rel;
asection *dlt, *plt, *stubs;
char *buf;
@@ -607,15 +612,14 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
/* If necessary, build a new table holding section symbols indices
- for this BFD. This is disgusting. */
+ for this BFD. */
if (info->shared && hppa_info->section_syms_bfd != abfd)
{
unsigned long i;
unsigned int highest_shndx;
- Elf_Internal_Sym *local_syms, *isym;
- Elf64_External_Sym *ext_syms, *esym;
- Elf_External_Sym_Shndx *shndx_buf, *shndx;
+ Elf_Internal_Sym *local_syms = NULL;
+ Elf_Internal_Sym *isym, *isymend;
bfd_size_type amt;
/* We're done with the old cache of section index to section symbol
@@ -626,71 +630,27 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
if (hppa_info->section_syms)
free (hppa_info->section_syms);
- /* Allocate memory for the internal and external symbols. */
- amt = symtab_hdr->sh_info;
- amt *= sizeof (Elf_Internal_Sym);
- local_syms = (Elf_Internal_Sym *) bfd_malloc (amt);
- if (local_syms == NULL)
- return false;
-
- amt = symtab_hdr->sh_info;
- amt *= sizeof (Elf64_External_Sym);
- ext_syms = (Elf64_External_Sym *) bfd_malloc (amt);
- if (ext_syms == NULL)
+ /* Read this BFD's local symbols. */
+ if (symtab_hdr->sh_info != 0)
{
- free (local_syms);
- return false;
- }
-
- /* Read in the local symbols. */
- if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (ext_syms, amt, abfd) != amt)
- {
- free (ext_syms);
- free (local_syms);
- return false;
- }
-
- shndx_buf = NULL;
- shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- if (shndx_hdr->sh_size != 0)
- {
- amt = symtab_hdr->sh_info;
- amt *= sizeof (Elf_External_Sym_Shndx);
- shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (shndx_buf == NULL)
- {
- free (ext_syms);
- free (local_syms);
- return false;
- }
-
- if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (shndx_buf, amt, abfd) != amt)
- {
- free (shndx_buf);
- free (ext_syms);
- free (local_syms);
- return false;
- }
+ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (local_syms == NULL)
+ local_syms = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (local_syms == NULL)
+ return false;
}
- /* Swap in the local symbols, also record the highest section index
- referenced by the local symbols. */
+ /* Record the highest section index referenced by the local symbols. */
highest_shndx = 0;
- for (i = 0, isym = local_syms, esym = ext_syms, shndx = shndx_buf;
- i < symtab_hdr->sh_info;
- i++, esym++, isym++, shndx = (shndx != NULL ? shndx + 1 : NULL))
+ isymend = local_syms + symtab_hdr->sh_info;
+ for (isym = local_syms; isym < isymend; isym++)
{
- bfd_elf64_swap_symbol_in (abfd, esym, shndx, isym);
if (isym->st_shndx > highest_shndx)
highest_shndx = isym->st_shndx;
}
- /* Now we can free the external symbols. */
- free (shndx_buf);
- free (ext_syms);
-
/* Allocate an array to hold the section index to section symbol index
mapping. Bump by one since we start counting at zero. */
highest_shndx++;
@@ -700,14 +660,24 @@ elf64_hppa_check_relocs (abfd, info, sec, relocs)
/* Now walk the local symbols again. If we find a section symbol,
record the index of the symbol into the section_syms array. */
- for (isym = local_syms, i = 0; i < symtab_hdr->sh_info; i++, isym++)
+ for (i = 0, isym = local_syms; isym < isymend; i++, isym++)
{
if (ELF_ST_TYPE (isym->st_info) == STT_SECTION)
hppa_info->section_syms[isym->st_shndx] = i;
}
- /* We are finished with the local symbols. Get rid of them. */
- free (local_syms);
+ /* We are finished with the local symbols. */
+ if (local_syms != NULL
+ && symtab_hdr->contents != (unsigned char *) local_syms)
+ {
+ if (! info->keep_memory)
+ free (local_syms);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) local_syms;
+ }
+ }
/* Record which BFD we built the section_syms mapping for. */
hppa_info->section_syms_bfd = abfd;
@@ -1072,7 +1042,7 @@ allocate_global_data_dlt (dyn_h, data)
table since we might need to create a dynamic relocation
against it. */
if (! h
- || (h && h->dynindx == -1))
+ || (h->dynindx == -1 && h->type != STT_PARISC_MILLI))
{
bfd *owner;
owner = (h ? h->root.u.def.section->owner : dyn_h->owner);
@@ -1158,7 +1128,8 @@ allocate_global_data_opd (dyn_h, data)
/* We never need an opd entry for a symbol which is not
defined by this output file. */
- if (h && h->root.type == bfd_link_hash_undefined)
+ if (h && (h->root.type == bfd_link_hash_undefined
+ || h->root.u.def.section->output_section == NULL))
dyn_h->want_opd = 0;
/* If we are creating a shared library, took the address of a local
@@ -1166,10 +1137,9 @@ allocate_global_data_opd (dyn_h, data)
we have to create an opd descriptor. */
else if (x->info->shared
|| h == NULL
- || h->dynindx == -1
- || ((h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && h->root.u.def.section->output_section != NULL))
+ || (h->dynindx == -1 && h->type != STT_PARISC_MILLI)
+ || (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak))
{
/* If we are creating a shared library, then we will have to
create a runtime relocation for the symbol to properly
@@ -1531,22 +1501,18 @@ allocate_dynrel_entries (dyn_h, data)
for (rent = dyn_h->reloc_entries; rent; rent = rent->next)
{
- switch (rent->type)
- {
- case R_PARISC_FPTR64:
- /* Allocate one iff we are not building a shared library and
- !want_opd, which by this point will be true only if we're
- actually allocating one statically in the main executable. */
- if (!x->info->shared && dyn_h->want_opd)
- continue;
- break;
- }
+ /* Allocate one iff we are building a shared library, the relocation
+ isn't a R_PARISC_FPTR64, or we don't want an opd entry. */
+ if (!shared && rent->type == R_PARISC_FPTR64 && dyn_h->want_opd)
+ continue;
+
hppa_info->other_rel_sec->_raw_size += sizeof (Elf64_External_Rela);
/* Make sure this symbol gets into the dynamic symbol table if it is
not already recorded. ?!? This should not be in the loop since
the symbol need only be added once. */
- if (dyn_h->h == 0 || dyn_h->h->dynindx == -1)
+ if (dyn_h->h == 0
+ || (dyn_h->h->dynindx == -1 && dyn_h->h->type != STT_PARISC_MILLI))
if (!_bfd_elf64_link_record_local_dynamic_symbol
(x->info, rent->sec->owner, dyn_h->sym_indx))
return false;
@@ -1614,6 +1580,36 @@ elf64_hppa_adjust_dynamic_symbol (info, h)
return true;
}
+/* This function is called via elf_link_hash_traverse to mark millicode
+ symbols with a dynindx of -1 and to remove the string table reference
+ from the dynamic symbol table. If the symbol is not a millicode symbol,
+ elf64_hppa_mark_exported_functions is called. */
+
+static boolean
+elf64_hppa_mark_milli_and_exported_functions (h, data)
+ struct elf_link_hash_entry *h;
+ PTR data;
+{
+ struct bfd_link_info *info = (struct bfd_link_info *)data;
+ struct elf_link_hash_entry *elf = h;
+
+ if (elf->root.type == bfd_link_hash_warning)
+ elf = (struct elf_link_hash_entry *) elf->root.u.i.link;
+
+ if (elf->type == STT_PARISC_MILLI)
+ {
+ if (elf->dynindx != -1)
+ {
+ elf->dynindx = -1;
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ elf->dynstr_index);
+ }
+ return true;
+ }
+
+ return elf64_hppa_mark_exported_functions (h, data);
+}
+
/* Set the final sizes of the dynamic sections and allocate memory for
the contents of our special sections. */
@@ -1635,6 +1631,19 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
+ /* Mark each function this program exports so that we will allocate
+ space in the .opd section for each function's FPTR. If we are
+ creating dynamic sections, change the dynamic index of millicode
+ symbols to -1 and remove them from the string table for .dynstr.
+
+ We have to traverse the main linker hash table since we have to
+ find functions which may not have been mentioned in any relocs. */
+ elf_link_hash_traverse (elf_hash_table (info),
+ (elf_hash_table (info)->dynamic_sections_created
+ ? elf64_hppa_mark_milli_and_exported_functions
+ : elf64_hppa_mark_exported_functions),
+ info);
+
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
@@ -1679,15 +1688,6 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
hppa_info->stub_sec->_raw_size = data.ofs;
}
- /* Mark each function this program exports so that we will allocate
- space in the .opd section for each function's FPTR.
-
- We have to traverse the main linker hash table since we have to
- find functions which may not have been mentioned in any relocs. */
- elf_link_hash_traverse (elf_hash_table (info),
- elf64_hppa_mark_exported_functions,
- info);
-
/* Allocate space for entries in the .opd section. */
if (elf64_hppa_hash_table (info)->opd_sec)
{
@@ -1722,10 +1722,9 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
if (strcmp (name, ".plt") == 0)
{
+ /* Strip this section if we don't need it; see the comment below. */
if (s->_raw_size == 0)
{
- /* Strip this section if we don't need it; see the
- comment below. */
strip = true;
}
else
@@ -1736,24 +1735,29 @@ elf64_hppa_size_dynamic_sections (output_bfd, info)
}
else if (strcmp (name, ".dlt") == 0)
{
+ /* Strip this section if we don't need it; see the comment below. */
if (s->_raw_size == 0)
{
- /* Strip this section if we don't need it; see the
- comment below. */
strip = true;
}
}
else if (strcmp (name, ".opd") == 0)
{
+ /* Strip this section if we don't need it; see the comment below. */
if (s->_raw_size == 0)
{
- /* Strip this section if we don't need it; see the
- comment below. */
strip = true;
}
}
- else if (strncmp (name, ".rela", 4) == 0)
+ else if (strncmp (name, ".rela", 5) == 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. */
if (s->_raw_size == 0)
{
/* If we don't need this section, strip it from the
@@ -1951,9 +1955,6 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
spltrel = hppa_info->plt_rel_sec;
sdltrel = hppa_info->dlt_rel_sec;
- BFD_ASSERT (stub != NULL && splt != NULL
- && sopd != NULL && sdlt != NULL)
-
/* Incredible. It is actually necessary to NOT use the symbol's real
value when building the dynamic symbol table for a shared library.
At least for symbols that refer to functions.
@@ -1963,6 +1964,8 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
the original values (in elf64_hppa_link_output_symbol_hook). */
if (dyn_h && dyn_h->want_opd)
{
+ BFD_ASSERT (sopd != NULL)
+
/* Save away the original value and section index so that we
can restore them later. */
dyn_h->st_value = sym->st_value;
@@ -1984,6 +1987,8 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
bfd_vma value;
Elf_Internal_Rela rel;
+ BFD_ASSERT (splt != NULL && spltrel != NULL)
+
/* We do not actually care about the value in the PLT entry
if we are creating a shared library and the symbol is
still undefined, we create a dynamic relocation to fill
@@ -2034,6 +2039,8 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
int insn;
unsigned int max_offset;
+ BFD_ASSERT (stub != NULL)
+
/* Install the generic stub template.
We are modifying the contents of the stub section, so we do not
@@ -2096,11 +2103,6 @@ elf64_hppa_finish_dynamic_symbol (output_bfd, info, h, sym)
stub->contents + dyn_h->stub_offset + 8);
}
- /* Millicode symbols should not be put in the dynamic
- symbol table under any circumstances. */
- if (ELF_ST_TYPE (sym->st_info) == STT_PARISC_MILLI)
- h->dynindx = -1;
-
return true;
}
@@ -2114,7 +2116,7 @@ elf64_hppa_finalize_opd (dyn_h, data)
{
struct bfd_link_info *info = (struct bfd_link_info *)data;
struct elf64_hppa_link_hash_table *hppa_info;
- struct elf_link_hash_entry *h = dyn_h->h;
+ struct elf_link_hash_entry *h = dyn_h ? dyn_h->h : NULL;
asection *sopd;
asection *sopdrel;
@@ -2122,7 +2124,7 @@ elf64_hppa_finalize_opd (dyn_h, data)
sopd = hppa_info->opd_sec;
sopdrel = hppa_info->opd_rel_sec;
- if (h && dyn_h && dyn_h->want_opd)
+ if (h && dyn_h->want_opd)
{
bfd_vma value;
@@ -2235,7 +2237,7 @@ elf64_hppa_finalize_dlt (dyn_h, data)
struct bfd_link_info *info = (struct bfd_link_info *)data;
struct elf64_hppa_link_hash_table *hppa_info;
asection *sdlt, *sdltrel;
- struct elf_link_hash_entry *h = dyn_h->h;
+ struct elf_link_hash_entry *h = dyn_h ? dyn_h->h : NULL;
hppa_info = elf64_hppa_hash_table (info);
@@ -2246,7 +2248,7 @@ elf64_hppa_finalize_dlt (dyn_h, data)
address, so there is no need to create a relocation. Just install
the proper value into the DLT, note this shortcut can not be
skipped when building a shared library. */
- if (! info->shared && h && dyn_h && dyn_h->want_dlt)
+ if (! info->shared && h && dyn_h->want_dlt)
{
bfd_vma value;
@@ -2262,16 +2264,17 @@ elf64_hppa_finalize_dlt (dyn_h, data)
+ hppa_info->opd_sec->output_offset
+ hppa_info->opd_sec->output_section->vma);
}
- else
+ else if (h->root.u.def.section)
{
- value = (h->root.u.def.value
- + h->root.u.def.section->output_offset);
-
+ value = h->root.u.def.value + h->root.u.def.section->output_offset;
if (h->root.u.def.section->output_section)
value += h->root.u.def.section->output_section->vma;
else
value += h->root.u.def.section->vma;
}
+ else
+ /* We have an undefined function reference. */
+ value = 0;
/* We do not need to include the output offset of the DLT section
here because we are modifying the in-memory contents. */
@@ -2356,16 +2359,10 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
{
Elf64_Internal_Rela rel;
- switch (rent->type)
- {
- case R_PARISC_FPTR64:
- /* Allocate one iff we are not building a shared library and
- !want_opd, which by this point will be true only if we're
- actually allocating one statically in the main executable. */
- if (!info->shared && dyn_h->want_opd)
- continue;
- break;
- }
+ /* Allocate one iff we are building a shared library, the relocation
+ isn't a R_PARISC_FPTR64, or we don't want an opd entry. */
+ if (!info->shared && rent->type == R_PARISC_FPTR64 && dyn_h->want_opd)
+ continue;
/* Create a dynamic relocation for this entry.
@@ -2394,7 +2391,7 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
We use a section symbol recorded by check_relocs as the
base symbol for the relocation. The addend is the difference
between the section symbol and the address of the .opd entry. */
- if (info->shared && rent->type == R_PARISC_FPTR64)
+ if (info->shared && rent->type == R_PARISC_FPTR64 && dyn_h->want_opd)
{
bfd_vma value, value2;
@@ -2439,6 +2436,27 @@ elf64_hppa_finalize_dynreloc (dyn_h, data)
return true;
}
+/* Used to decide how to sort relocs in an optimal manner for the
+ dynamic linker, before writing them out. */
+
+static enum elf_reloc_type_class
+elf64_hppa_reloc_type_class (rela)
+ const Elf_Internal_Rela *rela;
+{
+ if (ELF64_R_SYM (rela->r_info) == 0)
+ return reloc_class_relative;
+
+ switch ((int) ELF64_R_TYPE (rela->r_info))
+ {
+ case R_PARISC_IPLT:
+ return reloc_class_plt;
+ case R_PARISC_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
/* Finish up the dynamic sections. */
static boolean
@@ -2522,8 +2540,10 @@ elf64_hppa_finish_dynamic_sections (output_bfd, info)
case DT_RELA:
s = hppa_info->other_rel_sec;
- if (! s)
+ if (! s || ! s->_raw_size)
s = hppa_info->dlt_rel_sec;
+ if (! s || ! s->_raw_size)
+ s = hppa_info->opd_rel_sec;
dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
@@ -2673,6 +2693,7 @@ const struct elf_size_info hppa64_elf_size_info =
bfd_elf64_write_out_phdrs,
bfd_elf64_write_shdrs_and_ehdr,
bfd_elf64_write_relocs,
+ bfd_elf64_swap_symbol_in,
bfd_elf64_swap_symbol_out,
bfd_elf64_slurp_reloc_table,
bfd_elf64_slurp_symbol_table,
@@ -2703,7 +2724,7 @@ const struct elf_size_info hppa64_elf_size_info =
#define elf_backend_fake_sections elf_hppa_fake_sections
#define elf_backend_add_symbol_hook elf_hppa_add_symbol_hook
-#define elf_backend_relocate_section elf_hppa_relocate_section
+#define elf_backend_relocate_section elf_hppa_relocate_section
#define bfd_elf64_bfd_final_link elf_hppa_final_link
@@ -2748,6 +2769,8 @@ const struct elf_size_info hppa64_elf_size_info =
#define elf_backend_plt_header_size 0
#define elf_backend_type_change_ok true
#define elf_backend_get_symbol_type elf64_hppa_elf_get_symbol_type
+#define elf_backend_reloc_type_class elf64_hppa_reloc_type_class
+#define elf_backend_rela_normal 1
#include "elf64-target.h"