diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6c3dd562002..0b753bfa20f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,45 @@ +2008-08-20 Bob Wilson + + * elf-bfd.h (elf_object_id): Add XTENSA_ELF_TDATA. + * elf32-xtensa.c (elf_howto_table): Add TLS relocations. + (elf_xtensa_reloc_type_lookup): Likewise. + (TCB_SIZE): Define. + (elf_xtensa_link_hash_entry): New. + (GOT_UNKNOWN, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE, GOT_TLS_ANY): Define. + (elf_xtensa_hash_entry): Define. + (elf_xtensa_obj_tdata): New. + (elf_xtensa_tdata): Define. + (elf_xtensa_local_got_tls_type): Define. + (elf_xtensa_local_tlsfunc_refcounts): Define. + (is_xtensa_elf): Define. + (elf_xtensa_mkobject): New. + (elf_xtensa_link_hash_table): Add tlsbase field. + (elf_xtensa_link_hash_newfunc): New. + (elf_xtensa_link_hash_table_create): Use elf_xtensa_link_hash_newfunc. + Create an entry for "_TLS_MODULE_BASE_" and save it in tlsbase field. + (elf_xtensa_copy_indirect_symbol): New. + (elf_xtensa_check_relocs): Rewrite to handle TLS relocations. + (elf_xtensa_gc_sweep_hook): Likewise. + (elf_xtensa_allocate_dynrelocs): Optimize away GOT entries for + TLSDESC_FN relocations when an IE reference is seen. + (elf_xtensa_allocate_local_got_size): Likewise. + (elf_xtensa_always_size_sections): New. + (dtpoff_base, tpoff): New. + (elf_xtensa_do_reloc): Handle TLS relocations. + (replace_tls_insn): New. + (IS_XTENSA_TLS_RELOC): Define. + (elf_xtensa_relocate_section): Handle TLS relocations. + (get_indirect_call_dest_reg): New. + (bfd_elf32_mkobject): Define. + (elf_backend_always_size_sections): New. + (elf_backend_copy_indirect_symbol): New. + * reloc.c (BFD_RELOC_XTENSA_TLSDESC_FN, BFD_RELOC_XTENSA_TLSDESC_ARG) + (BFD_RELOC_XTENSA_TLS_DTPOFF, BFD_RELOC_XTENSA_TLS_TPOFF) + (BFD_RELOC_XTENSA_TLS_FUNC, BFD_RELOC_XTENSA_TLS_ARG) + (BFD_RELOC_XTENSA_TLS_CALL): New. + * bfd-in2.h: Regenerate. + * libbfd.h: Regenerate. + 2008-08-18 Richard Sandiford * elfxx-mips.c (_bfd_mips_elf_copy_indirect_symbol): Copy MIPS16 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index a39c46162f3..c8ef5f903c2 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -4369,6 +4369,15 @@ internally by the linker after analysis of a BFD_RELOC_XTENSA_ASM_EXPAND. */ BFD_RELOC_XTENSA_ASM_SIMPLIFY, +/* Xtensa TLS relocations. */ + BFD_RELOC_XTENSA_TLSDESC_FN, + BFD_RELOC_XTENSA_TLSDESC_ARG, + BFD_RELOC_XTENSA_TLS_DTPOFF, + BFD_RELOC_XTENSA_TLS_TPOFF, + BFD_RELOC_XTENSA_TLS_FUNC, + BFD_RELOC_XTENSA_TLS_ARG, + BFD_RELOC_XTENSA_TLS_CALL, + /* 8 bit signed offset in (ix+d) or (iy+d). */ BFD_RELOC_Z80_DISP8, diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 2b739f94212..993458eb530 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1418,6 +1418,7 @@ enum elf_object_id SH_ELF_TDATA, SPARC_ELF_TDATA, X86_64_ELF_TDATA, + XTENSA_ELF_TDATA, GENERIC_ELF_TDATA }; diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c index a618d3bbbba..3463efa8c34 100644 --- a/bfd/elf32-xtensa.c +++ b/bfd/elf32-xtensa.c @@ -288,6 +288,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 @@ -375,6 +398,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) @@ -479,6 +530,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_TDATA) + +static bfd_boolean +elf_xtensa_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct elf_xtensa_obj_tdata), + XTENSA_ELF_TDATA); +} + /* Xtensa ELF linker hash table. */ struct elf_xtensa_link_hash_table @@ -501,6 +602,8 @@ 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. */ @@ -508,11 +611,41 @@ struct elf_xtensa_link_hash_table #define elf_xtensa_hash_table(p) \ ((struct elf_xtensa_link_hash_table *) ((p)->hash)) +/* 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); @@ -521,8 +654,8 @@ elf_xtensa_link_hash_table_create (bfd *abfd) 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))) { free (ret); return NULL; @@ -538,9 +671,46 @@ elf_xtensa_link_hash_table_create (bfd *abfd) 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) @@ -800,9 +970,11 @@ 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); symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); @@ -812,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); @@ -824,46 +1001,94 @@ 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; } + eh = elf_xtensa_hash_entry (h); switch (r_type) { - case R_XTENSA_32: - if (h == NULL) - goto local_literal; - - if ((sec->flags & SEC_ALLOC) != 0) + case R_XTENSA_TLSDESC_FN: + 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; + is_tlsfunc = TRUE; + } + else + tls_type = GOT_TLS_IE; + break; + + case R_XTENSA_TLSDESC_ARG: + if (info->shared) + { + 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_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; + case R_XTENSA_TLS_DTPOFF: + if (info->shared) + tls_type = GOT_TLS_GD; + else + tls_type = GOT_TLS_IE; + break; - if ((sec->flags & SEC_ALLOC) != 0) + 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: + 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; + + default: + /* Nothing to do for any other relocations. */ + continue; + } + + if (h) + { + if (is_plt) { - if (h->plt.refcount <= 0) - { - h->needs_plt = 1; - h->plt.refcount = 1; - } - else - h->plt.refcount += 1; + h->plt.refcount += 1; + h->needs_plt = 1; /* Keep track of the total PLT relocation count even if we don't yet know whether the dynamic sections will be @@ -876,49 +1101,77 @@ elf_xtensa_check_relocs (bfd *abfd, return FALSE; } } - break; + else if (is_got) + h->got.refcount += 1; - local_literal: - if ((sec->flags & SEC_ALLOC) != 0) + if (is_tlsfunc) + eh->tlsfunc_refcount += 1; + + 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; } } @@ -1004,14 +1257,16 @@ 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 (info->relocatable) return TRUE; @@ -1021,7 +1276,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++) @@ -1029,6 +1283,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) @@ -1038,31 +1296,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_TLSDESC_FN: + if (info->shared) + { + is_got = TRUE; + is_tlsfunc = TRUE; + } + break; + + 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; + + case R_XTENSA_TLS_TPOFF: + if (info->shared || h) + is_got = TRUE; + break; + case R_XTENSA_32: - if (h == NULL) - goto local_literal; - if (h->got.refcount > 0) - h->got.refcount--; + is_got = TRUE; break; case R_XTENSA_PLT: - if (h == NULL) - goto local_literal; - if (h->plt.refcount > 0) - h->plt.refcount--; - break; - - local_literal: - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; + is_plt = TRUE; break; default: - break; + 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; + } } } @@ -1200,7 +1507,7 @@ 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; @@ -1211,9 +1518,15 @@ elf_xtensa_allocate_dynrelocs (struct elf_link_hash_entry *h, void *arg) info = (struct bfd_link_info *) arg; htab = elf_xtensa_hash_table (info); - 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) @@ -1249,6 +1562,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)); @@ -1498,7 +1821,66 @@ 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); + 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 @@ -1546,6 +1928,9 @@ 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: @@ -1585,7 +1970,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); @@ -1597,6 +1981,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.... */ @@ -1936,6 +2328,188 @@ elf_xtensa_create_plt_entry (struct bfd_link_info *info, } +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; + + 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; + } + } + + 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 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. */ @@ -1956,15 +2530,20 @@ 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); 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) { @@ -1986,12 +2565,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 @@ -2027,6 +2609,7 @@ 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); } @@ -2041,6 +2624,8 @@ elf_xtensa_relocate_section (bfd *output_bfd, && !unresolved_reloc && h->root.type == bfd_link_hash_undefweak) is_weak_undef = TRUE; + + sym_type = h->type; } if (sec != NULL && elf_discarded_section (sec)) @@ -2152,27 +2737,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 != 0 + && 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; @@ -2256,6 +2863,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 @@ -2271,10 +3023,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, @@ -2284,30 +3039,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, @@ -3111,6 +3852,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) { @@ -9965,6 +10729,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 @@ -9992,9 +10758,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" diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 640b2840f53..eb84d5826e9 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2001,6 +2001,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_XTENSA_OP2", "BFD_RELOC_XTENSA_ASM_EXPAND", "BFD_RELOC_XTENSA_ASM_SIMPLIFY", + "BFD_RELOC_XTENSA_TLSDESC_FN", + "BFD_RELOC_XTENSA_TLSDESC_ARG", + "BFD_RELOC_XTENSA_TLS_DTPOFF", + "BFD_RELOC_XTENSA_TLS_TPOFF", + "BFD_RELOC_XTENSA_TLS_FUNC", + "BFD_RELOC_XTENSA_TLS_ARG", + "BFD_RELOC_XTENSA_TLS_CALL", "BFD_RELOC_Z80_DISP8", "BFD_RELOC_Z8K_DISP7", "BFD_RELOC_Z8K_CALLR", diff --git a/bfd/reloc.c b/bfd/reloc.c index 03b46bf8092..9d993af8a3d 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -1,6 +1,6 @@ /* BFD support for handling relocation entries. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Written by Cygnus Support. @@ -5015,6 +5015,22 @@ ENUMDOC assembler-expanded instructions. This is commonly used internally by the linker after analysis of a BFD_RELOC_XTENSA_ASM_EXPAND. +ENUM + BFD_RELOC_XTENSA_TLSDESC_FN +ENUMX + BFD_RELOC_XTENSA_TLSDESC_ARG +ENUMX + BFD_RELOC_XTENSA_TLS_DTPOFF +ENUMX + BFD_RELOC_XTENSA_TLS_TPOFF +ENUMX + BFD_RELOC_XTENSA_TLS_FUNC +ENUMX + BFD_RELOC_XTENSA_TLS_ARG +ENUMX + BFD_RELOC_XTENSA_TLS_CALL +ENUMDOC + Xtensa TLS relocations. ENUM BFD_RELOC_Z80_DISP8 diff --git a/gas/ChangeLog b/gas/ChangeLog index 6bee5f993a4..096f1d4c2fe 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,29 @@ +2008-08-20 Bob Wilson + + * config/tc-xtensa.c (O_tlsfunc, O_tlsarg, O_tlscall): Define. + (O_tpoff, O_dtpoff): Define. + (suffix_relocs): Add entries for TLS suffixes. + (xtensa_elf_cons): Check for invalid use of TLS relocations. + (map_operator_to_reloc): Add is_literal parameter and use it to + control translating TLS instruction relocations to the corresponding + literal relocations. + (xg_valid_literal_expression): Allow TLS operators. + (xg_build_to_insn): Copy TLS operators from pseudo-instruction + operands to generated literals. + (xg_assemble_literal): Handle TLS operators. Update call to + map_operator_to_reloc. + (md_assemble): Handle CALLXn.TLS pseudo-instruction. + (md_apply_fix): Handle TLS relocations. + (emit_single_op): Handle TLS operators. + (convert_frag_immed): Update call to map_operator_to_reloc. + (vinsn_to_insnbuf): Emit relocations for TLS-related instructions. + * config/xtensa-istack.h (tinsn_struct): Add tls_reloc field. + * config/xtensa-relax.c (append_literal_op): Add src_op parameter + to initialize the op_data field of the BuildOp. + (build_transition): Use it here to record the source operand + corresponding to a generated literal. + * config/xtensa-relax.h (build_op): Comment op_data use for literals. + 2008-08-20 H.J. Lu AVX Programming Reference (August, 2008) diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c index d2753bbb35b..b893cef4a11 100644 --- a/gas/config/tc-xtensa.c +++ b/gas/config/tc-xtensa.c @@ -356,6 +356,11 @@ op_placement_info_table op_placement_table; #define O_hi16 O_md2 /* use high 16 bits of symbolic value */ #define O_lo16 O_md3 /* use low 16 bits of symbolic value */ #define O_pcrel O_md4 /* value is a PC-relative offset */ +#define O_tlsfunc O_md5 /* TLS_FUNC/TLSDESC_FN relocation */ +#define O_tlsarg O_md6 /* TLS_ARG/TLSDESC_ARG relocation */ +#define O_tlscall O_md7 /* TLS_CALL relocation */ +#define O_tpoff O_md8 /* TPOFF relocation */ +#define O_dtpoff O_md9 /* DTPOFF relocation */ struct suffix_reloc_map { @@ -373,6 +378,11 @@ static struct suffix_reloc_map suffix_relocs[] = SUFFIX_MAP ("h", BFD_RELOC_HI16, O_hi16), SUFFIX_MAP ("plt", BFD_RELOC_XTENSA_PLT, O_pltrel), SUFFIX_MAP ("pcrel", BFD_RELOC_32_PCREL, O_pcrel), + SUFFIX_MAP ("tlsfunc", BFD_RELOC_XTENSA_TLS_FUNC, O_tlsfunc), + SUFFIX_MAP ("tlsarg", BFD_RELOC_XTENSA_TLS_ARG, O_tlsarg), + SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall), + SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff), + SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff), { (char *) 0, 0, BFD_RELOC_UNUSED, 0 } }; @@ -1553,6 +1563,10 @@ xtensa_elf_cons (int nbytes) else if (nbytes != (int) bfd_get_reloc_size (reloc_howto)) as_bad (_("%s relocations do not fit in %d bytes"), reloc_howto->name, nbytes); + else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC + || reloc == BFD_RELOC_XTENSA_TLS_ARG + || reloc == BFD_RELOC_XTENSA_TLS_CALL) + as_bad (_("invalid use of %s relocation"), reloc_howto->name); else { char *p = frag_more ((int) nbytes); @@ -1665,7 +1679,7 @@ map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc) /* Find the matching reloc type. */ static bfd_reloc_code_real_type -map_operator_to_reloc (unsigned char operator) +map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal) { struct suffix_reloc_map *sfx; bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED; @@ -1679,6 +1693,14 @@ map_operator_to_reloc (unsigned char operator) } } + if (is_literal) + { + if (reloc == BFD_RELOC_XTENSA_TLS_FUNC) + return BFD_RELOC_XTENSA_TLSDESC_FN; + else if (reloc == BFD_RELOC_XTENSA_TLS_ARG) + return BFD_RELOC_XTENSA_TLSDESC_ARG; + } + if (reloc == BFD_RELOC_UNUSED) return BFD_RELOC_32; @@ -3149,6 +3171,10 @@ xg_valid_literal_expression (const expressionS *exp) case O_subtract: case O_pltrel: case O_pcrel: + case O_tlsfunc: + case O_tlsarg: + case O_tpoff: + case O_dtpoff: return TRUE; default: return FALSE; @@ -3347,6 +3373,9 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi) case OP_LITERAL: sym = get_special_literal_symbol (); set_expr_symbol_offset (&targ->tok[op_num], sym, 0); + if (insn->tok[op_data].X_op == O_tlsfunc + || insn->tok[op_data].X_op == O_tlsarg) + copy_expr (&targ->tls_reloc, &insn->tok[op_data]); break; case OP_LABEL: sym = get_special_label_symbol (); @@ -4062,9 +4091,13 @@ xg_assemble_literal (/* const */ TInsn *insn) pcrel = TRUE; /* fall through */ case O_pltrel: + case O_tlsfunc: + case O_tlsarg: + case O_tpoff: + case O_dtpoff: p = frag_more (litsize); xtensa_set_frag_assembly_state (frag_now); - reloc = map_operator_to_reloc (emit_val->X_op); + reloc = map_operator_to_reloc (emit_val->X_op, TRUE); if (emit_val->X_add_symbol) emit_val->X_op = O_symbol; else @@ -5310,8 +5343,58 @@ md_assemble (char *str) orig_insn.insn_type = ITYPE_INSN; orig_insn.ntok = 0; orig_insn.is_specific_opcode = (has_underbar || !use_transform ()); - orig_insn.opcode = xtensa_opcode_lookup (isa, opname); + + /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its + extra argument and set the opcode to "CALLXn". */ + if (orig_insn.opcode == XTENSA_UNDEFINED + && strncasecmp (opname, "callx", 5) == 0) + { + unsigned long window_size; + char *suffix; + + window_size = strtoul (opname + 5, &suffix, 10); + if (suffix != opname + 5 + && (window_size == 0 + || window_size == 4 + || window_size == 8 + || window_size == 12) + && strcasecmp (suffix, ".tls") == 0) + { + switch (window_size) + { + case 0: orig_insn.opcode = xtensa_callx0_opcode; break; + case 4: orig_insn.opcode = xtensa_callx4_opcode; break; + case 8: orig_insn.opcode = xtensa_callx8_opcode; break; + case 12: orig_insn.opcode = xtensa_callx12_opcode; break; + } + + if (num_args != 2) + as_bad (_("wrong number of operands for '%s'"), opname); + else + { + bfd_reloc_code_real_type reloc; + char *old_input_line_pointer; + expressionS *tok = &orig_insn.tls_reloc; + segT t; + + old_input_line_pointer = input_line_pointer; + input_line_pointer = arg_strings[num_args - 1]; + + t = expression (tok); + if (tok->X_op == O_symbol + && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok)) + == BFD_RELOC_XTENSA_TLS_CALL)) + tok->X_op = map_suffix_reloc_to_operator (reloc); + else + as_bad (_("bad relocation expression for '%s'"), opname); + + input_line_pointer = old_input_line_pointer; + num_args -= 1; + } + } + } + if (orig_insn.opcode == XTENSA_UNDEFINED) { xtensa_format fmt = xtensa_format_lookup (isa, opname); @@ -5726,6 +5809,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) fixP->fx_no_overflow = 0; /* Use the standard overflow check. */ break; + case BFD_RELOC_XTENSA_TLSDESC_FN: + case BFD_RELOC_XTENSA_TLSDESC_ARG: + case BFD_RELOC_XTENSA_TLS_TPOFF: + case BFD_RELOC_XTENSA_TLS_DTPOFF: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + md_number_to_chars (fixpos, 0, fixP->fx_size); + fixP->fx_no_overflow = 0; /* Use the standard overflow check. */ + break; + case BFD_RELOC_XTENSA_SLOT0_OP: case BFD_RELOC_XTENSA_SLOT1_OP: case BFD_RELOC_XTENSA_SLOT2_OP: @@ -5766,6 +5858,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg) break; case BFD_RELOC_XTENSA_ASM_EXPAND: + case BFD_RELOC_XTENSA_TLS_FUNC: + case BFD_RELOC_XTENSA_TLS_ARG: + case BFD_RELOC_XTENSA_TLS_CALL: case BFD_RELOC_XTENSA_SLOT0_ALT: case BFD_RELOC_XTENSA_SLOT1_ALT: case BFD_RELOC_XTENSA_SLOT2_ALT: @@ -6663,7 +6758,11 @@ emit_single_op (TInsn *orig_insn) || orig_insn->opcode == xtensa_movi_n_opcode) && !cur_vinsn.inside_bundle && (orig_insn->tok[1].X_op == O_symbol - || orig_insn->tok[1].X_op == O_pltrel) + || orig_insn->tok[1].X_op == O_pltrel + || orig_insn->tok[1].X_op == O_tlsfunc + || orig_insn->tok[1].X_op == O_tlsarg + || orig_insn->tok[1].X_op == O_tpoff + || orig_insn->tok[1].X_op == O_dtpoff) && !orig_insn->is_specific_opcode && use_transform ()) xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0); else @@ -9527,7 +9626,7 @@ convert_frag_immed (segT segP, /* Add a fixup. */ target_seg = S_GET_SEGMENT (lit_sym); assert (target_seg); - reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op); + reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op, TRUE); fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4, &tinsn->tok[0], FALSE, reloc_type); break; @@ -11527,12 +11626,29 @@ vinsn_to_insnbuf (vliw_insn *vinsn, for (slot = 0; slot < vinsn->num_slots; slot++) { TInsn *tinsn = &vinsn->slots[slot]; + expressionS *tls_reloc = &tinsn->tls_reloc; bfd_boolean tinsn_has_fixup = tinsn_to_slotbuf (vinsn->format, slot, tinsn, vinsn->slotbuf[slot]); xtensa_format_set_slot (isa, fmt, slot, insnbuf, vinsn->slotbuf[slot]); + if (tls_reloc->X_op != O_illegal) + { + if (vinsn->num_slots != 1) + as_bad (_("TLS relocation not allowed in FLIX bundle")); + else if (record_fixup) + /* Instructions that generate TLS relocations should always be + relaxed in the front-end. If "record_fixup" is set, then this + function is being called during back-end relaxation, so flag + the unexpected behavior as an error. */ + as_bad (_("unexpected TLS relocation")); + else + fix_new (fragP, frag_offset - fragP->fr_literal, + xtensa_format_length (isa, fmt), + tls_reloc->X_add_symbol, tls_reloc->X_add_number, + FALSE, map_operator_to_reloc (tls_reloc->X_op, FALSE)); + } if (tinsn_has_fixup) { int i; diff --git a/gas/config/xtensa-istack.h b/gas/config/xtensa-istack.h index 0bd0974e5ea..ebbb4f0e915 100644 --- a/gas/config/xtensa-istack.h +++ b/gas/config/xtensa-istack.h @@ -1,5 +1,5 @@ /* Declarations for stacks of tokenized Xtensa instructions. - Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -49,6 +49,8 @@ typedef struct tinsn_struct bfd_boolean loc_directive_seen; struct dwarf2_line_info debug_line; + expressionS tls_reloc; + /* Filled out by relaxation_requirements: */ enum xtensa_relax_statesE subtype; int literal_space; diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c index 89a53d3d13f..8f49afab51a 100644 --- a/gas/config/xtensa-relax.c +++ b/gas/config/xtensa-relax.c @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -645,13 +645,13 @@ append_op (BuildInstr *bi, BuildOp *b_op) static void -append_literal_op (BuildInstr *bi, unsigned op1) +append_literal_op (BuildInstr *bi, unsigned op1, unsigned src_op) { BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp)); b_op->op_num = op1; b_op->typ = OP_LITERAL; - b_op->op_data = 0; + b_op->op_data = src_op; b_op->next = NULL; append_op (bi, b_op); } @@ -1594,6 +1594,7 @@ build_transition (insn_pattern *initial_insn, TransitionRule *tr = NULL; xtensa_opcode opcode; xtensa_isa isa = xtensa_default_isa; + BuildInstr *literal_bi; opname_map_e *op1; opname_map_e *op2; @@ -1706,6 +1707,7 @@ build_transition (insn_pattern *initial_insn, can be used before they are defined. Also there are a number of special operands (e.g., HI24S). */ + literal_bi = NULL; for (r = replace_insns->head; r != NULL; r = r->next) { BuildInstr *bi; @@ -1730,6 +1732,7 @@ build_transition (insn_pattern *initial_insn, bi->typ = INSTR_LITERAL_DEF; if (operand_count != 1) as_fatal (_("expected one operand for generated literal")); + literal_bi = bi; } else if (strcmp (opcode_name, "LABEL") == 0) { @@ -1768,7 +1771,13 @@ build_transition (insn_pattern *initial_insn, if (op_is_constant (op)) append_constant_op (bi, op->operand_num, op_get_constant (op)); else if (strcmp (op->operand_name, "%LITERAL") == 0) - append_literal_op (bi, op->operand_num); + { + if (! literal_bi || ! literal_bi->ops || literal_bi->ops->next) + as_fatal (_("opcode '%s': cannot find literal definition"), + opcode_name); + append_literal_op (bi, op->operand_num, + literal_bi->ops->op_data); + } else if (strcmp (op->operand_name, "%LABEL") == 0) append_label_op (bi, op->operand_num); else if (op->operand_name[0] == 'a' diff --git a/gas/config/xtensa-relax.h b/gas/config/xtensa-relax.h index 74b4ae8f311..14898c91346 100644 --- a/gas/config/xtensa-relax.h +++ b/gas/config/xtensa-relax.h @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003, 2004, 2007 Free Software Foundation, Inc. + Copyright 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -135,7 +135,9 @@ struct build_op OPERAND: op_data is the field in the source instruction to take the value from and encode in the op_num field here. - LITERAL or LABEL: unused. */ + LITERAL: op_data is field in the source + instruction that is stored in the literal. + LABEL: unused. */ BuildOp *next; }; diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index 407c5ec6715..ae259dcbc3c 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,9 @@ +2008-08-20 Bob Wilson + + * xtensa.h (R_XTENSA_TLSDESC_FN, R_XTENSA_TLSDESC_ARG) + (R_XTENSA_TLS_DTPOFF, R_XTENSA_TLS_TPOFF, R_XTENSA_TLS_FUNC) + (R_XTENSA_TLS_ARG, R_XTENSA_TLS_CALL): New. + 2008-08-08 Richard Sandiford Daniel Jacobowitz Catherine Moore diff --git a/include/elf/xtensa.h b/include/elf/xtensa.h index 7e70cb58821..400bc1778ef 100644 --- a/include/elf/xtensa.h +++ b/include/elf/xtensa.h @@ -1,5 +1,5 @@ /* Xtensa ELF support for BFD. - Copyright 2003, 2004, 2007 Free Software Foundation, Inc. + Copyright 2003, 2004, 2007, 2008 Free Software Foundation, Inc. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. This file is part of BFD, the Binary File Descriptor library. @@ -76,6 +76,13 @@ START_RELOC_NUMBERS (elf_xtensa_reloc_type) RELOC_NUMBER (R_XTENSA_SLOT12_ALT, 47) RELOC_NUMBER (R_XTENSA_SLOT13_ALT, 48) RELOC_NUMBER (R_XTENSA_SLOT14_ALT, 49) + RELOC_NUMBER (R_XTENSA_TLSDESC_FN, 50) + RELOC_NUMBER (R_XTENSA_TLSDESC_ARG, 51) + RELOC_NUMBER (R_XTENSA_TLS_DTPOFF, 52) + RELOC_NUMBER (R_XTENSA_TLS_TPOFF, 53) + RELOC_NUMBER (R_XTENSA_TLS_FUNC, 54) + RELOC_NUMBER (R_XTENSA_TLS_ARG, 55) + RELOC_NUMBER (R_XTENSA_TLS_CALL, 56) END_RELOC_NUMBERS (R_XTENSA_max) /* Processor-specific flags for the ELF header e_flags field. */ diff --git a/ld/testsuite/ld-xtensa/tlsbin.dd b/ld/testsuite/ld-xtensa/tlsbin.dd new file mode 100644 index 00000000000..c3fad8bb31b --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlsbin.dd @@ -0,0 +1,65 @@ +#source: tlsbin.s +#as: +#ld: -melf32xtensa +#objdump: -drj.text --start-address=0x400238 +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Disassembly of section \.text: + +0+400238 <_start>: + [0-9a-f]+: [0-9a-f]+[ ]+entry a1, 32 +# GD -> IE because variable is not defined in executable + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 4001ec <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD -> IE because variable is not defined in executable where +# the variable is referenced through IE too + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 4001f4 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD -> LE with global variable defined in executable + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 4001fc <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD -> LE with local variable defined in executable + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 400204 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD -> LE with hidden variable defined in executable + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 40020c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# LD -> LE + [0-9a-f]+: [0-9a-f]+[ ]+nop.* + [0-9a-f]+: [0-9a-f]+[ ]+nop.* + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a12, 400218 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a12, a12, a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a13, 40021c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a13, a13, a10 +# LD -> LE against hidden variables + [0-9a-f]+: [0-9a-f]+[ ]+l32r a12, 400220 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a12, a12, a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a13, 400224 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a13, a13, a10 +# +# IE against global var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a2 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a3, 400228 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a3, a3, a2 +# IE -> LE against global var defined in exec + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a4 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a5, 40022c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a5, a5, a4 +# IE -> LE against local var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a6 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a7, 400230 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a7, a7, a6 +# IE -> LE against hidden var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a9, 400234 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a9, a9, a8 +# + [0-9a-f]+: [0-9a-f]+[ ]+retw.* diff --git a/ld/testsuite/ld-xtensa/tlsbin.rd b/ld/testsuite/ld-xtensa/tlsbin.rd new file mode 100644 index 00000000000..b2e87261b5a --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlsbin.rd @@ -0,0 +1,118 @@ +#source: tlsbin.s +#as: +#ld: -melf32xtensa +#readelf: -WSsrl +#target: xtensa*-*-linux* + +There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+: + +Section Headers: + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al + +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 00 +0 +0 +0 + +\[[ 0-9]+\] .interp +.* + +\[[ 0-9]+\] .hash +.* + +\[[ 0-9]+\] .dynsym +.* + +\[[ 0-9]+\] .dynstr +.* + +\[[ 0-9]+\] .rela.dyn +.* + +\[[ 0-9]+\] .text +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +AX +0 +0 +4 + +\[[ 0-9]+\] .got.loc +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +A +0 +0 +4 + +\[[ 0-9]+\] .tdata +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +WAT +0 +0 +4 + +\[[ 0-9]+\] .dynamic +DYNAMIC +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 08 +WA +4 +0 +4 + +\[[ 0-9]+\] .got +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +WA +0 +0 +4 + +\[[ 0-9]+\] .xt.lit +PROGBITS +0+ .* + +\[[ 0-9]+\] .xt.prop +PROGBITS +0+ .* + +\[[ 0-9]+\] .xtensa.info +NOTE +0+ .* + +\[[ 0-9]+\] .shstrtab +.* + +\[[ 0-9]+\] .symtab +.* + +\[[ 0-9]+\] .strtab +.* +Key to Flags: +.* +.* +.* + +Elf file type is EXEC \(Executable file\) +Entry point 0x[0-9a-f]+ +There are [0-9]+ program headers, starting at offset [0-9]+ + +Program Headers: + Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align + PHDR.* + INTERP.* +.*Requesting program interpreter.* + LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000 + LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW 0x1000 + DYNAMIC +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW +0x4 + TLS +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R +0x4 + + Section to Segment mapping: + Segment Sections... + 00 * + 01 +.interp * + 02 +.interp .hash .dynsym .dynstr .rela.dyn .text .got.loc * + 03 +.tdata .dynamic .got * + 04 +.dynamic * + 05 +.tdata * + +Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 3 entries: + +Offset +Info +Type +Sym\. Value Symbol's Name \+ Addend +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+ +sG1 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+ +sG2 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+ +sG2 \+ 0 + +Symbol table '\.dynsym' contains [0-9]+ entries: + +Num: +Value +Size Type +Bind +Vis +Ndx Name + +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND * + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2 + +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1 + +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata + +[0-9]+: 0+[0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end + +Symbol table '\.symtab' contains [0-9]+ entries: + +Num: +Value +Size Type +Bind +Vis +Ndx Name + +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 * + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl1 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl2 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl3 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl4 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl5 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl6 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl7 + +[0-9]+: [0-9a-f]+ +0 TLS +LOCAL DEFAULT +8 sl8 + +[0-9]+: 0+ +0 TLS +LOCAL HIDDEN +8 _TLS_MODULE_BASE_ + +[0-9]+: [0-9a-f]+ +0 OBJECT +LOCAL +HIDDEN +9 _DYNAMIC + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg8 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg3 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh3 + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG2 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg4 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg5 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh7 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh8 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg1 + +[0-9]+: [0-9a-f]+ +0 FUNC +GLOBAL DEFAULT +6 _start + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh4 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh5 + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg2 + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT UND sG1 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh1 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg6 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL DEFAULT +8 sg7 + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh2 + +[0-9]+: [0-9a-f]+ +0 TLS +GLOBAL HIDDEN +8 sh6 diff --git a/ld/testsuite/ld-xtensa/tlsbin.s b/ld/testsuite/ld-xtensa/tlsbin.s new file mode 100644 index 00000000000..2220cfc34fc --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlsbin.s @@ -0,0 +1,98 @@ + .section ".tdata", "awT", @progbits + .global sg1, sg2, sg3, sg4, sg5, sg6, sg7, sg8 + .global sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8 + .hidden sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8 + .align 4 +sg1: .long 17 +sg2: .long 18 +sg3: .long 19 +sg4: .long 20 +sg5: .long 21 +sg6: .long 22 +sg7: .long 23 +sg8: .long 24 +sl1: .long 65 +sl2: .long 66 +sl3: .long 67 +sl4: .long 68 +sl5: .long 69 +sl6: .long 70 +sl7: .long 71 +sl8: .long 72 +sh1: .long 157 +sh2: .long 158 +sh3: .long 159 +sh4: .long 160 +sh5: .long 161 +sh6: .long 162 +sh7: .long 163 +sh8: .long 164 + + .text + .global _start + .type _start, @function +_start: + entry sp, 32 + + /* GD -> IE because variable is not defined in executable */ + movi a8, sG1@tlsfunc + movi a10, sG1@tlsarg + callx8.tls a8, sG1@tlscall + + /* GD -> IE because variable is not defined in executable where + the variable is referenced through IE too */ + movi a8, sG2@tlsfunc + movi a10, sG2@tlsarg + callx8.tls a8, sG2@tlscall + + /* GD -> LE with global variable defined in executable */ + movi a8, sg1@tlsfunc + movi a10, sg1@tlsarg + callx8.tls a8, sg1@tlscall + + /* GD -> LE with local variable defined in executable */ + movi a8, sl1@tlsfunc + movi a10, sl1@tlsarg + callx8.tls a8, sl1@tlscall + + /* GD -> LE with hidden variable defined in executable */ + movi a8, sh1@tlsfunc + movi a10, sh1@tlsarg + callx8.tls a8, sh1@tlscall + + /* LD -> LE */ + movi a8, _TLS_MODULE_BASE_@tlsfunc + movi a10, _TLS_MODULE_BASE_@tlsarg + callx8.tls a8, _TLS_MODULE_BASE_@tlscall + movi a12, 1+sl1@dtpoff + add a12, a12, a10 + movi a13, sl2@dtpoff+2 + add a13, a13, a10 + + /* LD -> LE against hidden variables */ + movi a12, sh1@dtpoff + add a12, a12, a10 + movi a13, 3+sh2@dtpoff + add a13, a13, a10 + + /* IE against global var */ + rur a2, THREADPTR + movi a3, sG2@tpoff + add a3, a3, a2 + + /* IE -> LE against global var defined in exec */ + rur a4, THREADPTR + movi a5, sg1@tpoff + add a5, a5, a4 + + /* IE -> LE against local var */ + rur a6, THREADPTR + movi a7, sl1@tpoff + add a7, a7, a6 + + /* IE -> LE against hidden var */ + rur a8, THREADPTR + movi a9, sh1@tpoff + add a9, a9, a8 + + retw diff --git a/ld/testsuite/ld-xtensa/tlsbin.sd b/ld/testsuite/ld-xtensa/tlsbin.sd new file mode 100644 index 00000000000..484db07e2a0 --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlsbin.sd @@ -0,0 +1,14 @@ +#source: tlsbin.s +#as: +#ld: -melf32xtensa +#objdump: -sj.text --stop-address=0x400238 +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Contents of section .text: + *[0-9a-f]+ 0+ 0+ 0+ 0+ .* + *[0-9a-f]+ 0+ 0*080* 0+ 0*280* .* + *[0-9a-f]+ 0+ 0*480* 0+ 0*080* .* + *[0-9a-f]+ 0*290* 0*2e0* 0*480* 0*4f0* .* + *[0-9a-f]+ 0+ 0*080* 0*280* 0*480* .* diff --git a/ld/testsuite/ld-xtensa/tlsbin.td b/ld/testsuite/ld-xtensa/tlsbin.td new file mode 100644 index 00000000000..efef45c9410 --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlsbin.td @@ -0,0 +1,14 @@ +#source: tlsbin.s +#ld: -melf32xtensa +#objdump: -sj.tdata +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Contents of section .tdata: + *[0-9a-f]+ 0*110* 0*120* 0*130* 0*140* .* + *[0-9a-f]+ 0*150* 0*160* 0*170* 0*180* .* + *[0-9a-f]+ 0*410* 0*420* 0*430* 0*440* .* + *[0-9a-f]+ 0*450* 0*460* 0*470* 0*480* .* + *[0-9a-f]+ 0*9d0* 0*9e0* 0*9f0* 0*a00* .* + *[0-9a-f]+ 0*a10* 0*a20* 0*a30* 0*a40* .* diff --git a/ld/testsuite/ld-xtensa/tlslib.s b/ld/testsuite/ld-xtensa/tlslib.s new file mode 100644 index 00000000000..a2c430b733f --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlslib.s @@ -0,0 +1,18 @@ + .section ".tdata", "awT", @progbits + .global sG1, sG2, sG3, sG4, sG5, sG6, sG7, sG8 +sG1: .long 513 +sG2: .long 514 +sG3: .long 515 +sG4: .long 516 +sG5: .long 517 +sG6: .long 518 +sG7: .long 519 +sG8: .long 520 + + .text + /* Dummy. */ + .global __tls_get_addr + .type __tls_get_addr, @function +__tls_get_addr: + entry sp, 16 + retw diff --git a/ld/testsuite/ld-xtensa/tlspic.dd b/ld/testsuite/ld-xtensa/tlspic.dd new file mode 100644 index 00000000000..9f6e20ab81c --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic.dd @@ -0,0 +1,81 @@ +#source: tlspic1.s +#source: tlspic2.s +#as: +#ld: -shared -melf32xtensa +#objdump: -drj.text --start-address=0x350 +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Disassembly of section \.text: + +0+350 <_start>: + [0-9a-f]+: [0-9a-f]+[ ]+entry a1, 32 +# GD + [0-9a-f]+: [0-9a-f]+[ ]+l32r a8, 2e0 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 2e4 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+callx8 a8 +# GD -> IE because variable is referenced through IE too + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 2ec <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD against local variable + [0-9a-f]+: [0-9a-f]+[ ]+l32r a8, 2f0 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 2f4 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+callx8 a8 +# GD -> IE against local variable referenced through IE too + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 2fc <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD against hidden and local variable + [0-9a-f]+: [0-9a-f]+[ ]+l32r a8, 300 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 304 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+callx8 a8 +# GD -> IE against hidden and local variable referenced through IE too + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 30c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# GD against hidden but not local variable + [0-9a-f]+: [0-9a-f]+[ ]+l32r a8, 310 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 314 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+callx8 a8 +# GD -> IE against hidden but not local variable referenced through IE too + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 31c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a10, a10, a8 +# LD + [0-9a-f]+: [0-9a-f]+[ ]+l32r a8, 320 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+l32r a10, 324 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+callx8 a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a12, 328 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a12, a12, a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a13, 32c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a13, a13, a10 +# LD against hidden and local variables + [0-9a-f]+: [0-9a-f]+[ ]+l32r a12, 330 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a12, a12, a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a13, 334 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a13, a13, a10 +# LD against hidden but not local variables + [0-9a-f]+: [0-9a-f]+[ ]+l32r a12, 338 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a12, a12, a10 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a13, 33c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a13, a13, a10 +# IE against global var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a2 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a3, 340 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a3, a3, a2 +# IE against local var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a4 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a5, 344 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a5, a5, a4 +# IE against hidden and local var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a6 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a7, 348 <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a7, a7, a6 +# IE against hidden but not local var + [0-9a-f]+: [0-9a-f]+[ ]+rur.threadptr a8 + [0-9a-f]+: [0-9a-f]+[ ]+l32r a9, 34c <.*> + [0-9a-f]+: [0-9a-f]+[ ]+add.* a9, a9, a8 +# + [0-9a-f]+: [0-9a-f]+[ ]+retw.* diff --git a/ld/testsuite/ld-xtensa/tlspic.rd b/ld/testsuite/ld-xtensa/tlspic.rd new file mode 100644 index 00000000000..54dd71a15c6 --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic.rd @@ -0,0 +1,142 @@ +#source: tlspic1.s +#source: tlspic2.s +#as: +#ld: -shared -melf32xtensa +#readelf: -WSsrl +#target: xtensa*-*-linux* + +There are [0-9]+ section headers, starting at offset 0x[0-9a-f]+: + +Section Headers: + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al + +\[[ 0-9]+\] +NULL +0+ 0+ 0+ 00 +0 +0 +0 + +\[[ 0-9]+\] .hash +.* + +\[[ 0-9]+\] .dynsym +.* + +\[[ 0-9]+\] .dynstr +.* + +\[[ 0-9]+\] .rela.dyn +.* + +\[[ 0-9]+\] .text +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +AX +0 +0 +4 + +\[[ 0-9]+\] .got.loc +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +A +0 +0 +4 + +\[[ 0-9]+\] .tdata +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +WAT +0 +0 +4 + +\[[ 0-9]+\] .tbss +NOBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +WAT +0 +0 +4 + +\[[ 0-9]+\] .dynamic +DYNAMIC +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 08 +WA +3 +0 +4 + +\[[ 0-9]+\] .got +PROGBITS +[0-9a-f]+ [0-9a-f]+ [0-9a-f]+ 00 +WA +0 +0 +4 + +\[[ 0-9]+\] .xt.lit +PROGBITS +0+ .* + +\[[ 0-9]+\] .xt.prop +PROGBITS +0+ .* + +\[[ 0-9]+\] .xtensa.info +NOTE +0+ .* + +\[[ 0-9]+\] .shstrtab +.* + +\[[ 0-9]+\] .symtab +.* + +\[[ 0-9]+\] .strtab +.* +Key to Flags: +.* +.* +.* + +Elf file type is DYN \(Shared object file\) +Entry point 0x[0-9a-f]+ +There are [0-9]+ program headers, starting at offset [0-9]+ + +Program Headers: + Type +Offset +VirtAddr +PhysAddr +FileSiz +MemSiz +Flg Align + LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R E 0x1000 + LOAD +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW 0x1000 + DYNAMIC +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ RW +0x4 + TLS +0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ 0x[0-9a-f]+ R +0x4 + + Section to Segment mapping: + Segment Sections... + 00 +.hash .dynsym .dynstr .rela.dyn .text .got.loc * + 01 +.tdata .dynamic .got * + 02 +.dynamic * + 03 +.tdata .tbss * + +Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 18 entries: + +Offset +Info +Type +Sym\. Value Symbol's Name \+ Addend +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_FN +0+ +sg1 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_ARG +0+ +sg1 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+4 +sg2 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+4 +sg2 \+ 0 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_FN +0+20 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_ARG +0+20 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+24 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_FN +0+40 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_ARG +0+40 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+44 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_FN +0+60 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_ARG +0+60 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+64 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_FN +0+ +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLSDESC_ARG +0+ +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+24 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+44 +[0-9a-f]+ [0-9a-f]+ R_XTENSA_TLS_TPOFF +0+64 + +Symbol table '\.dynsym' contains [0-9]+ entries: + +Num: +Value +Size Type +Bind +Vis +Ndx Name + +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND * + +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +7 sg8 + +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +7 sg3 + +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +7 sg4 + +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +7 sg5 + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1 + +[0-9]+: 0+350 +0 FUNC +GLOBAL DEFAULT +5 _start + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start + +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +7 sg2 + +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +7 sg6 + +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +7 sg7 + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end + +Symbol table '\.symtab' contains [0-9]+ entries: + +Num: +Value +Size Type +Bind +Vis +Ndx Name + +[0-9]+: 0+ +0 NOTYPE LOCAL DEFAULT UND * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +1 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +2 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +3 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +4 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +5 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +6 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +7 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +8 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +9 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +10 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +11 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +12 * + +[0-9]+: [0-9a-f]+ +0 SECTION LOCAL DEFAULT +13 * + +[0-9]+: 0+20 +0 TLS +LOCAL DEFAULT +7 sl1 + +[0-9]+: 0+24 +0 TLS +LOCAL DEFAULT +7 sl2 + +[0-9]+: 0+28 +0 TLS +LOCAL DEFAULT +7 sl3 + +[0-9]+: 0+2c +0 TLS +LOCAL DEFAULT +7 sl4 + +[0-9]+: 0+30 +0 TLS +LOCAL DEFAULT +7 sl5 + +[0-9]+: 0+34 +0 TLS +LOCAL DEFAULT +7 sl6 + +[0-9]+: 0+38 +0 TLS +LOCAL DEFAULT +7 sl7 + +[0-9]+: 0+3c +0 TLS +LOCAL DEFAULT +7 sl8 + +[0-9]+: 0+60 +0 TLS +LOCAL HIDDEN +8 sH1 + +[0-9]+: 0+ +0 TLS +LOCAL HIDDEN +7 _TLS_MODULE_BASE_ + +[0-9]+: 0+144c +0 OBJECT LOCAL HIDDEN ABS _DYNAMIC + +[0-9]+: 0+48 +0 TLS +LOCAL HIDDEN +7 sh3 + +[0-9]+: 0+64 +0 TLS +LOCAL HIDDEN +8 sH2 + +[0-9]+: 0+78 +0 TLS +LOCAL HIDDEN +8 sH7 + +[0-9]+: 0+58 +0 TLS +LOCAL HIDDEN +7 sh7 + +[0-9]+: 0+5c +0 TLS +LOCAL HIDDEN +7 sh8 + +[0-9]+: 0+6c +0 TLS +LOCAL HIDDEN +8 sH4 + +[0-9]+: 0+4c +0 TLS +LOCAL HIDDEN +7 sh4 + +[0-9]+: 0+68 +0 TLS +LOCAL HIDDEN +8 sH3 + +[0-9]+: 0+50 +0 TLS +LOCAL HIDDEN +7 sh5 + +[0-9]+: 0+70 +0 TLS +LOCAL HIDDEN +8 sH5 + +[0-9]+: 0+74 +0 TLS +LOCAL HIDDEN +8 sH6 + +[0-9]+: 0+7c +0 TLS +LOCAL HIDDEN +8 sH8 + +[0-9]+: 0+40 +0 TLS +LOCAL HIDDEN +7 sh1 + +[0-9]+: 0+44 +0 TLS +LOCAL HIDDEN +7 sh2 + +[0-9]+: 0+54 +0 TLS +LOCAL HIDDEN +7 sh6 + +[0-9]+: 0+1c +0 TLS +GLOBAL DEFAULT +7 sg8 + +[0-9]+: 0+8 +0 TLS +GLOBAL DEFAULT +7 sg3 + +[0-9]+: 0+c +0 TLS +GLOBAL DEFAULT +7 sg4 + +[0-9]+: 0+10 +0 TLS +GLOBAL DEFAULT +7 sg5 + +[0-9]+: 0+ +0 TLS +GLOBAL DEFAULT +7 sg1 + +[0-9]+: 0+350 +0 FUNC +GLOBAL DEFAULT +5 _start + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS __bss_start + +[0-9]+: 0+4 +0 TLS +GLOBAL DEFAULT +7 sg2 + +[0-9]+: 0+14 +0 TLS +GLOBAL DEFAULT +7 sg6 + +[0-9]+: 0+18 +0 TLS +GLOBAL DEFAULT +7 sg7 + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _edata + +[0-9]+: [0-9a-f]+ +0 NOTYPE GLOBAL DEFAULT ABS _end diff --git a/ld/testsuite/ld-xtensa/tlspic.sd b/ld/testsuite/ld-xtensa/tlspic.sd new file mode 100644 index 00000000000..57dafc0c23e --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic.sd @@ -0,0 +1,17 @@ +#source: tlspic1.s +#source: tlspic2.s +#as: +#ld: -shared -melf32xtensa +#objdump: -sj.text --stop-address=0x350 +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Contents of section .text: + 0+2e0 0+ 0+ 0+ 0+ .* + 0+2f0 0+ 0+ 0+ 0+ .* + 0+300 0+ 0+ 0+ 0+ .* + 0+310 0+ 0+ 0+ 0+ .* + 0+320 0+ 0+ 0*200* 0*260* .* + 0+330 0*400* 0*470* 0*600* 0*650* .* + 0+340 0+ 0+ 0+ 0+ .* diff --git a/ld/testsuite/ld-xtensa/tlspic.td b/ld/testsuite/ld-xtensa/tlspic.td new file mode 100644 index 00000000000..d3e11d3f448 --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic.td @@ -0,0 +1,16 @@ +#source: tlspic1.s +#source: tlspic2.s +#as: +#ld: -shared -melf32xtensa +#objdump: -sj.tdata +#target: xtensa*-*-linux* + +.*: +file format elf32-xtensa-.e + +Contents of section .tdata: + *[0-9a-f]+ 0*110* 0*120* 0*130* 0*140* .* + *[0-9a-f]+ 0*150* 0*160* 0*170* 0*180* .* + *[0-9a-f]+ 0*410* 0*420* 0*430* 0*440* .* + *[0-9a-f]+ 0*450* 0*460* 0*470* 0*480* .* + *[0-9a-f]+ 0*9d0* 0*9e0* 0*9f0* 0*a00* .* + *[0-9a-f]+ 0*a10* 0*a20* 0*a30* 0*a40* .* diff --git a/ld/testsuite/ld-xtensa/tlspic1.s b/ld/testsuite/ld-xtensa/tlspic1.s new file mode 100644 index 00000000000..9ecde66a2de --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic1.s @@ -0,0 +1,120 @@ + .section ".tdata", "awT", @progbits + .global sg1, sg2, sg3, sg4, sg5, sg6, sg7, sg8 + .global sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8 + .hidden sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8 + .align 4 +sg1: .long 17 +sg2: .long 18 +sg3: .long 19 +sg4: .long 20 +sg5: .long 21 +sg6: .long 22 +sg7: .long 23 +sg8: .long 24 +sl1: .long 65 +sl2: .long 66 +sl3: .long 67 +sl4: .long 68 +sl5: .long 69 +sl6: .long 70 +sl7: .long 71 +sl8: .long 72 +sh1: .long 157 +sh2: .long 158 +sh3: .long 159 +sh4: .long 160 +sh5: .long 161 +sh6: .long 162 +sh7: .long 163 +sh8: .long 164 + + .text + .global _start + .type _start, @function +_start: + entry sp, 32 + + /* GD */ + movi a8, sg1@tlsfunc + movi a10, sg1@tlsarg + callx8.tls a8, sg1@tlscall + + /* GD -> IE because variable is referenced through IE too */ + movi a8, sg2@tlsfunc + movi a10, sg2@tlsarg + callx8.tls a8, sg2@tlscall + + /* GD against local variable */ + movi a8, sl1@tlsfunc + movi a10, sl1@tlsarg + callx8.tls a8, sl1@tlscall + + /* GD -> IE against local variable referenced through IE too */ + movi a8, sl2@tlsfunc + movi a10, sl2@tlsarg + callx8.tls a8, sl2@tlscall + + /* GD against hidden and local variable */ + movi a8, sh1@tlsfunc + movi a10, sh1@tlsarg + callx8.tls a8, sh1@tlscall + + /* GD -> IE against hidden and local variable referenced through + IE too */ + movi a8, sh2@tlsfunc + movi a10, sh2@tlsarg + callx8.tls a8, sh2@tlscall + + /* GD against hidden but not local variable */ + movi a8, sH1@tlsfunc + movi a10, sH1@tlsarg + callx8.tls a8, sH1@tlscall + + /* GD -> IE against hidden but not local variable referenced through + IE too */ + movi a8, sH2@tlsfunc + movi a10, sH2@tlsarg + callx8.tls a8, sH2@tlscall + + /* LD */ + movi a8, _TLS_MODULE_BASE_@tlsfunc + movi a10, _TLS_MODULE_BASE_@tlsarg + callx8.tls a8, _TLS_MODULE_BASE_@tlscall + movi a12, sl1@dtpoff + add a12, a12, a10 + movi a13, 2+sl2@dtpoff + add a13, a13, a10 + + /* LD against hidden and local variables */ + movi a12, sh1@dtpoff + add a12, a12, a10 + movi a13, sh2@dtpoff+3 + add a13, a13, a10 + + /* LD against hidden but not local variables */ + movi a12, sH1@dtpoff + add a12, a12, a10 + movi a13, sH2@dtpoff+1 + add a13, a13, a10 + + /* IE against global var */ + rur a2, THREADPTR + movi a3, sg2@tpoff + add a3, a3, a2 + + /* IE against local var */ + rur a4, THREADPTR + movi a5, sl2@tpoff + add a5, a5, a4 + + /* IE against hidden and local var */ + rur a6, THREADPTR + movi a7, sh2@tpoff + add a7, a7, a6 + + /* IE against hidden but not local var */ + rur a8, THREADPTR + movi a9, sH2@tpoff + add a9, a9, a8 + + retw diff --git a/ld/testsuite/ld-xtensa/tlspic2.s b/ld/testsuite/ld-xtensa/tlspic2.s new file mode 100644 index 00000000000..9f337e78b99 --- /dev/null +++ b/ld/testsuite/ld-xtensa/tlspic2.s @@ -0,0 +1,12 @@ + .section ".tbss", "awT", @nobits + .global sH1, sH2, sH3, sH4, sH5, sH6, sH7, sH8 + .hidden sH1, sH2, sH3, sH4, sH5, sH6, sH7, sH8 + .align 4 +sH1: .space 4 +sH2: .space 4 +sH3: .space 4 +sH4: .space 4 +sH5: .space 4 +sH6: .space 4 +sH7: .space 4 +sH8: .space 4 diff --git a/ld/testsuite/ld-xtensa/xtensa.exp b/ld/testsuite/ld-xtensa/xtensa.exp new file mode 100644 index 00000000000..e6dc827ee49 --- /dev/null +++ b/ld/testsuite/ld-xtensa/xtensa.exp @@ -0,0 +1,54 @@ +# Expect script for ld-xtensa tests +# Copyright (C) 2008 Free Software Foundation +# +# This file is part of the GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +if { !([istarget "xtensa*-*-linux*"]) } { + return +} + +# List contains test-items with 3 items followed by 2 lists: +# 0:name 1:ld options 2:assembler options +# 3:filenames of assembler files 4: action and options. 5: name of output file + +# Actions: +# objdump: Apply objdump options on result. Compare with regex (last arg). +# nm: Apply nm options on result. Compare with regex (last arg). +# readelf: Apply readelf options on result. Compare with regex (last arg). + +set xtensatests { + {"TLS -shared transitions" + "-shared -melf32xtensa" "" {tlspic1.s tlspic2.s} + {{readelf -WSsrl tlspic.rd} + {objdump "-drj.text --start-address=0x350" tlspic.dd} + {objdump "-sj.text --stop-address=0x350" tlspic.sd} + {objdump -sj.tdata tlspic.td}} + "libtlspic.so"} + {"Helper shared library" "-shared -melf32xtensa" + "" {tlslib.s} {} "libtlslib.so"} + {"TLS exec transitions" + "-melf32xtensa tmpdir/libtlslib.so" "" {tlsbin.s} + {{readelf -WSsrl tlsbin.rd} + {objdump "-drj.text --start-address=0x400238" tlsbin.dd} + {objdump "-sj.text --stop-address=0x400238" tlsbin.sd} + {objdump -sj.tdata tlsbin.td}} + "tlsbin"} +} + +run_ld_link_tests $xtensatests