summaryrefslogtreecommitdiff
path: root/bfd/elf32-xtensa.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf32-xtensa.c')
-rw-r--r--bfd/elf32-xtensa.c262
1 files changed, 181 insertions, 81 deletions
diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
index 1f8d86de223..3322c9efd68 100644
--- a/bfd/elf32-xtensa.c
+++ b/bfd/elf32-xtensa.c
@@ -102,6 +102,8 @@ static bfd_boolean elf_xtensa_new_section_hook
/* Local helper functions. */
+static bfd_boolean xtensa_elf_dynamic_symbol_p
+ PARAMS ((struct elf_link_hash_entry *, struct bfd_link_info *));
static int property_table_compare
PARAMS ((const PTR, const PTR));
static bfd_boolean elf_xtensa_in_literal_pool
@@ -131,12 +133,10 @@ static void do_fix_for_relocatable_link
PARAMS ((Elf_Internal_Rela *, bfd *, asection *));
static void do_fix_for_final_link
PARAMS ((Elf_Internal_Rela *, asection *, bfd_vma *));
-static bfd_boolean xtensa_elf_dynamic_symbol_p
- PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
static bfd_vma elf_xtensa_create_plt_entry
PARAMS ((bfd *, bfd *, unsigned));
static int elf_xtensa_combine_prop_entries
- PARAMS ((bfd *, const char *));
+ PARAMS ((bfd *, asection *, asection *));
static bfd_boolean elf_xtensa_discard_info_for_section
PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *,
asection *));
@@ -206,6 +206,8 @@ static bfd_boolean pcrel_reloc_fits
PARAMS ((xtensa_operand, bfd_vma, bfd_vma));
static bfd_boolean xtensa_is_property_section
PARAMS ((asection *));
+static bfd_boolean xtensa_is_littable_section
+ PARAMS ((asection *));
static bfd_boolean is_literal_section
PARAMS ((asection *));
static int internal_reloc_compare
@@ -231,7 +233,7 @@ typedef struct xtensa_relax_info_struct xtensa_relax_info;
The actual PLT code must be split into multiple sections and all
the sections have to be created before size_dynamic_sections,
where we figure out the exact number of PLT entries that will be
- needed. It is OK is this count is an overestimate, e.g., some
+ needed. It is OK if this count is an overestimate, e.g., some
relocations may be removed by GC. */
static int plt_reloc_count = 0;
@@ -447,6 +449,21 @@ static const bfd_byte elf_xtensa_le_plt_entry[PLT_ENTRY_SIZE] =
0 /* unused */
};
+
+static inline bfd_boolean
+xtensa_elf_dynamic_symbol_p (h, info)
+ struct elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+{
+ /* Check if we should do dynamic things to this symbol. The
+ "ignore_protected" argument need not be set, because Xtensa code
+ does not require special handling of STV_PROTECTED to make function
+ pointer comparisons work properly. The PLT addresses are never
+ used for function pointers. */
+
+ return _bfd_elf_dynamic_symbol_p (h, info, 0);
+}
+
static int
property_table_compare (ap, bp)
@@ -904,7 +921,7 @@ elf_xtensa_create_dynamic_sections (dynobj, info)
bfd *dynobj;
struct bfd_link_info *info;
{
- flagword flags;
+ flagword flags, noalloc_flags;
asection *s;
/* First do all the standard stuff. */
@@ -916,8 +933,9 @@ elf_xtensa_create_dynamic_sections (dynobj, info)
if (!add_extra_plt_sections (dynobj, plt_reloc_count))
return FALSE;
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED | SEC_READONLY);
+ noalloc_flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+ flags = noalloc_flags | SEC_ALLOC | SEC_LOAD;
/* Mark the ".got.plt" section READONLY. */
s = bfd_get_section_by_name (dynobj, ".got.plt");
@@ -932,10 +950,17 @@ elf_xtensa_create_dynamic_sections (dynobj, info)
|| ! bfd_set_section_alignment (dynobj, s, 2))
return FALSE;
+ /* Create ".got.loc" (literal tables for use by dynamic linker). */
+ s = bfd_make_section (dynobj, ".got.loc");
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags)
+ || ! bfd_set_section_alignment (dynobj, s, 2))
+ return FALSE;
+
/* Create ".xt.lit.plt" (literal table for ".got.plt*"). */
s = bfd_make_section (dynobj, ".xt.lit.plt");
if (s == NULL
- || ! bfd_set_section_flags (dynobj, s, flags)
+ || ! bfd_set_section_flags (dynobj, s, noalloc_flags)
|| ! bfd_set_section_alignment (dynobj, s, 2))
return FALSE;
@@ -1053,7 +1078,7 @@ elf_xtensa_fix_refcounts (h, arg)
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
- if (! xtensa_elf_dynamic_symbol_p (info, h))
+ if (! xtensa_elf_dynamic_symbol_p (h, info))
elf_xtensa_make_sym_local (info, h);
/* If the symbol has a relocation outside the GOT, set the
@@ -1136,8 +1161,8 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
- bfd *dynobj;
- asection *s, *srelplt, *splt, *sgotplt, *srelgot, *spltlittbl;
+ bfd *dynobj, *abfd;
+ asection *s, *srelplt, *splt, *sgotplt, *srelgot, *spltlittbl, *sgotloc;
bfd_boolean relplt, relgot;
int plt_entries, plt_chunks, chunk;
@@ -1241,6 +1266,25 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
splt->_raw_size = 0;
}
}
+
+ /* Allocate space in ".got.loc" to match the total size of all the
+ literal tables. */
+ sgotloc = bfd_get_section_by_name (dynobj, ".got.loc");
+ if (sgotloc == NULL)
+ abort ();
+ sgotloc->_raw_size = spltlittbl->_raw_size;
+ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ {
+ if (abfd->flags & DYNAMIC)
+ continue;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (! elf_discarded_section (s)
+ && xtensa_is_littable_section (s)
+ && s != spltlittbl)
+ sgotloc->_raw_size += s->_raw_size;
+ }
+ }
}
/* Allocate memory for dynamic sections. */
@@ -1291,7 +1335,8 @@ elf_xtensa_size_dynamic_sections (output_bfd, info)
else if (strcmp (name, ".got") != 0
&& strcmp (name, ".plt") != 0
&& strcmp (name, ".got.plt") != 0
- && strcmp (name, ".xt.lit.plt") != 0)
+ && strcmp (name, ".xt.lit.plt") != 0
+ && strcmp (name, ".got.loc") != 0)
{
/* It's not one of our sections, so don't allocate space. */
continue;
@@ -1800,46 +1845,6 @@ elf_xtensa_create_plt_entry (dynobj, output_bfd, reloc_index)
}
-static bfd_boolean
-xtensa_elf_dynamic_symbol_p (info, h)
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
-{
- if (h == NULL)
- return FALSE;
-
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
-
- if (h->dynindx == -1)
- return FALSE;
-
- if (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_defweak)
- return TRUE;
-
- switch (ELF_ST_VISIBILITY (h->other))
- {
- case STV_DEFAULT:
- break;
- case STV_HIDDEN:
- case STV_INTERNAL:
- return FALSE;
- case STV_PROTECTED:
- if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
- return FALSE;
- break;
- }
-
- if ((info->shared && !info->symbolic)
- || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
- return TRUE;
-
- return FALSE;
-}
-
-
/* Relocate an Xtensa ELF section. This is invoked by the linker for
both relocatable and final links. */
@@ -2066,7 +2071,7 @@ elf_xtensa_relocate_section (output_bfd, info, input_bfd,
/* Generate dynamic relocations. */
if (elf_hash_table (info)->dynamic_sections_created)
{
- bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+ bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (h, info);
if (dynamic_symbol && (r_type == R_XTENSA_OP0
|| r_type == R_XTENSA_OP1
@@ -2236,25 +2241,31 @@ elf_xtensa_finish_dynamic_symbol (output_bfd, info, h, sym)
on error. */
static int
-elf_xtensa_combine_prop_entries (output_bfd, secname)
+elf_xtensa_combine_prop_entries (output_bfd, sxtlit, sgotloc)
bfd *output_bfd;
- const char *secname;
+ asection *sxtlit;
+ asection *sgotloc;
{
- asection *sec;
bfd_byte *contents;
property_table_entry *table;
- bfd_size_type section_size;
+ bfd_size_type section_size, sgotloc_size;
bfd_vma offset;
int n, m, num;
- sec = bfd_get_section_by_name (output_bfd, secname);
- if (!sec)
- return -1;
-
- section_size = (sec->_cooked_size != 0 ? sec->_cooked_size : sec->_raw_size);
+ section_size = (sxtlit->_cooked_size != 0
+ ? sxtlit->_cooked_size : sxtlit->_raw_size);
BFD_ASSERT (section_size % 8 == 0);
num = section_size / 8;
+ sgotloc_size = (sgotloc->_cooked_size != 0
+ ? sgotloc->_cooked_size : sgotloc->_raw_size);
+ if (sgotloc_size != section_size)
+ {
+ (*_bfd_error_handler)
+ ("internal inconsistency in size of .got.loc section");
+ return -1;
+ }
+
contents = (bfd_byte *) bfd_malloc (section_size);
table = (property_table_entry *)
bfd_malloc (num * sizeof (property_table_entry));
@@ -2264,9 +2275,10 @@ elf_xtensa_combine_prop_entries (output_bfd, secname)
/* The ".xt.lit.plt" section has the SEC_IN_MEMORY flag set and this
propagates to the output section, where it doesn't really apply and
where it breaks the following call to bfd_get_section_contents. */
- sec->flags &= ~SEC_IN_MEMORY;
+ sxtlit->flags &= ~SEC_IN_MEMORY;
- if (! bfd_get_section_contents (output_bfd, sec, contents, 0, section_size))
+ if (! bfd_get_section_contents (output_bfd, sxtlit, contents, 0,
+ section_size))
return -1;
/* There should never be any relocations left at this point, so this
@@ -2321,12 +2333,16 @@ elf_xtensa_combine_prop_entries (output_bfd, secname)
if ((bfd_size_type) (num * 8) < section_size)
{
memset (&contents[num * 8], 0, section_size - num * 8);
- sec->_cooked_size = num * 8;
+ sxtlit->_cooked_size = num * 8;
}
- if (! bfd_set_section_contents (output_bfd, sec, contents, 0, section_size))
+ if (! bfd_set_section_contents (output_bfd, sxtlit, contents, 0,
+ section_size))
return -1;
+ /* Copy the contents to ".got.loc". */
+ memcpy (sgotloc->contents, contents, section_size);
+
free (contents);
return num;
}
@@ -2340,7 +2356,7 @@ elf_xtensa_finish_dynamic_sections (output_bfd, info)
struct bfd_link_info *info;
{
bfd *dynobj;
- asection *sdyn, *srelplt, *sgot;
+ asection *sdyn, *srelplt, *sgot, *sxtlit, *sgotloc;
Elf32_External_Dyn *dyncon, *dynconend;
int num_xtlit_entries;
@@ -2466,7 +2482,11 @@ elf_xtensa_finish_dynamic_sections (output_bfd, info)
/* Combine adjacent literal table entries. */
BFD_ASSERT (! info->relocatable);
- num_xtlit_entries = elf_xtensa_combine_prop_entries (output_bfd, ".xt.lit");
+ sxtlit = bfd_get_section_by_name (output_bfd, ".xt.lit");
+ sgotloc = bfd_get_section_by_name (dynobj, ".got.loc");
+ BFD_ASSERT (sxtlit && sgotloc);
+ num_xtlit_entries =
+ elf_xtensa_combine_prop_entries (output_bfd, sxtlit, sgotloc);
if (num_xtlit_entries < 0)
return FALSE;
@@ -2486,13 +2506,11 @@ elf_xtensa_finish_dynamic_sections (output_bfd, info)
break;
case DT_XTENSA_GOT_LOC_SZ:
- s = bfd_get_section_by_name (output_bfd, ".xt.lit");
- BFD_ASSERT (s);
dyn.d_un.d_val = num_xtlit_entries;
break;
case DT_XTENSA_GOT_LOC_OFF:
- name = ".xt.lit";
+ name = ".got.loc";
goto get_vma;
case DT_PLTGOT:
name = ".got";
@@ -2564,7 +2582,7 @@ elf_xtensa_merge_private_bfd_data (ibfd, obfd)
if (out_mach != in_mach)
{
(*_bfd_error_handler)
- ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x\n",
+ ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x",
bfd_archive_filename (ibfd), out_mach, in_mach);
bfd_set_error (bfd_error_wrong_format);
return FALSE;
@@ -2810,6 +2828,24 @@ elf_xtensa_discard_info_for_section (abfd, cookie, info, sec)
sec->_cooked_size = section_size - removed_bytes;
/* Also shrink _raw_size. See comments in relax_property_section. */
sec->_raw_size = sec->_cooked_size;
+
+ if (xtensa_is_littable_section (sec))
+ {
+ bfd *dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj)
+ {
+ asection *sgotloc =
+ bfd_get_section_by_name (dynobj, ".got.loc");
+ if (sgotloc)
+ {
+ bfd_size_type sgotloc_size =
+ (sgotloc->_cooked_size ? sgotloc->_cooked_size
+ : sgotloc->_raw_size);
+ sgotloc->_cooked_size = sgotloc_size - removed_bytes;
+ sgotloc->_raw_size = sgotloc_size - removed_bytes;
+ }
+ }
+ }
}
else
{
@@ -3088,7 +3124,7 @@ elf_xtensa_do_asm_simplify (contents, address, content_length)
if (content_length < address)
{
(*_bfd_error_handler)
- ("Attempt to convert L32R/CALLX to CALL failed\n");
+ ("Attempt to convert L32R/CALLX to CALL failed");
return bfd_reloc_other;
}
@@ -3097,7 +3133,7 @@ elf_xtensa_do_asm_simplify (contents, address, content_length)
if (direct_call_opcode == XTENSA_UNDEFINED)
{
(*_bfd_error_handler)
- ("Attempt to convert L32R/CALLX to CALL failed\n");
+ ("Attempt to convert L32R/CALLX to CALL failed");
return bfd_reloc_other;
}
@@ -4931,7 +4967,7 @@ shrink_dynamic_reloc_sections (info, abfd, input_section, rel)
else
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+ dynamic_symbol = xtensa_elf_dynamic_symbol_p (h, info);
if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
&& (input_section->flags & SEC_ALLOC) != 0
@@ -5264,9 +5300,27 @@ relax_property_section (abfd, sec, link_info)
relaxed; shrinking _raw_size means that these checks will
not be unnecessarily lax.) */
sec->_raw_size = sec->_cooked_size;
+
+ if (xtensa_is_littable_section (sec))
+ {
+ bfd *dynobj = elf_hash_table (link_info)->dynobj;
+ if (dynobj)
+ {
+ asection *sgotloc =
+ bfd_get_section_by_name (dynobj, ".got.loc");
+ if (sgotloc)
+ {
+ bfd_size_type sgotloc_size =
+ (sgotloc->_cooked_size ? sgotloc->_cooked_size
+ : sgotloc->_raw_size);
+ sgotloc->_cooked_size = sgotloc_size - removed_bytes;
+ sgotloc->_raw_size = sgotloc_size - removed_bytes;
+ }
+ }
+ }
}
}
-
+
error_return:
release_internal_relocs (sec, internal_relocs);
release_contents (sec, contents);
@@ -5584,12 +5638,42 @@ static bfd_boolean
xtensa_is_property_section (sec)
asection *sec;
{
- static int len = sizeof (".gnu.linkonce.t.") - 1;
+ static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+
+ if (strncmp (".xt.insn", sec->name, 8) == 0
+ || strncmp (".xt.lit", sec->name, 7) == 0)
+ return TRUE;
+
+ if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0)
+ {
+ if (strncmp ("x.", sec->name + linkonce_len, 2) == 0
+ || strncmp ("p.", sec->name + linkonce_len, 2) == 0)
+ return TRUE;
+ if (strstr (sec->name + linkonce_len, ".xt.insn") != NULL
+ || strstr (sec->name + linkonce_len, ".xt.lit") != NULL)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+static bfd_boolean
+xtensa_is_littable_section (sec)
+ asection *sec;
+{
+ static int linkonce_len = sizeof (".gnu.linkonce.") - 1;
+
+ if (strncmp (".xt.lit", sec->name, 7) == 0)
+ return TRUE;
- return (strcmp (".xt.insn", sec->name) == 0
- || strcmp (".xt.lit", sec->name) == 0
- || strncmp (".gnu.linkonce.x.", sec->name, len) == 0
- || strncmp (".gnu.linkonce.p.", sec->name, len) == 0);
+ if (strncmp (".gnu.linkonce.", sec->name, linkonce_len) == 0)
+ {
+ if (strncmp ("p.", sec->name + linkonce_len, 2) == 0)
+ return TRUE;
+ if (strstr (sec->name + linkonce_len, ".xt.lit") != NULL)
+ return TRUE;
+ }
+ return FALSE;
}
@@ -5781,6 +5865,21 @@ xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure)
return ok;
}
+/* The default literal sections should always be marked as "code" (i.e.,
+ SHF_EXECINSTR). This is particularly important for the Linux kernel
+ module loader so that the literals are not placed after the text. */
+static struct bfd_elf_special_section const elf_xtensa_special_sections[]=
+{
+ { ".literal", 0, NULL, 0,
+ SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { ".init.literal", 0, NULL, 0,
+ SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { ".fini.literal", 0, NULL, 0,
+ SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, NULL, 0,
+ 0, 0 }
+};
+
#ifndef ELF_ARCH
#define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec
@@ -5841,5 +5940,6 @@ xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure)
#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class
#define elf_backend_relocate_section elf_xtensa_relocate_section
#define elf_backend_size_dynamic_sections elf_xtensa_size_dynamic_sections
+#define elf_backend_special_sections elf_xtensa_special_sections
#include "elf32-target.h"