X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-xtensa.c;h=75ccefef0251cbe796e2b0f84a20344a9a2d37b1;hb=f2de978509eb51f85410eab04696725f0bccf9c3;hp=0d744c220e1035e3618ff619bed936cad9eb64b7;hpb=cb33740c88ad5fd9e07f243332c511275c15219f;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c index 0d744c220e..75ccefef02 100644 --- a/bfd/elf32-xtensa.c +++ b/bfd/elf32-xtensa.c @@ -1,5 +1,6 @@ /* Xtensa-specific support for 32-bit ELF. - Copyright 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -108,7 +109,8 @@ static bfd_boolean xtensa_is_littable_section (asection *); static bfd_boolean xtensa_is_proptable_section (asection *); static int internal_reloc_compare (const void *, const void *); static int internal_reloc_matches (const void *, const void *); -extern asection *xtensa_get_property_section (asection *, const char *); +static asection *xtensa_get_property_section (asection *, const char *); +extern asection *xtensa_make_property_section (asection *, const char *); static flagword xtensa_get_property_predef_flags (asection *); /* Other functions called directly by the linker. */ @@ -153,6 +155,10 @@ static bfd_boolean relaxing_section = FALSE; int elf32xtensa_no_literal_movement = 1; +/* Rename one of the generic section flags to better document how it + is used here. */ +/* Whether relocations have been processed. */ +#define reloc_done sec_flg0 static reloc_howto_type elf_howto_table[] = { @@ -287,6 +293,29 @@ static reloc_howto_type elf_howto_table[] = bfd_elf_xtensa_reloc, "R_XTENSA_SLOT13_ALT", FALSE, 0, 0, TRUE), HOWTO (R_XTENSA_SLOT14_ALT, 0, 0, 0, TRUE, 0, complain_overflow_dont, bfd_elf_xtensa_reloc, "R_XTENSA_SLOT14_ALT", FALSE, 0, 0, TRUE), + + /* TLS relocations. */ + HOWTO (R_XTENSA_TLSDESC_FN, 0, 2, 32, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_FN", + FALSE, 0, 0xffffffff, FALSE), + HOWTO (R_XTENSA_TLSDESC_ARG, 0, 2, 32, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLSDESC_ARG", + FALSE, 0, 0xffffffff, FALSE), + HOWTO (R_XTENSA_TLS_DTPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLS_DTPOFF", + FALSE, 0, 0xffffffff, FALSE), + HOWTO (R_XTENSA_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLS_TPOFF", + FALSE, 0, 0xffffffff, FALSE), + HOWTO (R_XTENSA_TLS_FUNC, 0, 0, 0, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLS_FUNC", + FALSE, 0, 0, FALSE), + HOWTO (R_XTENSA_TLS_ARG, 0, 0, 0, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLS_ARG", + FALSE, 0, 0, FALSE), + HOWTO (R_XTENSA_TLS_CALL, 0, 0, 0, FALSE, 0, complain_overflow_dont, + bfd_elf_xtensa_reloc, "R_XTENSA_TLS_CALL", + FALSE, 0, 0, FALSE), }; #if DEBUG_GEN_RELOC @@ -374,6 +403,34 @@ elf_xtensa_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, TRACE ("BFD_RELOC_VTABLE_ENTRY"); return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ]; + case BFD_RELOC_XTENSA_TLSDESC_FN: + TRACE ("BFD_RELOC_XTENSA_TLSDESC_FN"); + return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_FN ]; + + case BFD_RELOC_XTENSA_TLSDESC_ARG: + TRACE ("BFD_RELOC_XTENSA_TLSDESC_ARG"); + return &elf_howto_table[(unsigned) R_XTENSA_TLSDESC_ARG ]; + + case BFD_RELOC_XTENSA_TLS_DTPOFF: + TRACE ("BFD_RELOC_XTENSA_TLS_DTPOFF"); + return &elf_howto_table[(unsigned) R_XTENSA_TLS_DTPOFF ]; + + case BFD_RELOC_XTENSA_TLS_TPOFF: + TRACE ("BFD_RELOC_XTENSA_TLS_TPOFF"); + return &elf_howto_table[(unsigned) R_XTENSA_TLS_TPOFF ]; + + case BFD_RELOC_XTENSA_TLS_FUNC: + TRACE ("BFD_RELOC_XTENSA_TLS_FUNC"); + return &elf_howto_table[(unsigned) R_XTENSA_TLS_FUNC ]; + + case BFD_RELOC_XTENSA_TLS_ARG: + TRACE ("BFD_RELOC_XTENSA_TLS_ARG"); + return &elf_howto_table[(unsigned) R_XTENSA_TLS_ARG ]; + + case BFD_RELOC_XTENSA_TLS_CALL: + TRACE ("BFD_RELOC_XTENSA_TLS_CALL"); + return &elf_howto_table[(unsigned) R_XTENSA_TLS_CALL ]; + default: if (code >= BFD_RELOC_XTENSA_SLOT0_OP && code <= BFD_RELOC_XTENSA_SLOT14_OP) @@ -478,6 +535,56 @@ static const bfd_byte elf_xtensa_le_plt_entry[PLT_ENTRY_SIZE] = 0 /* unused */ }; +/* The size of the thread control block. */ +#define TCB_SIZE 8 + +struct elf_xtensa_link_hash_entry +{ + struct elf_link_hash_entry elf; + + bfd_signed_vma tlsfunc_refcount; + +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 /* global or local dynamic */ +#define GOT_TLS_IE 4 /* initial or local exec */ +#define GOT_TLS_ANY (GOT_TLS_GD | GOT_TLS_IE) + unsigned char tls_type; +}; + +#define elf_xtensa_hash_entry(ent) ((struct elf_xtensa_link_hash_entry *)(ent)) + +struct elf_xtensa_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; + + bfd_signed_vma *local_tlsfunc_refcounts; +}; + +#define elf_xtensa_tdata(abfd) \ + ((struct elf_xtensa_obj_tdata *) (abfd)->tdata.any) + +#define elf_xtensa_local_got_tls_type(abfd) \ + (elf_xtensa_tdata (abfd)->local_got_tls_type) + +#define elf_xtensa_local_tlsfunc_refcounts(abfd) \ + (elf_xtensa_tdata (abfd)->local_tlsfunc_refcounts) + +#define is_xtensa_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == XTENSA_ELF_DATA) + +static bfd_boolean +elf_xtensa_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct elf_xtensa_obj_tdata), + XTENSA_ELF_DATA); +} + /* Xtensa ELF linker hash table. */ struct elf_xtensa_link_hash_table @@ -500,46 +607,107 @@ struct elf_xtensa_link_hash_table needed. It is OK if this count is an overestimate, e.g., some relocations may be removed by GC. */ int plt_reloc_count; + + struct elf_xtensa_link_hash_entry *tlsbase; }; /* Get the Xtensa ELF linker hash table from a link_info structure. */ #define elf_xtensa_hash_table(p) \ - ((struct elf_xtensa_link_hash_table *) ((p)->hash)) + (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ + == XTENSA_ELF_DATA ? ((struct elf_xtensa_link_hash_table *) ((p)->hash)) : NULL) + +/* Create an entry in an Xtensa ELF linker hash table. */ + +static struct bfd_hash_entry * +elf_xtensa_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, + sizeof (struct elf_xtensa_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_elf_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (entry); + eh->tlsfunc_refcount = 0; + eh->tls_type = GOT_UNKNOWN; + } + + return entry; +} /* Create an Xtensa ELF linker hash table. */ static struct bfd_link_hash_table * elf_xtensa_link_hash_table_create (bfd *abfd) { + struct elf_link_hash_entry *tlsbase; struct elf_xtensa_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_xtensa_link_hash_table); - ret = bfd_malloc (amt); + ret = bfd_zmalloc (amt); if (ret == NULL) return NULL; if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry))) + elf_xtensa_link_hash_newfunc, + sizeof (struct elf_xtensa_link_hash_entry), + XTENSA_ELF_DATA)) { free (ret); return NULL; } - ret->sgot = NULL; - ret->sgotplt = NULL; - ret->srelgot = NULL; - ret->splt = NULL; - ret->srelplt = NULL; - ret->sgotloc = NULL; - ret->spltlittbl = NULL; - - ret->plt_reloc_count = 0; + /* Create a hash entry for "_TLS_MODULE_BASE_" to speed up checking + for it later. */ + tlsbase = elf_link_hash_lookup (&ret->elf, "_TLS_MODULE_BASE_", + TRUE, FALSE, FALSE); + tlsbase->root.type = bfd_link_hash_new; + tlsbase->root.u.undef.abfd = NULL; + tlsbase->non_elf = 0; + ret->tlsbase = elf_xtensa_hash_entry (tlsbase); + ret->tlsbase->tls_type = GOT_UNKNOWN; return &ret->elf.root; } +/* Copy the extra info we tack onto an elf_link_hash_entry. */ + +static void +elf_xtensa_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_xtensa_link_hash_entry *edir, *eind; + + edir = elf_xtensa_hash_entry (dir); + eind = elf_xtensa_hash_entry (ind); + + if (ind->root.type == bfd_link_hash_indirect) + { + edir->tlsfunc_refcount += eind->tlsfunc_refcount; + eind->tlsfunc_refcount = 0; + + if (dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + } + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + static inline bfd_boolean elf_xtensa_dynamic_symbol_p (struct elf_link_hash_entry *h, struct bfd_link_info *info) @@ -574,7 +742,7 @@ property_table_compare (const void *ap, const void *bp) != GET_XTENSA_PROP_ALIGNMENT (b->flags))) return (GET_XTENSA_PROP_ALIGNMENT (a->flags) - GET_XTENSA_PROP_ALIGNMENT (b->flags)); - + if ((a->flags & XTENSA_PROP_UNREACHABLE) != (b->flags & XTENSA_PROP_UNREACHABLE)) return ((b->flags & XTENSA_PROP_UNREACHABLE) @@ -636,7 +804,7 @@ xtensa_read_table_entries (bfd *abfd, if (table_section) table_size = table_section->size; - if (table_size == 0) + if (table_size == 0) { *table_p = NULL; return 0; @@ -671,7 +839,7 @@ xtensa_read_table_entries (bfd *abfd, section_limit = bfd_get_section_limit (abfd, section); rel_end = internal_relocs + table_section->reloc_count; - for (off = 0; off < table_size; off += table_entry_size) + for (off = 0; off < table_size; off += table_entry_size) { bfd_vma address = bfd_get_32 (abfd, table_data + off); @@ -799,10 +967,15 @@ elf_xtensa_check_relocs (bfd *abfd, const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; - if (info->relocatable) + if (info->relocatable || (sec->flags & SEC_ALLOC) == 0) return TRUE; + BFD_ASSERT (is_xtensa_elf (abfd)); + htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); @@ -811,7 +984,12 @@ elf_xtensa_check_relocs (bfd *abfd, { unsigned int r_type; unsigned long r_symndx; - struct elf_link_hash_entry *h; + struct elf_link_hash_entry *h = NULL; + struct elf_xtensa_link_hash_entry *eh; + int tls_type, old_tls_type; + bfd_boolean is_got = FALSE; + bfd_boolean is_plt = FALSE; + bfd_boolean is_tlsfunc = FALSE; r_symndx = ELF32_R_SYM (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info); @@ -823,38 +1001,95 @@ elf_xtensa_check_relocs (bfd *abfd, return FALSE; } - if (r_symndx < symtab_hdr->sh_info) - h = NULL; - else + if (r_symndx >= symtab_hdr->sh_info) { h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 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; + + /* PR15323, ref flags aren't set for references in the same + object. */ + h->root.non_ir_ref = 1; } + eh = elf_xtensa_hash_entry (h); switch (r_type) { - case R_XTENSA_32: - if (h == NULL) - goto local_literal; + case R_XTENSA_TLSDESC_FN: + if (info->shared) + { + tls_type = GOT_TLS_GD; + is_got = TRUE; + is_tlsfunc = TRUE; + } + else + tls_type = GOT_TLS_IE; + break; - if ((sec->flags & SEC_ALLOC) != 0) + case R_XTENSA_TLSDESC_ARG: + if (info->shared) { - if (h->got.refcount <= 0) - h->got.refcount = 1; - else - h->got.refcount += 1; + tls_type = GOT_TLS_GD; + is_got = TRUE; + } + else + { + tls_type = GOT_TLS_IE; + if (h && elf_xtensa_hash_entry (h) != htab->tlsbase) + is_got = TRUE; } break; + case R_XTENSA_TLS_DTPOFF: + if (info->shared) + tls_type = GOT_TLS_GD; + else + tls_type = GOT_TLS_IE; + break; + + case R_XTENSA_TLS_TPOFF: + tls_type = GOT_TLS_IE; + if (info->shared) + info->flags |= DF_STATIC_TLS; + if (info->shared || h) + is_got = TRUE; + break; + + case R_XTENSA_32: + tls_type = GOT_NORMAL; + is_got = TRUE; + break; + case R_XTENSA_PLT: - /* If this relocation is against a local symbol, then it's - exactly the same as a normal local GOT entry. */ - if (h == NULL) - goto local_literal; + tls_type = GOT_NORMAL; + is_plt = TRUE; + break; + + case R_XTENSA_GNU_VTINHERIT: + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; + continue; + + case R_XTENSA_GNU_VTENTRY: + /* This relocation describes which C++ vtable entries are actually + used. Record for later use during GC. */ + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + continue; - if ((sec->flags & SEC_ALLOC) != 0) + default: + /* Nothing to do for any other relocations. */ + continue; + } + + if (h) + { + if (is_plt) { if (h->plt.refcount <= 0) { @@ -875,49 +1110,82 @@ elf_xtensa_check_relocs (bfd *abfd, return FALSE; } } - break; + else if (is_got) + { + if (h->got.refcount <= 0) + h->got.refcount = 1; + else + h->got.refcount += 1; + } + + if (is_tlsfunc) + eh->tlsfunc_refcount += 1; - local_literal: - if ((sec->flags & SEC_ALLOC) != 0) + old_tls_type = eh->tls_type; + } + else + { + /* Allocate storage the first time. */ + if (elf_local_got_refcounts (abfd) == NULL) { - bfd_signed_vma *local_got_refcounts; + bfd_size_type size = symtab_hdr->sh_info; + void *mem; - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; + mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma)); + if (mem == NULL) + return FALSE; + elf_local_got_refcounts (abfd) = (bfd_signed_vma *) mem; - size = symtab_hdr->sh_info; - size *= sizeof (bfd_signed_vma); - local_got_refcounts = - (bfd_signed_vma *) bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - } - local_got_refcounts[r_symndx] += 1; + mem = bfd_zalloc (abfd, size); + if (mem == NULL) + return FALSE; + elf_xtensa_local_got_tls_type (abfd) = (char *) mem; + + mem = bfd_zalloc (abfd, size * sizeof (bfd_signed_vma)); + if (mem == NULL) + return FALSE; + elf_xtensa_local_tlsfunc_refcounts (abfd) + = (bfd_signed_vma *) mem; } - break; - case R_XTENSA_GNU_VTINHERIT: - /* This relocation describes the C++ object vtable hierarchy. - Reconstruct it for later use during GC. */ - if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return FALSE; - break; + /* This is a global offset table entry for a local symbol. */ + if (is_got || is_plt) + elf_local_got_refcounts (abfd) [r_symndx] += 1; - case R_XTENSA_GNU_VTENTRY: - /* This relocation describes which C++ vtable entries are actually - used. Record for later use during GC. */ - BFD_ASSERT (h != NULL); - if (h != NULL - && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) - return FALSE; - break; + if (is_tlsfunc) + elf_xtensa_local_tlsfunc_refcounts (abfd) [r_symndx] += 1; - default: - break; + old_tls_type = elf_xtensa_local_got_tls_type (abfd) [r_symndx]; + } + + if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE)) + tls_type |= old_tls_type; + /* If a TLS symbol is accessed using IE at least once, + there is no point to use a dynamic model for it. */ + else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN + && ((old_tls_type & GOT_TLS_GD) == 0 + || (tls_type & GOT_TLS_IE) == 0)) + { + if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_GD)) + tls_type = old_tls_type; + else if ((old_tls_type & GOT_TLS_GD) && (tls_type & GOT_TLS_GD)) + tls_type |= old_tls_type; + else + { + (*_bfd_error_handler) + (_("%B: `%s' accessed both as normal and thread local symbol"), + abfd, + h ? h->root.root.string : ""); + return FALSE; + } + } + + if (old_tls_type != tls_type) + { + if (eh) + eh->tls_type = tls_type; + else + elf_xtensa_local_got_tls_type (abfd) [r_symndx] = tls_type; } } @@ -1003,14 +1271,18 @@ elf_xtensa_gc_mark_hook (asection *sec, static bfd_boolean elf_xtensa_gc_sweep_hook (bfd *abfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs) { Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel, *relend; + struct elf_xtensa_link_hash_table *htab; + + htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; if (info->relocatable) return TRUE; @@ -1020,7 +1292,6 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; rel++) @@ -1028,6 +1299,10 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, unsigned long r_symndx; unsigned int r_type; struct elf_link_hash_entry *h = NULL; + struct elf_xtensa_link_hash_entry *eh; + bfd_boolean is_got = FALSE; + bfd_boolean is_plt = FALSE; + bfd_boolean is_tlsfunc = FALSE; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx >= symtab_hdr->sh_info) @@ -1037,31 +1312,80 @@ elf_xtensa_gc_sweep_hook (bfd *abfd, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; } + eh = elf_xtensa_hash_entry (h); r_type = ELF32_R_TYPE (rel->r_info); switch (r_type) { - case R_XTENSA_32: - if (h == NULL) - goto local_literal; - if (h->got.refcount > 0) - h->got.refcount--; + case R_XTENSA_TLSDESC_FN: + if (info->shared) + { + is_got = TRUE; + is_tlsfunc = TRUE; + } break; - case R_XTENSA_PLT: - if (h == NULL) - goto local_literal; - if (h->plt.refcount > 0) - h->plt.refcount--; + case R_XTENSA_TLSDESC_ARG: + if (info->shared) + is_got = TRUE; + else + { + if (h && elf_xtensa_hash_entry (h) != htab->tlsbase) + is_got = TRUE; + } break; - local_literal: - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; + case R_XTENSA_TLS_TPOFF: + if (info->shared || h) + is_got = TRUE; break; - default: + case R_XTENSA_32: + is_got = TRUE; break; + + case R_XTENSA_PLT: + is_plt = TRUE; + break; + + default: + continue; + } + + if (h) + { + if (is_plt) + { + if (h->plt.refcount > 0) + h->plt.refcount--; + } + else if (is_got) + { + if (h->got.refcount > 0) + h->got.refcount--; + } + if (is_tlsfunc) + { + if (eh->tlsfunc_refcount > 0) + eh->tlsfunc_refcount--; + } + } + else + { + if (is_got || is_plt) + { + bfd_signed_vma *got_refcount + = &elf_local_got_refcounts (abfd) [r_symndx]; + if (*got_refcount > 0) + *got_refcount -= 1; + } + if (is_tlsfunc) + { + bfd_signed_vma *tlsfunc_refcount + = &elf_xtensa_local_tlsfunc_refcounts (abfd) [r_symndx]; + if (*tlsfunc_refcount > 0) + *tlsfunc_refcount -= 1; + } } } @@ -1078,14 +1402,17 @@ elf_xtensa_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) flagword flags, noalloc_flags; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; /* First do all the standard stuff. */ if (! _bfd_elf_create_dynamic_sections (dynobj, info)) return FALSE; - htab->splt = bfd_get_section_by_name (dynobj, ".plt"); - htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); - htab->sgot = bfd_get_section_by_name (dynobj, ".got"); - htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); + htab->splt = bfd_get_linker_section (dynobj, ".plt"); + htab->srelplt = bfd_get_linker_section (dynobj, ".rela.plt"); + htab->sgot = bfd_get_linker_section (dynobj, ".got"); + htab->sgotplt = bfd_get_linker_section (dynobj, ".got.plt"); + htab->srelgot = bfd_get_linker_section (dynobj, ".rela.got"); /* Create any extra PLT sections in case check_relocs has already been called on all the non-dynamic input files. */ @@ -1101,21 +1428,16 @@ elf_xtensa_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) || ! bfd_set_section_flags (dynobj, htab->sgotplt, flags)) return FALSE; - /* Create ".rela.got". */ - htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", flags); - if (htab->srelgot == NULL - || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) - return FALSE; - /* Create ".got.loc" (literal tables for use by dynamic linker). */ - htab->sgotloc = bfd_make_section_with_flags (dynobj, ".got.loc", flags); + htab->sgotloc = bfd_make_section_anyway_with_flags (dynobj, ".got.loc", + flags); if (htab->sgotloc == NULL || ! bfd_set_section_alignment (dynobj, htab->sgotloc, 2)) return FALSE; /* Create ".xt.lit.plt" (literal table for ".got.plt*"). */ - htab->spltlittbl = bfd_make_section_with_flags (dynobj, ".xt.lit.plt", - noalloc_flags); + htab->spltlittbl = bfd_make_section_anyway_with_flags (dynobj, ".xt.lit.plt", + noalloc_flags); if (htab->spltlittbl == NULL || ! bfd_set_section_alignment (dynobj, htab->spltlittbl, 2)) return FALSE; @@ -1147,14 +1469,14 @@ add_extra_plt_sections (struct bfd_link_info *info, int count) sname = (char *) bfd_malloc (10); sprintf (sname, ".plt.%u", chunk); - s = bfd_make_section_with_flags (dynobj, sname, flags | SEC_CODE); + s = bfd_make_section_anyway_with_flags (dynobj, sname, flags | SEC_CODE); if (s == NULL || ! bfd_set_section_alignment (dynobj, s, 2)) return FALSE; sname = (char *) bfd_malloc (14); sprintf (sname, ".got.plt.%u", chunk); - s = bfd_make_section_with_flags (dynobj, sname, flags); + s = bfd_make_section_anyway_with_flags (dynobj, sname, flags); if (s == NULL || ! bfd_set_section_alignment (dynobj, s, 2)) return FALSE; @@ -1199,20 +1521,25 @@ elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg) { struct bfd_link_info *info; struct elf_xtensa_link_hash_table *htab; - bfd_boolean is_dynamic; + struct elf_xtensa_link_hash_entry *eh = elf_xtensa_hash_entry (h); if (h->root.type == bfd_link_hash_indirect) return TRUE; - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - info = (struct bfd_link_info *) arg; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; - is_dynamic = elf_xtensa_dynamic_symbol_p (h, info); + /* If we saw any use of an IE model for this symbol, we can then optimize + away GOT entries for any TLSDESC_FN relocs. */ + if ((eh->tls_type & GOT_TLS_IE) != 0) + { + BFD_ASSERT (h->got.refcount >= eh->tlsfunc_refcount); + h->got.refcount -= eh->tlsfunc_refcount; + } - if (! is_dynamic) + if (! elf_xtensa_dynamic_symbol_p (h, info)) elf_xtensa_make_sym_local (info, h); if (h->plt.refcount > 0) @@ -1232,6 +1559,8 @@ elf_xtensa_allocate_local_got_size (struct bfd_link_info *info) bfd *i; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return; for (i = info->input_bfds; i; i = i->link_next) { @@ -1248,6 +1577,16 @@ elf_xtensa_allocate_local_got_size (struct bfd_link_info *info) for (j = 0; j < cnt; ++j) { + /* If we saw any use of an IE model for this symbol, we can + then optimize away GOT entries for any TLSDESC_FN relocs. */ + if ((elf_xtensa_local_got_tls_type (i) [j] & GOT_TLS_IE) != 0) + { + bfd_signed_vma *tlsfunc_refcount + = &elf_xtensa_local_tlsfunc_refcounts (i) [j]; + BFD_ASSERT (local_got_refcounts[j] >= *tlsfunc_refcount); + local_got_refcounts[j] -= *tlsfunc_refcount; + } + if (local_got_refcounts[j] > 0) htab->srelgot->size += (local_got_refcounts[j] * sizeof (Elf32_External_Rela)); @@ -1272,6 +1611,9 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, plt_chunks = 0; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; + dynobj = elf_hash_table (info)->dynobj; if (dynobj == NULL) abort (); @@ -1289,7 +1631,7 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Set the contents of the .interp section to the interpreter. */ if (info->executable) { - s = bfd_get_section_by_name (dynobj, ".interp"); + s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) abort (); s->size = sizeof ELF_DYNAMIC_INTERPRETER; @@ -1365,7 +1707,7 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, continue; for (s = abfd->sections; s != NULL; s = s->next) { - if (! elf_discarded_section (s) + if (! discarded_section (s) && xtensa_is_littable_section (s) && s != spltlittbl) sgotloc->size += s->size; @@ -1497,7 +1839,69 @@ elf_xtensa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return TRUE; } +static bfd_boolean +elf_xtensa_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + struct elf_xtensa_link_hash_table *htab; + asection *tls_sec; + + htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; + + tls_sec = htab->elf.tls_sec; + + if (tls_sec && (htab->tlsbase->tls_type & GOT_TLS_ANY) != 0) + { + struct elf_link_hash_entry *tlsbase = &htab->tlsbase->elf; + struct bfd_link_hash_entry *bh = &tlsbase->root; + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + + tlsbase->type = STT_TLS; + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, + tls_sec, 0, NULL, FALSE, + bed->collect, &bh))) + return FALSE; + tlsbase->def_regular = 1; + tlsbase->other = STV_HIDDEN; + (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); + } + + return TRUE; +} + +/* Return the base VMA address which should be subtracted from real addresses + when resolving @dtpoff relocation. + This is PT_TLS segment p_vaddr. */ + +static bfd_vma +dtpoff_base (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ + +static bfd_vma +tpoff (struct bfd_link_info *info, bfd_vma address) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + bfd_vma base; + + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) + return 0; + base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power); + return address - htab->tls_sec->vma + base; +} + /* Perform the specified relocation. The instruction at (contents + address) is modified to set one operand to represent the value in "relocation". The operand position is determined by the relocation type recorded in the @@ -1545,19 +1949,21 @@ elf_xtensa_do_reloc (reloc_howto_type *howto, case R_XTENSA_DIFF8: case R_XTENSA_DIFF16: case R_XTENSA_DIFF32: + case R_XTENSA_TLS_FUNC: + case R_XTENSA_TLS_ARG: + case R_XTENSA_TLS_CALL: return bfd_reloc_ok; case R_XTENSA_ASM_EXPAND: if (!is_weak_undef) { /* Check for windowed CALL across a 1GB boundary. */ - xtensa_opcode opcode = - get_expanded_call_opcode (contents + address, - input_size - address, 0); + opcode = get_expanded_call_opcode (contents + address, + input_size - address, 0); if (is_windowed_call_opcode (opcode)) { if ((self_address >> CALL_SEGMENT_BITS) - != (relocation >> CALL_SEGMENT_BITS)) + != (relocation >> CALL_SEGMENT_BITS)) { *error_message = "windowed longcall crosses 1GB boundary; " "return may fail"; @@ -1584,7 +1990,6 @@ elf_xtensa_do_reloc (reloc_howto_type *howto, break; case R_XTENSA_32: - case R_XTENSA_PLT: { bfd_vma x; x = bfd_get_32 (abfd, contents + address); @@ -1596,6 +2001,14 @@ elf_xtensa_do_reloc (reloc_howto_type *howto, case R_XTENSA_32_PCREL: bfd_put_32 (abfd, relocation - self_address, contents + address); return bfd_reloc_ok; + + case R_XTENSA_PLT: + case R_XTENSA_TLSDESC_FN: + case R_XTENSA_TLSDESC_ARG: + case R_XTENSA_TLS_DTPOFF: + case R_XTENSA_TLS_TPOFF: + bfd_put_32 (abfd, relocation, contents + address); + return bfd_reloc_ok; } /* Only instruction slot-specific relocations handled below.... */ @@ -1723,7 +2136,7 @@ elf_xtensa_do_reloc (reloc_howto_type *howto, && is_windowed_call_opcode (opcode)) { if ((self_address >> CALL_SEGMENT_BITS) - != (relocation >> CALL_SEGMENT_BITS)) + != (relocation >> CALL_SEGMENT_BITS)) { *error_message = "windowed call crosses 1GB boundary; return may fail"; @@ -1751,8 +2164,8 @@ vsprint_msg (const char *origmsg, const char *fmt, int arglen, ...) VA_OPEN (ap, arglen); VA_FIXEDARG (ap, const char *, origmsg); - - is_append = (origmsg == message); + + is_append = (origmsg == message); orig_len = strlen (origmsg); len = orig_len + strlen (fmt) + arglen + 20; @@ -1907,34 +2320,216 @@ elf_xtensa_create_plt_entry (struct bfd_link_info *info, plt_base = splt->output_section->vma + splt->output_offset; got_base = sgotplt->output_section->vma + sgotplt->output_offset; - lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4; - code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE; + lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4; + code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE; + + /* Fill in the literal entry. This is the offset of the dynamic + relocation entry. */ + bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela), + sgotplt->contents + lit_offset); + + /* Fill in the entry in the procedure linkage table. */ + memcpy (splt->contents + code_offset, + (bfd_big_endian (output_bfd) + ? elf_xtensa_be_plt_entry + : elf_xtensa_le_plt_entry), + PLT_ENTRY_SIZE); + bfd_put_16 (output_bfd, l32r_offset (got_base + 0, + plt_base + code_offset + 3), + splt->contents + code_offset + 4); + bfd_put_16 (output_bfd, l32r_offset (got_base + 4, + plt_base + code_offset + 6), + splt->contents + code_offset + 7); + bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset, + plt_base + code_offset + 9), + splt->contents + code_offset + 10); + + return plt_base + code_offset; +} + + +static bfd_boolean get_indirect_call_dest_reg (xtensa_opcode, unsigned *); + +static bfd_boolean +replace_tls_insn (Elf_Internal_Rela *rel, + bfd *abfd, + asection *input_section, + bfd_byte *contents, + bfd_boolean is_ld_model, + char **error_message) +{ + static xtensa_insnbuf ibuff = NULL; + static xtensa_insnbuf sbuff = NULL; + xtensa_isa isa = xtensa_default_isa; + xtensa_format fmt; + xtensa_opcode old_op, new_op; + bfd_size_type input_size; + int r_type; + unsigned dest_reg, src_reg; + + if (ibuff == NULL) + { + ibuff = xtensa_insnbuf_alloc (isa); + sbuff = xtensa_insnbuf_alloc (isa); + } + + input_size = bfd_get_section_limit (abfd, input_section); + + /* Read the instruction into a buffer and decode the opcode. */ + xtensa_insnbuf_from_chars (isa, ibuff, contents + rel->r_offset, + input_size - rel->r_offset); + fmt = xtensa_format_decode (isa, ibuff); + if (fmt == XTENSA_UNDEFINED) + { + *error_message = "cannot decode instruction format"; + return FALSE; + } + + BFD_ASSERT (xtensa_format_num_slots (isa, fmt) == 1); + xtensa_format_get_slot (isa, fmt, 0, ibuff, sbuff); + + old_op = xtensa_opcode_decode (isa, fmt, 0, sbuff); + if (old_op == XTENSA_UNDEFINED) + { + *error_message = "cannot decode instruction opcode"; + return FALSE; + } + + r_type = ELF32_R_TYPE (rel->r_info); + switch (r_type) + { + case R_XTENSA_TLS_FUNC: + case R_XTENSA_TLS_ARG: + if (old_op != get_l32r_opcode () + || xtensa_operand_get_field (isa, old_op, 0, fmt, 0, + sbuff, &dest_reg) != 0) + { + *error_message = "cannot extract L32R destination for TLS access"; + return FALSE; + } + break; + + case R_XTENSA_TLS_CALL: + if (! get_indirect_call_dest_reg (old_op, &dest_reg) + || xtensa_operand_get_field (isa, old_op, 0, fmt, 0, + sbuff, &src_reg) != 0) + { + *error_message = "cannot extract CALLXn operands for TLS access"; + return FALSE; + } + break; + + default: + abort (); + } + + if (is_ld_model) + { + switch (r_type) + { + case R_XTENSA_TLS_FUNC: + case R_XTENSA_TLS_ARG: + /* Change the instruction to a NOP (or "OR a1, a1, a1" for older + versions of Xtensa). */ + new_op = xtensa_opcode_lookup (isa, "nop"); + if (new_op == XTENSA_UNDEFINED) + { + new_op = xtensa_opcode_lookup (isa, "or"); + if (new_op == XTENSA_UNDEFINED + || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 + || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, + sbuff, 1) != 0 + || xtensa_operand_set_field (isa, new_op, 1, fmt, 0, + sbuff, 1) != 0 + || xtensa_operand_set_field (isa, new_op, 2, fmt, 0, + sbuff, 1) != 0) + { + *error_message = "cannot encode OR for TLS access"; + return FALSE; + } + } + else + { + if (xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0) + { + *error_message = "cannot encode NOP for TLS access"; + return FALSE; + } + } + break; + + case R_XTENSA_TLS_CALL: + /* Read THREADPTR into the CALLX's return value register. */ + new_op = xtensa_opcode_lookup (isa, "rur.threadptr"); + if (new_op == XTENSA_UNDEFINED + || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 + || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, + sbuff, dest_reg + 2) != 0) + { + *error_message = "cannot encode RUR.THREADPTR for TLS access"; + return FALSE; + } + break; + } + } + else + { + switch (r_type) + { + case R_XTENSA_TLS_FUNC: + new_op = xtensa_opcode_lookup (isa, "rur.threadptr"); + if (new_op == XTENSA_UNDEFINED + || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 + || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, + sbuff, dest_reg) != 0) + { + *error_message = "cannot encode RUR.THREADPTR for TLS access"; + return FALSE; + } + break; - /* Fill in the literal entry. This is the offset of the dynamic - relocation entry. */ - bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela), - sgotplt->contents + lit_offset); + case R_XTENSA_TLS_ARG: + /* Nothing to do. Keep the original L32R instruction. */ + return TRUE; + + case R_XTENSA_TLS_CALL: + /* Add the CALLX's src register (holding the THREADPTR value) + to the first argument register (holding the offset) and put + the result in the CALLX's return value register. */ + new_op = xtensa_opcode_lookup (isa, "add"); + if (new_op == XTENSA_UNDEFINED + || xtensa_opcode_encode (isa, fmt, 0, sbuff, new_op) != 0 + || xtensa_operand_set_field (isa, new_op, 0, fmt, 0, + sbuff, dest_reg + 2) != 0 + || xtensa_operand_set_field (isa, new_op, 1, fmt, 0, + sbuff, dest_reg + 2) != 0 + || xtensa_operand_set_field (isa, new_op, 2, fmt, 0, + sbuff, src_reg) != 0) + { + *error_message = "cannot encode ADD for TLS access"; + return FALSE; + } + break; + } + } - /* Fill in the entry in the procedure linkage table. */ - memcpy (splt->contents + code_offset, - (bfd_big_endian (output_bfd) - ? elf_xtensa_be_plt_entry - : elf_xtensa_le_plt_entry), - PLT_ENTRY_SIZE); - bfd_put_16 (output_bfd, l32r_offset (got_base + 0, - plt_base + code_offset + 3), - splt->contents + code_offset + 4); - bfd_put_16 (output_bfd, l32r_offset (got_base + 4, - plt_base + code_offset + 6), - splt->contents + code_offset + 7); - bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset, - plt_base + code_offset + 9), - splt->contents + code_offset + 10); + xtensa_format_set_slot (isa, fmt, 0, ibuff, sbuff); + xtensa_insnbuf_to_chars (isa, ibuff, contents + rel->r_offset, + input_size - rel->r_offset); - return plt_base + code_offset; + return TRUE; } +#define IS_XTENSA_TLS_RELOC(R_TYPE) \ + ((R_TYPE) == R_XTENSA_TLSDESC_FN \ + || (R_TYPE) == R_XTENSA_TLSDESC_ARG \ + || (R_TYPE) == R_XTENSA_TLS_DTPOFF \ + || (R_TYPE) == R_XTENSA_TLS_TPOFF \ + || (R_TYPE) == R_XTENSA_TLS_FUNC \ + || (R_TYPE) == R_XTENSA_TLS_ARG \ + || (R_TYPE) == R_XTENSA_TLS_CALL) + /* Relocate an Xtensa ELF section. This is invoked by the linker for both relocatable and final links. */ @@ -1955,15 +2550,23 @@ elf_xtensa_relocate_section (bfd *output_bfd, struct elf_link_hash_entry **sym_hashes; property_table_entry *lit_table = 0; int ltblsize = 0; + char *local_got_tls_types; char *error_message = NULL; bfd_size_type input_size; + int tls_type; if (!xtensa_default_isa) xtensa_default_isa = xtensa_isa_init (0, 0); + BFD_ASSERT (is_xtensa_elf (input_bfd)); + htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); + local_got_tls_types = elf_xtensa_local_got_tls_type (input_bfd); if (elf_hash_table (info)->dynamic_sections_created) { @@ -1985,12 +2588,15 @@ elf_xtensa_relocate_section (bfd *output_bfd, unsigned long r_symndx; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; + char sym_type; + const char *name; asection *sec; bfd_vma relocation; bfd_reloc_status_type r; bfd_boolean is_weak_undef; bfd_boolean unresolved_reloc; bfd_boolean warned; + bfd_boolean dynamic_symbol; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == (int) R_XTENSA_GNU_VTINHERIT @@ -2026,35 +2632,36 @@ elf_xtensa_relocate_section (bfd *output_bfd, if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; + sym_type = ELF32_ST_TYPE (sym->st_info); sec = local_sections[r_symndx]; relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); } else { + bfd_boolean ignored; + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); if (relocation == 0 && !unresolved_reloc && h->root.type == bfd_link_hash_undefweak) is_weak_undef = TRUE; - } - if (sec != NULL && elf_discarded_section (sec)) - { - /* For relocs against symbols from removed linkonce sections, - or sections discarded by a linker script, we just want the - section contents zeroed. Avoid any special processing. */ - _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); - rel->r_info = 0; - rel->r_addend = 0; - continue; + sym_type = h->type; } + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + if (info->relocatable) { + bfd_vma dest_addr; + asection * sym_sec = get_elf_r_symndx_section (input_bfd, r_symndx); + /* This is a relocatable link. 1) If the reloc is against a section symbol, adjust according to the output section. @@ -2071,9 +2678,12 @@ elf_xtensa_relocate_section (bfd *output_bfd, return FALSE; } + dest_addr = sym_sec->output_section->vma + sym_sec->output_offset + + get_elf_r_symndx_offset (input_bfd, r_symndx) + rel->r_addend; + if (r_type == R_XTENSA_ASM_SIMPLIFY) { - char *error_message = NULL; + error_message = NULL; /* Convert ASM_SIMPLIFY into the simpler relocation so that they never escape a relaxing link. */ r = contract_asm_expansion (contents, input_size, rel, @@ -2107,25 +2717,41 @@ elf_xtensa_relocate_section (bfd *output_bfd, to work around problems with DWARF in relocatable links with some previous version of BFD. Now we can't easily get rid of the hack without breaking backward compatibility.... */ - if (rel->r_addend) + r = bfd_reloc_ok; + howto = &elf_howto_table[r_type]; + if (howto->partial_inplace && rel->r_addend) + { + r = elf_xtensa_do_reloc (howto, input_bfd, input_section, + rel->r_addend, contents, + rel->r_offset, FALSE, + &error_message); + rel->r_addend = 0; + } + else { - howto = &elf_howto_table[r_type]; - if (howto->partial_inplace) + /* Put the correct bits in the target instruction, even + though the relocation will still be present in the output + file. This makes disassembly clearer, as well as + allowing loadable kernel modules to work without needing + relocations on anything other than calls and l32r's. */ + + /* If it is not in the same section, there is nothing we can do. */ + if (r_type >= R_XTENSA_SLOT0_OP && r_type <= R_XTENSA_SLOT14_OP && + sym_sec->output_section == input_section->output_section) { r = elf_xtensa_do_reloc (howto, input_bfd, input_section, - rel->r_addend, contents, + dest_addr, contents, rel->r_offset, FALSE, &error_message); - if (r != bfd_reloc_ok) - { - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; - } - rel->r_addend = 0; } } + if (r != bfd_reloc_ok) + { + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } /* Done with work for relocatable link; continue with next reloc. */ continue; @@ -2151,27 +2777,49 @@ elf_xtensa_relocate_section (bfd *output_bfd, return FALSE; } - /* Generate dynamic relocations. */ - if (elf_hash_table (info)->dynamic_sections_created) + if (h != NULL) + name = h->root.root.string; + else { - bfd_boolean dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info); + name = (bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name)); + if (name == NULL || *name == '\0') + name = bfd_section_name (input_bfd, sec); + } - if (dynamic_symbol && (is_operand_relocation (r_type) - || r_type == R_XTENSA_32_PCREL)) - { - const char *name = h->root.root.string; - error_message = - vsprint_msg ("invalid relocation for dynamic symbol", ": %s", - strlen (name) + 2, name); - if (!((*info->callbacks->reloc_dangerous) - (info, error_message, input_bfd, input_section, - rel->r_offset))) - return FALSE; - continue; - } - else if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT) - && (input_section->flags & SEC_ALLOC) != 0 - && (dynamic_symbol || info->shared)) + if (r_symndx != STN_UNDEF + && r_type != R_XTENSA_NONE + && (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && IS_XTENSA_TLS_RELOC (r_type) != (sym_type == STT_TLS)) + { + (*_bfd_error_handler) + ((sym_type == STT_TLS + ? _("%B(%A+0x%lx): %s used with TLS symbol %s") + : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")), + input_bfd, + input_section, + (long) rel->r_offset, + howto->name, + name); + } + + dynamic_symbol = elf_xtensa_dynamic_symbol_p (h, info); + + tls_type = GOT_UNKNOWN; + if (h) + tls_type = elf_xtensa_hash_entry (h)->tls_type; + else if (local_got_tls_types) + tls_type = local_got_tls_types [r_symndx]; + + switch (r_type) + { + case R_XTENSA_32: + case R_XTENSA_PLT: + if (elf_hash_table (info)->dynamic_sections_created + && (input_section->flags & SEC_ALLOC) != 0 + && (dynamic_symbol || info->shared)) { Elf_Internal_Rela outrel; bfd_byte *loc; @@ -2255,6 +2903,151 @@ elf_xtensa_relocate_section (bfd *output_bfd, Just ignore these relocations. */ continue; } + break; + + case R_XTENSA_TLS_TPOFF: + /* Switch to LE model for local symbols in an executable. */ + if (! info->shared && ! dynamic_symbol) + { + relocation = tpoff (info, relocation); + break; + } + /* fall through */ + + case R_XTENSA_TLSDESC_FN: + case R_XTENSA_TLSDESC_ARG: + { + if (r_type == R_XTENSA_TLSDESC_FN) + { + if (! info->shared || (tls_type & GOT_TLS_IE) != 0) + r_type = R_XTENSA_NONE; + } + else if (r_type == R_XTENSA_TLSDESC_ARG) + { + if (info->shared) + { + if ((tls_type & GOT_TLS_IE) != 0) + r_type = R_XTENSA_TLS_TPOFF; + } + else + { + r_type = R_XTENSA_TLS_TPOFF; + if (! dynamic_symbol) + { + relocation = tpoff (info, relocation); + break; + } + } + } + + if (r_type == R_XTENSA_NONE) + /* Nothing to do here; skip to the next reloc. */ + continue; + + if (! elf_hash_table (info)->dynamic_sections_created) + { + error_message = + _("TLS relocation invalid without dynamic sections"); + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + asection *srel = htab->srelgot; + int indx; + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + + /* Complain if the relocation is in a read-only section + and not in a literal pool. */ + if ((input_section->flags & SEC_READONLY) != 0 + && ! elf_xtensa_in_literal_pool (lit_table, ltblsize, + outrel.r_offset)) + { + error_message = + _("dynamic relocation in read-only section"); + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + + indx = h && h->dynindx != -1 ? h->dynindx : 0; + if (indx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + else + outrel.r_addend = 0; + rel->r_addend = 0; + + outrel.r_info = ELF32_R_INFO (indx, r_type); + relocation = 0; + unresolved_reloc = FALSE; + + BFD_ASSERT (srel); + loc = (srel->contents + + srel->reloc_count++ * sizeof (Elf32_External_Rela)); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count + <= srel->size); + } + } + break; + + case R_XTENSA_TLS_DTPOFF: + if (! info->shared) + /* Switch from LD model to LE model. */ + relocation = tpoff (info, relocation); + else + relocation -= dtpoff_base (info); + break; + + case R_XTENSA_TLS_FUNC: + case R_XTENSA_TLS_ARG: + case R_XTENSA_TLS_CALL: + /* Check if optimizing to IE or LE model. */ + if ((tls_type & GOT_TLS_IE) != 0) + { + bfd_boolean is_ld_model = + (h && elf_xtensa_hash_entry (h) == htab->tlsbase); + if (! replace_tls_insn (rel, input_bfd, input_section, contents, + is_ld_model, &error_message)) + { + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + } + + if (r_type != R_XTENSA_TLS_ARG || is_ld_model) + { + /* Skip subsequent relocations on the same instruction. */ + while (rel + 1 < relend && rel[1].r_offset == rel->r_offset) + rel++; + } + } + continue; + + default: + if (elf_hash_table (info)->dynamic_sections_created + && dynamic_symbol && (is_operand_relocation (r_type) + || r_type == R_XTENSA_32_PCREL)) + { + error_message = + vsprint_msg ("invalid relocation for dynamic symbol", ": %s", + strlen (name) + 2, name); + if (!((*info->callbacks->reloc_dangerous) + (info, error_message, input_bfd, input_section, + rel->r_offset))) + return FALSE; + continue; + } + break; } /* Dynamic relocs are not propagated for SEC_DEBUGGING sections @@ -2262,7 +3055,9 @@ elf_xtensa_relocate_section (bfd *output_bfd, not process them. */ if (unresolved_reloc && !((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)) + && h->def_dynamic) + && _bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset) != (bfd_vma) -1) { (*_bfd_error_handler) (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), @@ -2270,10 +3065,13 @@ elf_xtensa_relocate_section (bfd *output_bfd, input_section, (long) rel->r_offset, howto->name, - h->root.root.string); + name); return FALSE; } + /* TLS optimizations may have changed r_type; update "howto". */ + howto = &elf_howto_table[r_type]; + /* There's no point in calling bfd_perform_relocation here. Just go directly to our "special function". */ r = elf_xtensa_do_reloc (howto, input_bfd, input_section, @@ -2283,30 +3081,16 @@ elf_xtensa_relocate_section (bfd *output_bfd, if (r != bfd_reloc_ok && !warned) { - const char *name; - BFD_ASSERT (r == bfd_reloc_dangerous || r == bfd_reloc_other); BFD_ASSERT (error_message != NULL); - if (h) - name = h->root.root.string; + if (rel->r_addend == 0) + error_message = vsprint_msg (error_message, ": %s", + strlen (name) + 2, name); else - { - name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); - if (name && *name == '\0') - name = bfd_section_name (input_bfd, sec); - } - if (name) - { - if (rel->r_addend == 0) - error_message = vsprint_msg (error_message, ": %s", - strlen (name) + 2, name); - else - error_message = vsprint_msg (error_message, ": (%s+0x%x)", - strlen (name) + 22, - name, (int)rel->r_addend); - } + error_message = vsprint_msg (error_message, ": (%s+0x%x)", + strlen (name) + 22, + name, (int) rel->r_addend); if (!((*info->callbacks->reloc_dangerous) (info, error_message, input_bfd, input_section, @@ -2347,7 +3131,7 @@ elf_xtensa_finish_dynamic_symbol (bfd *output_bfd ATTRIBUTE_UNUSED, } /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + if (h == elf_hash_table (info)->hdynamic || h == elf_hash_table (info)->hgot) sym->st_shndx = SHN_ABS; @@ -2418,18 +3202,18 @@ elf_xtensa_combine_prop_entries (bfd *output_bfd, for (n = 0; n < num; n++) { - bfd_boolean remove = FALSE; + bfd_boolean remove_entry = FALSE; if (table[n].size == 0) - remove = TRUE; - else if (n > 0 && - (table[n-1].address + table[n-1].size == table[n].address)) + remove_entry = TRUE; + else if (n > 0 + && (table[n-1].address + table[n-1].size == table[n].address)) { table[n-1].size += table[n].size; - remove = TRUE; + remove_entry = TRUE; } - if (remove) + if (remove_entry) { for (m = n; m < num - 1; m++) { @@ -2484,8 +3268,11 @@ elf_xtensa_finish_dynamic_sections (bfd *output_bfd, return TRUE; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return FALSE; + dynobj = elf_hash_table (info)->dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); BFD_ASSERT (sdyn != NULL); /* Set the first entry in the global offset table to the address of @@ -2675,7 +3462,7 @@ elf_xtensa_merge_private_bfd_data (bfd *ibfd, bfd *obfd) unsigned out_mach, in_mach; flagword out_flag, in_flag; - /* Check if we have the same endianess. */ + /* Check if we have the same endianness. */ if (!_bfd_generic_verify_endian_match (ibfd, obfd)) return FALSE; @@ -2711,10 +3498,10 @@ elf_xtensa_merge_private_bfd_data (bfd *ibfd, bfd *obfd) return TRUE; } - if ((out_flag & EF_XTENSA_XT_INSN) != (in_flag & EF_XTENSA_XT_INSN)) + if ((out_flag & EF_XTENSA_XT_INSN) != (in_flag & EF_XTENSA_XT_INSN)) elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_INSN); - if ((out_flag & EF_XTENSA_XT_LIT) != (in_flag & EF_XTENSA_XT_LIT)) + if ((out_flag & EF_XTENSA_XT_LIT) != (in_flag & EF_XTENSA_XT_LIT)) elf_elfheader (obfd)->e_flags &= (~ EF_XTENSA_XT_LIT); return TRUE; @@ -2804,7 +3591,9 @@ elf_xtensa_final_write_processing (bfd *abfd, static enum elf_reloc_type_class -elf_xtensa_reloc_type_class (const Elf_Internal_Rela *rela) +elf_xtensa_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) { switch ((int) ELF32_R_TYPE (rela->r_info)) { @@ -3001,10 +3790,10 @@ elf_xtensa_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) based on the size. Just assume this is GNU/Linux. */ /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -3025,9 +3814,9 @@ elf_xtensa_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return FALSE; case 128: /* GNU/Linux elf_prpsinfo */ - elf_tdata (abfd)->core_program + elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); - elf_tdata (abfd)->core_command + elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); } @@ -3036,7 +3825,7 @@ elf_xtensa_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) implementations, so strip it off if it exists. */ { - char *command = elf_tdata (abfd)->core_command; + char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (0 < n && command[n - 1] == ' ') @@ -3110,6 +3899,29 @@ is_windowed_call_opcode (xtensa_opcode opcode) } +static bfd_boolean +get_indirect_call_dest_reg (xtensa_opcode opcode, unsigned *pdst) +{ + unsigned dst = (unsigned) -1; + + init_call_opcodes (); + if (opcode == callx0_op) + dst = 0; + else if (opcode == callx4_op) + dst = 4; + else if (opcode == callx8_op) + dst = 8; + else if (opcode == callx12_op) + dst = 12; + + if (dst == (unsigned) -1) + return FALSE; + + *pdst = dst; + return TRUE; +} + + static xtensa_opcode get_const16_opcode (void) { @@ -3282,7 +4094,7 @@ get_asm_simplify_size (bfd_byte *contents, return 0; size += insnlen; - + insnlen = insn_decode_len (contents, content_len, offset + size); if (insnlen == 0) return 0; @@ -3321,7 +4133,7 @@ is_operand_relocation (int r_type) return FALSE; } - + #define MIN_INSN_LENGTH 2 /* Return 0 if it fails to decode. */ @@ -3422,7 +4234,7 @@ check_loop_aligned (bfd_byte *contents, BFD_ASSERT (FALSE); return FALSE; } - + loop_len = insn_decode_len (contents, content_length, offset); insn_len = insn_decode_len (contents, content_length, offset + loop_len); if (loop_len == 0 || insn_len == 0) @@ -3814,7 +4626,7 @@ can_widen_instruction (xtensa_insnbuf slotbuf, return 0; } - + /* Attempt to widen an instruction. If the widening is valid, perform the action in-place directly into the contents and return TRUE. Otherwise, the return value is FALSE and the contents are not modified. */ @@ -3909,12 +4721,12 @@ elf_xtensa_do_asm_simplify (bfd_byte *contents, *error_message = _("Attempt to convert L32R/CALLX to CALL failed"); return bfd_reloc_other; } - + /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */ core_format = xtensa_format_lookup (isa, "x24"); opcode = xtensa_opcode_lookup (isa, "or"); xtensa_opcode_encode (isa, core_format, 0, slotbuf, opcode); - for (opn = 0; opn < 3; opn++) + for (opn = 0; opn < 3; opn++) { uint32 regno = 1; xtensa_operand_encode (isa, opcode, opn, ®no); @@ -3982,7 +4794,7 @@ swap_callx_for_call_opcode (xtensa_opcode opcode) #define CONST16_TARGET_REG_OPERAND 0 #define CALLN_SOURCE_OPERAND 0 -static xtensa_opcode +static xtensa_opcode get_expanded_call_opcode (bfd_byte *buf, int bufsize, bfd_boolean *p_uses_l32r) { static xtensa_insnbuf insnbuf = NULL; @@ -4058,7 +4870,7 @@ get_expanded_call_opcode (bfd_byte *buf, int bufsize, bfd_boolean *p_uses_l32r) || xtensa_format_get_slot (isa, fmt, 0, insnbuf, slotbuf)) return XTENSA_UNDEFINED; opcode = xtensa_opcode_decode (isa, fmt, 0, slotbuf); - if (opcode == XTENSA_UNDEFINED + if (opcode == XTENSA_UNDEFINED || !is_indirect_call_opcode (opcode)) return XTENSA_UNDEFINED; @@ -4089,7 +4901,7 @@ get_expanded_call_opcode (bfd_byte *buf, int bufsize, bfd_boolean *p_uses_l32r) For efficiency, an r_reloc also contains a "target_offset" field to cache the target-section-relative offset value that is represented by the relocation. - + The r_reloc also contains a virtual offset that allows multiple inserted literals to be placed at the same "address" with different offsets. */ @@ -4216,7 +5028,7 @@ print_r_reloc (FILE *fp, const r_reloc *r_rel) fprintf (fp, " + "); fprintf_vma (fp, r_rel->virtual_offset); } - + fprintf (fp, ")"); } @@ -4336,7 +5148,7 @@ typedef struct value_map_hash_table_struct value_map_hash_table; struct literal_value_struct { - r_reloc r_rel; + r_reloc r_rel; unsigned long value; bfd_boolean is_abs_literal; }; @@ -4377,7 +5189,7 @@ literal_value_equal (const literal_value *src1, { struct elf_link_hash_entry *h1, *h2; - if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) + if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel)) return FALSE; if (r_reloc_is_const (&src1->r_rel)) @@ -4389,13 +5201,13 @@ literal_value_equal (const literal_value *src1, if (src1->r_rel.target_offset != src2->r_rel.target_offset) return FALSE; - + if (src1->r_rel.virtual_offset != src2->r_rel.virtual_offset) return FALSE; if (src1->value != src2->value) return FALSE; - + /* Now check for the same section (if defined) or the same elf_hash (if undefined or weak). */ h1 = r_reloc_get_hash_entry (&src1->r_rel); @@ -4437,7 +5249,7 @@ value_map_hash_table_init (void) values->count = 0; values->buckets = (value_map **) bfd_zmalloc (sizeof (value_map *) * values->bucket_count); - if (values->buckets == NULL) + if (values->buckets == NULL) { free (values); return NULL; @@ -4476,7 +5288,7 @@ literal_value_hash (const literal_value *src) hash_val += hash_bfd_vma (src->is_abs_literal * 1000); hash_val += hash_bfd_vma (src->r_rel.target_offset); hash_val += hash_bfd_vma (src->r_rel.virtual_offset); - + /* Now check for the same section and the same elf_hash. */ if (r_reloc_is_defined (&src->r_rel)) sec_or_hash = r_reloc_get_section (&src->r_rel); @@ -4542,7 +5354,7 @@ add_value_map (value_map_hash_table *map, *bucket_p = val_e; map->count++; /* FIXME: Consider resizing the hash table if we get too many entries. */ - + return val_e; } @@ -4682,7 +5494,7 @@ adjust_fill_action (text_action *ta, int fill_diff) "unreachable_space" bytes can be freely contracted. Note that a negative removed value is a fill. */ -static void +static void text_action_add (text_action_list *l, text_action_t action, asection *sec, @@ -4703,12 +5515,20 @@ text_action_add (text_action_list *l, for (m_p = &l->head; *m_p && (*m_p)->offset <= offset; m_p = &(*m_p)->next) { text_action *t = *m_p; - /* When the action is another fill at the same address, - just increase the size. */ - if (t->offset == offset && t->action == ta_fill && action == ta_fill) + + if (action == ta_fill) { - t->removed_bytes += removed; - return; + /* When the action is another fill at the same address, + just increase the size. */ + if (t->offset == offset && t->action == ta_fill) + { + t->removed_bytes += removed; + return; + } + /* Fills need to happen before widens so that we don't + insert fill bytes into the instruction stream. */ + if (t->offset == offset && t->action == ta_widen_insn) + break; } } @@ -4793,7 +5613,7 @@ removed_by_actions (text_action **p_start_action, } -static bfd_vma +static bfd_vma offset_with_removed_text (text_action_list *action_list, bfd_vma offset) { text_action *r = action_list->head; @@ -4881,7 +5701,7 @@ print_action_list (FILE *fp, text_action_list *action_list) fprintf (fp, "%s: %s[0x%lx] \"%s\" %d\n", r->sec->owner->filename, - r->sec->name, r->offset, t, r->removed_bytes); + r->sec->name, (unsigned long) r->offset, t, r->removed_bytes); } } @@ -4931,9 +5751,9 @@ add_removed_literal (removed_literal_list *removed_list, else new_r->to.abfd = NULL; new_r->next = NULL; - + r = removed_list->head; - if (r == NULL) + if (r == NULL) { removed_list->head = new_r; removed_list->tail = new_r; @@ -4946,7 +5766,7 @@ add_removed_literal (removed_literal_list *removed_list, } else { - while (r->from.target_offset < from->target_offset && r->next) + while (r->from.target_offset < from->target_offset && r->next) { r = r->next; } @@ -5024,7 +5844,7 @@ struct xtensa_relax_info_struct reallocated, the newly allocated relocations will be referenced here along with the actual size allocated. The relocation count will always be found in the section structure. */ - Elf_Internal_Rela *allocated_relocs; + Elf_Internal_Rela *allocated_relocs; unsigned relocs_count; unsigned allocated_relocs_count; }; @@ -5090,7 +5910,7 @@ init_xtensa_relax_info (asection *sec) relax_info->fix_array = NULL; relax_info->fix_array_count = 0; - relax_info->allocated_relocs = NULL; + relax_info->allocated_relocs = NULL; relax_info->relocs_count = 0; relax_info->allocated_relocs_count = 0; } @@ -5110,11 +5930,11 @@ struct reloc_bfd_fix_struct asection *src_sec; bfd_vma src_offset; unsigned src_type; /* Relocation type. */ - + asection *target_sec; bfd_vma target_offset; bfd_boolean translated; - + reloc_bfd_fix *next; }; @@ -5245,7 +6065,7 @@ init_section_cache (section_cache_t *sec_cache) static void -clear_section_cache (section_cache_t *sec_cache) +free_section_cache (section_cache_t *sec_cache) { if (sec_cache->sec) { @@ -5253,7 +6073,6 @@ clear_section_cache (section_cache_t *sec_cache) release_internal_relocs (sec_cache->sec, sec_cache->relocs); if (sec_cache->ptbl) free (sec_cache->ptbl); - memset (sec_cache, 0, sizeof (sec_cache)); } } @@ -5294,8 +6113,8 @@ section_cache_section (section_cache_t *sec_cache, goto err; /* Fill in the new section cache. */ - clear_section_cache (sec_cache); - memset (sec_cache, 0, sizeof (sec_cache)); + free_section_cache (sec_cache); + init_section_cache (sec_cache); sec_cache->sec = sec; sec_cache->contents = contents; @@ -5726,7 +6545,7 @@ retrieve_contents (bfd *abfd, asection *sec, bfd_boolean keep_memory) sec_size = bfd_get_section_limit (abfd, sec); contents = elf_section_data (sec)->this_hdr.contents; - + if (contents == NULL && sec_size != 0) { if (!bfd_malloc_and_get_section (abfd, sec, &contents)) @@ -5735,7 +6554,7 @@ retrieve_contents (bfd *abfd, asection *sec, bfd_boolean keep_memory) free (contents); return NULL; } - if (keep_memory) + if (keep_memory) elf_section_data (sec)->this_hdr.contents = contents; } return contents; @@ -5810,12 +6629,12 @@ static bfd_boolean compute_removed_literals (bfd *, asection *, struct bfd_link_info *, value_map_hash_table *); static Elf_Internal_Rela *get_irel_at_offset (asection *, Elf_Internal_Rela *, bfd_vma); -static bfd_boolean is_removable_literal +static bfd_boolean is_removable_literal (const source_reloc *, int, const source_reloc *, int, asection *, property_table_entry *, int); static bfd_boolean remove_dead_literal (bfd *, asection *, struct bfd_link_info *, Elf_Internal_Rela *, - Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); + Elf_Internal_Rela *, source_reloc *, property_table_entry *, int); static bfd_boolean identify_literal_placement (bfd *, asection *, bfd_byte *, struct bfd_link_info *, value_map_hash_table *, bfd_boolean *, Elf_Internal_Rela *, int, @@ -5845,7 +6664,7 @@ static bfd_boolean relax_property_section static bfd_boolean relax_section_symbols (bfd *, asection *); -static bfd_boolean +static bfd_boolean elf_xtensa_relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info, @@ -6008,7 +6827,7 @@ find_relaxable_sections (bfd *abfd, internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); - if (internal_relocs == NULL) + if (internal_relocs == NULL) return ok; contents = retrieve_contents (abfd, sec, link_info->keep_memory); @@ -6019,7 +6838,7 @@ find_relaxable_sections (bfd *abfd, } source_relax_info = get_xtensa_relax_info (sec); - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; r_reloc r_rel; @@ -6099,9 +6918,9 @@ collect_source_relocs (bfd *abfd, unsigned i; bfd_size_type sec_size; - internal_relocs = retrieve_internal_relocs (abfd, sec, + internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); - if (internal_relocs == NULL) + if (internal_relocs == NULL) return ok; sec_size = bfd_get_section_limit (abfd, sec); @@ -6113,7 +6932,7 @@ collect_source_relocs (bfd *abfd, } /* Record relocations against relaxable literal sections. */ - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; r_reloc r_rel; @@ -6171,7 +6990,7 @@ collect_source_relocs (bfd *abfd, relocations associated with ASM_EXPANDs because they were just added in the preceding loop over the relocations. */ - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; bfd_boolean is_reachable; @@ -6210,7 +7029,7 @@ collect_source_relocs (bfd *abfd, the l32r_irel. Note: The src_relocs array is not yet sorted, but it wouldn't matter anyway because we're searching by source offset instead of target offset. */ - s_reloc = find_source_reloc (target_relax_info->src_relocs, + s_reloc = find_source_reloc (target_relax_info->src_relocs, target_relax_info->src_next, sec, l32r_irel); BFD_ASSERT (s_reloc); @@ -6269,7 +7088,7 @@ is_resolvable_asm_expansion (bfd *abfd, if (contents == NULL) return FALSE; - if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) + if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND) return FALSE; sec_size = bfd_get_section_limit (abfd, sec); @@ -6278,7 +7097,7 @@ is_resolvable_asm_expansion (bfd *abfd, /* Optimization of longcalls that use CONST16 is not yet implemented. */ if (!uses_l32r) return FALSE; - + direct_call_opcode = swap_callx_for_call_opcode (opcode); if (direct_call_opcode == XTENSA_UNDEFINED) return FALSE; @@ -6297,7 +7116,7 @@ is_resolvable_asm_expansion (bfd *abfd, shouldn't crash regardless. */ if (!target_sec->output_section) return FALSE; - + /* For relocatable sections, we can only simplify when the output section of the target is the same as the output section of the source. */ @@ -6310,7 +7129,7 @@ is_resolvable_asm_expansion (bfd *abfd, + sec->output_offset + irel->r_offset + 3); dest_address = (target_sec->output_section->vma + target_sec->output_offset + target_offset); - + *is_reachable_p = pcrel_reloc_fits (direct_call_opcode, 0, self_address, dest_address); @@ -6331,7 +7150,7 @@ find_associated_l32r_irel (bfd *abfd, { unsigned i; - for (i = 0; i < sec->reloc_count; i++) + for (i = 0; i < sec->reloc_count; i++) { Elf_Internal_Rela *irel = &internal_relocs[i]; @@ -6548,7 +7367,7 @@ prev_instr_is_a_loop (bfd_byte *contents, return FALSE; prev_opcode = insn_decode_opcode (contents, content_length, offset-3, 0); return (xtensa_opcode_is_loop (xtensa_default_isa, prev_opcode) == 1); -} +} /* Find all of the possible actions for an extended basic block. */ @@ -6598,7 +7417,7 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table) insn_len = insn_decode_len (ebb->contents, ebb->content_length, offset); - if (insn_len == 0) + if (insn_len == 0) goto decode_error; if (check_branch_target_aligned_address (offset, insn_len)) @@ -6627,7 +7446,7 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table) { bfd_size_type simplify_size; - simplify_size = get_asm_simplify_size (ebb->contents, + simplify_size = get_asm_simplify_size (ebb->contents, ebb->content_length, irel->r_offset); if (simplify_size == 0) @@ -6635,7 +7454,7 @@ compute_ebb_proposed_actions (ebb_constraint *ebb_table) ebb_propose_action (ebb_table, EBB_NO_ALIGN, 0, ta_convert_longcall, offset, 0, TRUE); - + offset += simplify_size; continue; } @@ -6982,7 +7801,7 @@ struct xlate_map }; -static int +static int xlate_compare (const void *a_v, const void *b_v) { const xlate_map_entry_t *a = (const xlate_map_entry_t *) a_v; @@ -7000,7 +7819,6 @@ xlate_offset_with_removed_text (const xlate_map_t *map, text_action_list *action_list, bfd_vma offset) { - xlate_map_entry_t tmp; void *r; xlate_map_entry_t *e; @@ -7010,14 +7828,10 @@ xlate_offset_with_removed_text (const xlate_map_t *map, if (map->entry_count == 0) return offset; - tmp.orig_address = offset; - tmp.new_address = offset; - tmp.size = 1; - r = bsearch (&offset, map->entry, map->entry_count, sizeof (xlate_map_entry_t), &xlate_compare); e = (xlate_map_entry_t *) r; - + BFD_ASSERT (e != NULL); if (e == NULL) return offset; @@ -7042,7 +7856,7 @@ build_xlate_map (asection *sec, xtensa_relax_info *relax_info) return NULL; num_actions = action_list_count (action_list); - map->entry = (xlate_map_entry_t *) + map->entry = (xlate_map_entry_t *) bfd_malloc (sizeof (xlate_map_entry_t) * (num_actions + 1)); if (map->entry == NULL) { @@ -7050,7 +7864,7 @@ build_xlate_map (asection *sec, xtensa_relax_info *relax_info) return NULL; } map->entry_count = 0; - + removed = 0; current_entry = &map->entry[0]; @@ -7105,7 +7919,7 @@ build_xlate_map (asection *sec, xtensa_relax_info *relax_info) /* Free an offset translation map. */ -static void +static void free_xlate_map (xlate_map_t *map) { if (map && map->entry) @@ -7337,7 +8151,7 @@ compute_fill_extra_space (property_table_entry *entry) add an entry to the per-section list of removed literals. The actual changes are deferred until the next pass. */ -static bfd_boolean +static bfd_boolean compute_removed_literals (bfd *abfd, asection *sec, struct bfd_link_info *link_info, @@ -7364,7 +8178,7 @@ compute_removed_literals (bfd *abfd, if (!relax_info->is_relaxable_literal_section) return ok; - internal_relocs = retrieve_internal_relocs (abfd, sec, + internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); sec_size = bfd_get_section_limit (abfd, sec); @@ -7416,14 +8230,14 @@ compute_removed_literals (bfd *abfd, continue; prev_i = i; - if (last_loc_is_prev && + if (last_loc_is_prev && last_target_offset + 4 != rel->r_rel.target_offset) last_loc_is_prev = FALSE; /* Check if the relocation was from an L32R that is being removed because a CALLX was converted to a direct CALL, and check if there are no other relocations to the literal. */ - if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, + if (is_removable_literal (rel, i, src_relocs, relax_info->src_count, sec, prop_table, ptblsize)) { if (!remove_dead_literal (abfd, sec, link_info, internal_relocs, @@ -7437,8 +8251,8 @@ compute_removed_literals (bfd *abfd, } if (!identify_literal_placement (abfd, sec, contents, link_info, - values, - &last_loc_is_prev, irel, + values, + &last_loc_is_prev, irel, relax_info->src_count - i, rel, prop_table, ptblsize, &target_sec_cache, rel->is_abs_literal)) @@ -7455,8 +8269,9 @@ compute_removed_literals (bfd *abfd, #endif /* DEBUG */ error_return: - if (prop_table) free (prop_table); - clear_section_cache (&target_sec_cache); + if (prop_table) + free (prop_table); + free_section_cache (&target_sec_cache); release_contents (sec, contents); release_internal_relocs (sec, internal_relocs); @@ -7474,7 +8289,7 @@ get_irel_at_offset (asection *sec, unsigned r_type; Elf_Internal_Rela key; - if (!internal_relocs) + if (!internal_relocs) return NULL; key.r_offset = offset; @@ -7518,8 +8333,8 @@ is_removable_literal (const source_reloc *rel, if (!rel->is_null) return FALSE; - - entry = elf_xtensa_find_property_entry (prop_table, ptblsize, + + entry = elf_xtensa_find_property_entry (prop_table, ptblsize, sec->vma + rel->r_rel.target_offset); if (entry && (entry->flags & XTENSA_PROP_NO_TRANSFORM)) return FALSE; @@ -7540,7 +8355,7 @@ is_removable_literal (const source_reloc *rel, } -bfd_boolean +bfd_boolean remove_dead_literal (bfd *abfd, asection *sec, struct bfd_link_info *link_info, @@ -7567,7 +8382,7 @@ remove_dead_literal (bfd *abfd, ta_remove_literal, sec, rel->r_rel.target_offset, 4); /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2) + if (sec->alignment_power > 2) { int fill_extra_space; bfd_vma entry_sec_offset; @@ -7611,7 +8426,7 @@ remove_dead_literal (bfd *abfd, } -bfd_boolean +bfd_boolean identify_literal_placement (bfd *abfd, asection *sec, bfd_byte *contents, @@ -7681,7 +8496,7 @@ identify_literal_placement (bfd *abfd, /* For relocatable links, do not try to move literals. To do it correctly might increase the number of relocations in an input section making the default relocatable linking fail. */ - if (!link_info->relocatable && !literal_placed + if (!link_info->relocatable && !literal_placed && values->has_last_loc && !(*last_loc_is_prev_p)) { asection *target_sec = r_reloc_get_section (&values->last_loc); @@ -7694,7 +8509,7 @@ identify_literal_placement (bfd *abfd, /* There is a last loc that was in the same output section. */ if (relocations_reach (rel, remaining_src_rels, &try_loc) && move_shared_literal (sec, link_info, rel, - prop_table, ptblsize, + prop_table, ptblsize, &try_loc, &val, target_sec_cache)) { values->last_loc.virtual_offset += 4; @@ -7794,7 +8609,7 @@ relocations_reach (source_reloc *reloc, /* Move a literal to another literal location because it is the same as the other literal value. */ -static bfd_boolean +static bfd_boolean coalesce_shared_literal (asection *sec, source_reloc *rel, property_table_entry *prop_table, @@ -7823,7 +8638,7 @@ coalesce_shared_literal (asection *sec, ta_remove_literal, sec, rel->r_rel.target_offset, 4); /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2) + if (sec->alignment_power > 2) { int fill_extra_space; bfd_vma entry_sec_offset; @@ -7859,7 +8674,7 @@ coalesce_shared_literal (asection *sec, total amount of space used because of alignments so we need to do this carefully. Also, it may make a branch go out of range. */ -static bfd_boolean +static bfd_boolean move_shared_literal (asection *sec, struct bfd_link_info *link_info, source_reloc *rel, @@ -7902,7 +8717,7 @@ move_shared_literal (asection *sec, return FALSE; target_entry = elf_xtensa_find_property_entry - (target_sec_cache->ptbl, target_sec_cache->pte_count, + (target_sec_cache->ptbl, target_sec_cache->pte_count, target_sec->vma + target_loc->target_offset); if (!target_entry) @@ -7913,7 +8728,7 @@ move_shared_literal (asection *sec, init_ebb_constraint (&ebb_table); ebb = &ebb_table.ebb; - init_ebb (ebb, target_sec_cache->sec, target_sec_cache->contents, + init_ebb (ebb, target_sec_cache->sec, target_sec_cache->contents, target_sec_cache->content_length, target_sec_cache->ptbl, target_sec_cache->pte_count, target_sec_cache->relocs, target_sec_cache->reloc_count); @@ -7925,24 +8740,24 @@ move_shared_literal (asection *sec, -4 - (1 << target_sec->alignment_power), TRUE); /* Check all of the PC-relative relocations to make sure they still fit. */ - relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec, + relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec, target_sec_cache->contents, target_sec_cache->relocs, &ebb_table, NULL); - if (!relocs_fit) + if (!relocs_fit) return FALSE; text_action_add_literal (&target_relax_info->action_list, ta_add_literal, target_loc, lit_value, -4); - if (target_sec->alignment_power > 2 && target_entry != src_entry) + if (target_sec->alignment_power > 2 && target_entry != src_entry) { /* May need to add or remove some fill to maintain alignment. */ int fill_extra_space; bfd_vma entry_sec_offset; - entry_sec_offset = + entry_sec_offset = target_entry->address - target_sec->vma + target_entry->size; /* If the literal range is at the end of the section, @@ -7975,7 +8790,7 @@ move_shared_literal (asection *sec, ta_remove_literal, sec, rel->r_rel.target_offset, 4); /* If the section is 4-byte aligned, do not add fill. */ - if (sec->alignment_power > 2 && target_entry != src_entry) + if (sec->alignment_power > 2 && target_entry != src_entry) { int fill_extra_space; bfd_vma entry_sec_offset; @@ -8039,8 +8854,11 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) return relax_property_section (abfd, sec, link_info); } - internal_relocs = retrieve_internal_relocs (abfd, sec, + internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); + if (!internal_relocs && !relax_info->action_list.head) + return TRUE; + contents = retrieve_contents (abfd, sec, link_info->keep_memory); if (contents == NULL && sec_size != 0) { @@ -8143,9 +8961,9 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) that here and adjust things accordingly. */ if (! elf_xtensa_ignore_discarded_relocs (sec) && elf_xtensa_action_discarded (sec) == PRETEND - && sec->sec_info_type != ELF_INFO_TYPE_STABS + && sec->sec_info_type != SEC_INFO_TYPE_STABS && target_sec != NULL - && elf_discarded_section (target_sec)) + && discarded_section (target_sec)) { /* It would be natural to call _bfd_elf_check_kept_section here, but it's not exported from elflink.c. It's also a @@ -8366,7 +9184,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) dup_dot += copy_size; } virtual_action = TRUE; - } + } else BFD_ASSERT (action->virtual_offset <= orig_dot_vo); } @@ -8437,7 +9255,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) relax_info, &internal_relocs, &action->value)) goto error_return; - if (virtual_action) + if (virtual_action) orig_dot_vo += copy_size; orig_dot += orig_insn_size; @@ -8502,7 +9320,7 @@ relax_section (bfd *abfd, asection *sec, struct bfd_link_info *link_info) } -static bfd_boolean +static bfd_boolean translate_section_fixes (asection *sec) { xtensa_relax_info *relax_info; @@ -8523,7 +9341,7 @@ translate_section_fixes (asection *sec) /* Translate a fix given the mapping in the relax info for the target section. If it has already been translated, no work is required. */ -static bfd_boolean +static bfd_boolean translate_reloc_bfd_fix (reloc_bfd_fix *fix) { reloc_bfd_fix new_fix; @@ -8569,7 +9387,7 @@ translate_reloc_bfd_fix (reloc_bfd_fix *fix) target_offset); } - if (removed) + if (removed) { asection *new_sec; @@ -8579,11 +9397,11 @@ translate_reloc_bfd_fix (reloc_bfd_fix *fix) /* This was moved to some other address (possibly another section). */ new_sec = r_reloc_get_section (&removed->to); - if (new_sec != sec) + if (new_sec != sec) { sec = new_sec; relax_info = get_xtensa_relax_info (sec); - if (!relax_info || + if (!relax_info || (!relax_info->is_relaxable_literal_section && !relax_info->is_relaxable_asm_section)) { @@ -8717,6 +9535,9 @@ shrink_dynamic_reloc_sections (struct bfd_link_info *info, bfd_boolean dynamic_symbol; htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); @@ -8825,12 +9646,10 @@ move_literal (bfd *abfd, { int r_type; unsigned i; - asection *target_sec; reloc_bfd_fix *fix; unsigned insert_at; r_type = ELF32_R_TYPE (r_rel->rela.r_info); - target_sec = r_reloc_get_section (r_rel); /* This is the difficult case. We have to create a fix up. */ this_rela.r_offset = offset; @@ -8871,7 +9690,7 @@ move_literal (bfd *abfd, BFD_ASSERT (relax_info->allocated_relocs == NULL || sec->reloc_count == relax_info->relocs_count); - if (relax_info->allocated_relocs_count == 0) + if (relax_info->allocated_relocs_count == 0) new_relocs_count = (sec->reloc_count + 2) * 2; else new_relocs_count = (relax_info->allocated_relocs_count + 2) * 2; @@ -8891,7 +9710,7 @@ move_literal (bfd *abfd, if (insert_at != sec->reloc_count) memcpy (new_relocs + insert_at + 1, (*internal_relocs_p) + insert_at, - (sec->reloc_count - insert_at) + (sec->reloc_count - insert_at) * sizeof (Elf_Internal_Rela)); if (*internal_relocs_p != relax_info->allocated_relocs) @@ -8950,7 +9769,7 @@ relax_property_section (bfd *abfd, bfd_size_type entry_size; sec_size = bfd_get_section_limit (abfd, sec); - internal_relocs = retrieve_internal_relocs (abfd, sec, + internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); contents = retrieve_contents (abfd, sec, link_info->keep_memory); if (contents == NULL && sec_size != 0) @@ -9175,7 +9994,7 @@ relax_property_section (bfd *abfd, actual_offset = offset - removed_bytes; size = bfd_get_32 (abfd, &contents[actual_offset + 4]); - if (is_full_prop_section) + if (is_full_prop_section) flags = bfd_get_32 (abfd, &contents[actual_offset + 8]); else flags = predef_flags; @@ -9203,7 +10022,7 @@ relax_property_section (bfd *abfd, bfd_vma new_address = (offset_rel->r_addend + bfd_get_32 (abfd, &contents[actual_offset])); - if (is_full_prop_section) + if (is_full_prop_section) old_flags = bfd_get_32 (abfd, &contents[last_irel->r_offset + 8]); else @@ -9232,12 +10051,7 @@ relax_property_section (bfd *abfd, if (remove_this_rel) { offset_rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE); - /* In case this is the last entry, move the relocation offset - to the previous entry, if there is one. */ - if (offset_rel->r_offset >= bytes_to_remove) - offset_rel->r_offset -= bytes_to_remove; - else - offset_rel->r_offset = 0; + offset_rel->r_offset = 0; } if (bytes_to_remove != 0) @@ -9452,12 +10266,15 @@ elf_xtensa_get_plt_section (struct bfd_link_info *info, int chunk) if (chunk == 0) { htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return NULL; + return htab->splt; } dynobj = elf_hash_table (info)->dynobj; sprintf (plt_name, ".plt.%u", chunk); - return bfd_get_section_by_name (dynobj, plt_name); + return bfd_get_linker_section (dynobj, plt_name); } @@ -9471,12 +10288,14 @@ elf_xtensa_get_gotplt_section (struct bfd_link_info *info, int chunk) if (chunk == 0) { htab = elf_xtensa_hash_table (info); + if (htab == NULL) + return NULL; return htab->sgotplt; } dynobj = elf_hash_table (info)->dynobj; sprintf (got_name, ".got.plt.%u", chunk); - return bfd_get_section_by_name (dynobj, got_name); + return bfd_get_linker_section (dynobj, got_name); } @@ -9619,7 +10438,7 @@ pcrel_reloc_fits (xtensa_opcode opc, } -static bfd_boolean +static bfd_boolean xtensa_is_property_section (asection *sec) { if (xtensa_is_insntable_section (sec) @@ -9631,7 +10450,7 @@ xtensa_is_property_section (asection *sec) } -static bfd_boolean +static bfd_boolean xtensa_is_insntable_section (asection *sec) { if (CONST_STRNEQ (sec->name, XTENSA_INSN_SEC_NAME) @@ -9642,7 +10461,7 @@ xtensa_is_insntable_section (asection *sec) } -static bfd_boolean +static bfd_boolean xtensa_is_littable_section (asection *sec) { if (CONST_STRNEQ (sec->name, XTENSA_LIT_SEC_NAME) @@ -9653,7 +10472,7 @@ xtensa_is_littable_section (asection *sec) } -static bfd_boolean +static bfd_boolean xtensa_is_proptable_section (asection *sec) { if (CONST_STRNEQ (sec->name, XTENSA_PROP_SEC_NAME) @@ -9706,7 +10525,7 @@ match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) { const char *gname = inf; const char *group_name = elf_group_name (sec); - + return (group_name == gname || (group_name != NULL && gname != NULL @@ -9716,12 +10535,11 @@ match_section_group (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *inf) static int linkonce_len = sizeof (".gnu.linkonce.") - 1; -asection * -xtensa_get_property_section (asection *sec, const char *base_name) +static char * +xtensa_property_section_name (asection *sec, const char *base_name) { const char *suffix, *group_name; char *prop_sec_name; - asection *prop_sec; group_name = elf_group_name (sec); if (group_name) @@ -9739,9 +10557,9 @@ xtensa_get_property_section (asection *sec, const char *base_name) { char *linkonce_kind = 0; - if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0) + if (strcmp (base_name, XTENSA_INSN_SEC_NAME) == 0) linkonce_kind = "x."; - else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0) + else if (strcmp (base_name, XTENSA_LIT_SEC_NAME) == 0) linkonce_kind = "p."; else if (strcmp (base_name, XTENSA_PROP_SEC_NAME) == 0) linkonce_kind = "prop."; @@ -9763,10 +10581,36 @@ xtensa_get_property_section (asection *sec, const char *base_name) else prop_sec_name = strdup (base_name); + return prop_sec_name; +} + + +static asection * +xtensa_get_property_section (asection *sec, const char *base_name) +{ + char *prop_sec_name; + asection *prop_sec; + + prop_sec_name = xtensa_property_section_name (sec, base_name); + prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name, + match_section_group, + (void *) elf_group_name (sec)); + free (prop_sec_name); + return prop_sec; +} + + +asection * +xtensa_make_property_section (asection *sec, const char *base_name) +{ + char *prop_sec_name; + asection *prop_sec; + /* Check if the section already exists. */ + prop_sec_name = xtensa_property_section_name (sec, base_name); prop_sec = bfd_get_section_by_name_if (sec->owner, prop_sec_name, match_section_group, - (void *) group_name); + (void *) elf_group_name (sec)); /* If not, create it. */ if (! prop_sec) { @@ -9779,7 +10623,7 @@ xtensa_get_property_section (asection *sec, const char *base_name) if (! prop_sec) return 0; - elf_group_name (prop_sec) = group_name; + elf_group_name (prop_sec) = elf_group_name (sec); } free (prop_sec_name); @@ -9830,7 +10674,7 @@ xtensa_callback_required_dependence (bfd *abfd, /* Find the corresponding ".got.plt*" section. */ if (sec->name[4] == '\0') - sgotplt = bfd_get_section_by_name (sec->owner, ".got.plt"); + sgotplt = bfd_get_linker_section (sec->owner, ".got.plt"); else { char got_name[14]; @@ -9840,7 +10684,7 @@ xtensa_callback_required_dependence (bfd *abfd, chunk = strtol (&sec->name[5], NULL, 10); sprintf (got_name, ".got.plt.%u", chunk); - sgotplt = bfd_get_section_by_name (sec->owner, got_name); + sgotplt = bfd_get_linker_section (sec->owner, got_name); } BFD_ASSERT (sgotplt); @@ -9855,7 +10699,7 @@ xtensa_callback_required_dependence (bfd *abfd, if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) return ok; - internal_relocs = retrieve_internal_relocs (abfd, sec, + internal_relocs = retrieve_internal_relocs (abfd, sec, link_info->keep_memory); if (internal_relocs == NULL || sec->reloc_count == 0) @@ -9913,6 +10757,7 @@ static const struct bfd_elf_special_section elf_xtensa_special_sections[] = { NULL, 0, 0, 0, 0 } }; +#define ELF_TARGET_ID XTENSA_ELF_DATA #ifndef ELF_ARCH #define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec #define TARGET_LITTLE_NAME "elf32-xtensa-le" @@ -9939,6 +10784,8 @@ static const struct bfd_elf_special_section elf_xtensa_special_sections[] = #define elf_info_to_howto elf_xtensa_info_to_howto_rela +#define bfd_elf32_mkobject elf_xtensa_mkobject + #define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data #define bfd_elf32_new_section_hook elf_xtensa_new_section_hook #define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data @@ -9966,9 +10813,11 @@ static const struct bfd_elf_special_section elf_xtensa_special_sections[] = #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_always_size_sections elf_xtensa_always_size_sections #define elf_backend_omit_section_dynsym \ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) #define elf_backend_special_sections elf_xtensa_special_sections #define elf_backend_action_discarded elf_xtensa_action_discarded +#define elf_backend_copy_indirect_symbol elf_xtensa_copy_indirect_symbol #include "elf32-target.h"