diff options
Diffstat (limited to 'bfd/elf32-xtensa.c')
-rw-r--r-- | bfd/elf32-xtensa.c | 262 |
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" |