From e1918d23874ba95c5fcdab4902a6d5e24c504f87 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Tue, 4 Nov 2003 06:16:39 +0000 Subject: [PATCH] * bfd-in.h (_bfd_elf_tls_setup): Declare. * bfd-in2.h: Regenerate. * elf-bfd.h (struct elf_link_tls_segment): Delete. (struct elf_link_hash_table): Add tls_sec and tls_size. * elf.c (_bfd_elf_link_hash_table_init): Init tls_sec and tls_size. * elflink.c (_bfd_elf_tls_setup): New function. * elflink.h (struct elf_final_link_info): Remove first_tls_sec. (elf_bfd_final_link): Don't set first_tls_sec here. Update code saving tls segment info, round segment size up. (elf_link_output_extsym): Adjust code using tls segment info. (elf_link_input_bfd): Likewise. * elf32-i386.c (dtpoff_base, tpoff): Likewise. * elf32-s390.c (dtpoff_base, tpoff): Likewise. * elf32-sh.c (dtpoff_base, tpoff): Likewise. * elf32-sparc.c (dtpoff_base, tpoff): Likewise. * elf64-s390.c (dtpoff_base, tpoff): Likewise. * elf64-x86-64.c (dtpoff_base, tpoff): Likewise. * elfxx-ia64.c (elfNN_ia64_tprel_base): Likewise. (elfNN_ia64_dtprel_base): Likewise. * elf64-alpha.c (alpha_get_dtprel_base): Likewise. (alpha_get_tprel_base): Likewise. (struct alpha_relax_info): Remove tls_segment. (elf64_alpha_relax_got_load): Adjust invocation of alpha_get_dtprel_base and alpha_get_tprel_base. (elf64_alpha_relax_tls_get_addr): Likewise. (elf64_alpha_relax_section): Likewise. (elf64_alpha_relocate_section): Likewise. (elf64_alpha_relax_find_tls_segment): Delete. * elf32-ppc.c (struct ppc_elf_link_hash_table): Remove tls_sec. (ppc_elf_tls_setup): Call _bfd_elf_tls_setup. Return section. (ppc_elf_relocate_section): Adjust to use elf.tls_sec. * elf32-ppc.h (ppc_elf_tls_setup): Update. * elf64-ppc.c (struct ppc_link_hash_table): Remove tls_sec. (ppc64_elf_tls_setup): Call _bfd_elf_tls_setup. Return section. (ppc64_elf_tls_optimize): Adjust to use elf.tls_sec. (ppc64_elf_relocate_section): Likewise. * elf64-ppc.h (ppc64_elf_tls_setup): Update. * emultempl/elf32.em (gld${EMULATION_NAME}_before_allocation): Call _bfd_elf_tls_setup. --- bfd/ChangeLog | 40 ++++++++++++++++++ bfd/bfd-in.h | 3 ++ bfd/bfd-in2.h | 3 ++ bfd/elf-bfd.h | 13 ++---- bfd/elf.c | 3 +- bfd/elf32-i386.c | 16 ++++--- bfd/elf32-ppc.c | 32 +++++--------- bfd/elf32-ppc.h | 2 +- bfd/elf32-s390.c | 16 ++++--- bfd/elf32-sh.c | 12 +++--- bfd/elf32-sparc.c | 16 ++++--- bfd/elf64-alpha.c | 98 ++++++++++--------------------------------- bfd/elf64-ppc.c | 35 ++++++---------- bfd/elf64-ppc.h | 2 +- bfd/elf64-s390.c | 16 ++++--- bfd/elf64-x86-64.c | 14 +++---- bfd/elflink.c | 28 +++++++++++++ bfd/elflink.h | 46 +++++++------------- bfd/elfxx-ia64.c | 12 +++--- ld/ChangeLog | 5 +++ ld/emultempl/elf32.em | 3 ++ 21 files changed, 193 insertions(+), 222 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 18e63ebfdc..9bad45f336 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,43 @@ +2003-11-04 Alan Modra + + * bfd-in.h (_bfd_elf_tls_setup): Declare. + * bfd-in2.h: Regenerate. + * elf-bfd.h (struct elf_link_tls_segment): Delete. + (struct elf_link_hash_table): Add tls_sec and tls_size. + * elf.c (_bfd_elf_link_hash_table_init): Init tls_sec and tls_size. + * elflink.c (_bfd_elf_tls_setup): New function. + * elflink.h (struct elf_final_link_info): Remove first_tls_sec. + (elf_bfd_final_link): Don't set first_tls_sec here. Update code + saving tls segment info, round segment size up. + (elf_link_output_extsym): Adjust code using tls segment info. + (elf_link_input_bfd): Likewise. + * elf32-i386.c (dtpoff_base, tpoff): Likewise. + * elf32-s390.c (dtpoff_base, tpoff): Likewise. + * elf32-sh.c (dtpoff_base, tpoff): Likewise. + * elf32-sparc.c (dtpoff_base, tpoff): Likewise. + * elf64-s390.c (dtpoff_base, tpoff): Likewise. + * elf64-x86-64.c (dtpoff_base, tpoff): Likewise. + * elfxx-ia64.c (elfNN_ia64_tprel_base): Likewise. + (elfNN_ia64_dtprel_base): Likewise. + * elf64-alpha.c (alpha_get_dtprel_base): Likewise. + (alpha_get_tprel_base): Likewise. + (struct alpha_relax_info): Remove tls_segment. + (elf64_alpha_relax_got_load): Adjust invocation of + alpha_get_dtprel_base and alpha_get_tprel_base. + (elf64_alpha_relax_tls_get_addr): Likewise. + (elf64_alpha_relax_section): Likewise. + (elf64_alpha_relocate_section): Likewise. + (elf64_alpha_relax_find_tls_segment): Delete. + * elf32-ppc.c (struct ppc_elf_link_hash_table): Remove tls_sec. + (ppc_elf_tls_setup): Call _bfd_elf_tls_setup. Return section. + (ppc_elf_relocate_section): Adjust to use elf.tls_sec. + * elf32-ppc.h (ppc_elf_tls_setup): Update. + * elf64-ppc.c (struct ppc_link_hash_table): Remove tls_sec. + (ppc64_elf_tls_setup): Call _bfd_elf_tls_setup. Return section. + (ppc64_elf_tls_optimize): Adjust to use elf.tls_sec. + (ppc64_elf_relocate_section): Likewise. + * elf64-ppc.h (ppc64_elf_tls_setup): Update. + 2003-11-03 Daniel Jacobowitz * elf-bfd.h (struct elf_backend_data): Remove plt_header_size. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index cba25f4ba2..1a67d08ad2 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -677,6 +677,9 @@ extern int bfd_get_arch_size extern int bfd_get_sign_extend_vma (bfd *); +extern struct bfd_section *_bfd_elf_tls_setup + (bfd *, struct bfd_link_info *); + extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); extern bfd_boolean bfd_mips_elf32_create_embedded_relocs diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 1d0111663f..fbd05abdb9 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -684,6 +684,9 @@ extern int bfd_get_arch_size extern int bfd_get_sign_extend_vma (bfd *); +extern struct bfd_section *_bfd_elf_tls_setup + (bfd *, struct bfd_link_info *); + extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs (bfd *, struct bfd_link_info *, struct bfd_section *, struct bfd_section *, char **); extern bfd_boolean bfd_mips_elf32_create_embedded_relocs diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index a1019b635d..3353cde3e7 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -309,14 +309,6 @@ struct eh_frame_hdr_info bfd_boolean table; }; -/* Cached start, size and alignment of PT_TLS segment. */ -struct elf_link_tls_segment -{ - bfd_vma start; - bfd_size_type size; - unsigned int align; -}; - /* ELF linker hash table. */ struct elf_link_hash_table @@ -377,8 +369,9 @@ struct elf_link_hash_table objects included in the link. */ struct bfd_link_needed_list *runpath; - /* Cached start, size and alignment of PT_TLS segment. */ - struct elf_link_tls_segment *tls_segment; + /* Cached first output tls section and size of PT_TLS segment. */ + asection *tls_sec; + bfd_size_type tls_size; /* A linked list of BFD's loaded in the link. */ struct elf_link_loaded_list *loaded; diff --git a/bfd/elf.c b/bfd/elf.c index f891fbdeda..93e1a3e6e0 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1444,7 +1444,8 @@ _bfd_elf_link_hash_table_init memset (&table->eh_info, 0, sizeof (table->eh_info)); table->dynlocal = NULL; table->runpath = NULL; - table->tls_segment = NULL; + table->tls_sec = NULL; + table->tls_size = 0; table->loaded = NULL; ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc); diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 8f50a3dd49..ff8aab4a8b 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1953,10 +1953,10 @@ elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, static bfd_vma dtpoff_base (struct bfd_link_info *info) { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation @@ -1965,14 +1965,12 @@ dtpoff_base (struct bfd_link_info *info) static bfd_vma tpoff (struct bfd_link_info *info, bfd_vma address) { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); - /* If tls_segment is NULL, we should have signalled an error already. */ - if (tls_segment == NULL) + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) return 0; - return (align_power (tls_segment->size, tls_segment->align) - + tls_segment->start - address); + return htab->tls_size + htab->tls_sec->vma - address; } /* Relocate an i386 ELF section. */ diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 85755bb9df..1b10e5682c 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -205,9 +205,6 @@ struct ppc_elf_link_hash_table elf_linker_section_t *sdata2; asection *sbss; - /* Short-cut to first output tls section. */ - asection *tls_sec; - /* Shortcut to .__tls_get_addr. */ struct elf_link_hash_entry *tls_get_addr; @@ -4184,25 +4181,18 @@ ppc_elf_gc_sweep_hook (bfd *abfd, return TRUE; } -/* Set htab->tls_sec and htab->tls_get_addr. */ +/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ -bfd_boolean +asection * ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) { - asection *tls; struct ppc_elf_link_hash_table *htab; htab = ppc_elf_hash_table (info); htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE); - for (tls = obfd->sections; tls != NULL; tls = tls->next) - if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) - == (SEC_THREAD_LOCAL | SEC_LOAD)) - break; - htab->tls_sec = tls; - - return tls != NULL; + return _bfd_elf_tls_setup (obfd, info); } /* Run through all the TLS relocs looking for optimization @@ -4917,8 +4907,8 @@ ppc_elf_relocate_section (bfd *output_bfd, { /* Was an LD reloc. */ r_symndx = 0; - rel->r_addend = htab->tls_sec->vma + DTP_OFFSET; - rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET; + rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; + rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; } r_type = R_PPC_TPREL16_HA; rel->r_info = ELF32_R_INFO (r_symndx, r_type); @@ -5156,7 +5146,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { outrel.r_addend += relocation; if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - outrel.r_addend -= htab->tls_sec->vma; + outrel.r_addend -= htab->elf.tls_sec->vma; } loc = htab->relgot->contents; loc += (htab->relgot->reloc_count++ @@ -5174,7 +5164,7 @@ ppc_elf_relocate_section (bfd *output_bfd, value = 1; else if (tls_ty != 0) { - value -= htab->tls_sec->vma + DTP_OFFSET; + value -= htab->elf.tls_sec->vma + DTP_OFFSET; if (tls_ty == (TLS_TLS | TLS_TPREL)) value += DTP_OFFSET - TP_OFFSET; @@ -5262,7 +5252,7 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_DTPREL16_LO: case R_PPC_DTPREL16_HI: case R_PPC_DTPREL16_HA: - addend -= htab->tls_sec->vma + DTP_OFFSET; + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; /* Relocations that may need to be propagated if this is a shared @@ -5271,18 +5261,18 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: - addend -= htab->tls_sec->vma + TP_OFFSET; + addend -= htab->elf.tls_sec->vma + TP_OFFSET; /* The TPREL16 relocs shouldn't really be used in shared libs as they will result in DT_TEXTREL being set, but support them anyway. */ goto dodyn; case R_PPC_TPREL32: - addend -= htab->tls_sec->vma + TP_OFFSET; + addend -= htab->elf.tls_sec->vma + TP_OFFSET; goto dodyn; case R_PPC_DTPREL32: - addend -= htab->tls_sec->vma + DTP_OFFSET; + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; goto dodyn; case R_PPC_DTPMOD32: diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h index 72be813a80..fa2c585610 100644 --- a/bfd/elf32-ppc.h +++ b/bfd/elf32-ppc.h @@ -17,5 +17,5 @@ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -bfd_boolean ppc_elf_tls_setup (bfd *, struct bfd_link_info *); +asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *); bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *); diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c index 7f6c54ffa9..f594189d81 100644 --- a/bfd/elf32-s390.c +++ b/bfd/elf32-s390.c @@ -2216,10 +2216,10 @@ static bfd_vma dtpoff_base (info) struct bfd_link_info *info; { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation @@ -2230,14 +2230,12 @@ tpoff (info, address) struct bfd_link_info *info; bfd_vma address; { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); - /* If tls_segment is NULL, we should have signalled an error already. */ - if (tls_segment == NULL) + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) return 0; - return (align_power (tls_segment->size, tls_segment->align) - + tls_segment->start - address); + return htab->tls_size + htab->tls_sec->vma - address; } /* Complain if TLS instruction relocation is against an invalid diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c index 4fa6620bcc..34036e5284 100644 --- a/bfd/elf32-sh.c +++ b/bfd/elf32-sh.c @@ -6021,10 +6021,10 @@ sh_elf_get_relocated_section_contents (bfd *output_bfd, static bfd_vma dtpoff_base (struct bfd_link_info *info) { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for R_SH_TLS_TPOFF32.. */ @@ -6032,12 +6032,12 @@ dtpoff_base (struct bfd_link_info *info) static bfd_vma tpoff (struct bfd_link_info *info, bfd_vma address) { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) return 0; /* SH TLS ABI is variant I and static TLS block start just after tcbhead structure which has 2 pointer fields. */ - return (address - dtpoff_base (info) + 8); + return address - elf_hash_table (info)->tls_sec->vma + 8; } static asection * diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c index f226b07be8..85a2a2fe04 100644 --- a/bfd/elf32-sparc.c +++ b/bfd/elf32-sparc.c @@ -2082,10 +2082,10 @@ static bfd_vma dtpoff_base (info) struct bfd_link_info *info; { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation @@ -2096,14 +2096,12 @@ tpoff (info, address) struct bfd_link_info *info; bfd_vma address; { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); - /* If tls_segment is NULL, we should have signalled an error already. */ - if (tls_segment == NULL) + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) return 0; - return -(align_power (tls_segment->size, tls_segment->align) - + tls_segment->start - address); + return address - htab->tls_size - htab->tls_sec->vma; } /* Relocate a SPARC ELF section. */ diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c index 1d1eea7d5d..4933d28dab 100644 --- a/bfd/elf64-alpha.c +++ b/bfd/elf64-alpha.c @@ -1158,13 +1158,15 @@ elf64_alpha_info_to_howto (abfd, cache_ptr, dst) (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8) /* This is PT_TLS segment p_vaddr. */ -#define alpha_get_dtprel_base(tlss) \ - ((tlss)->start) +#define alpha_get_dtprel_base(info) \ + (elf_hash_table (info)->tls_sec->vma) /* Main program TLS (whose template starts at PT_TLS p_vaddr) is assigned offset round(16, PT_TLS p_align). */ -#define alpha_get_tprel_base(tlss) \ - ((tlss)->start - align_power ((bfd_vma) 16, (tlss)->align)) +#define alpha_get_tprel_base(info) \ + (elf_hash_table (info)->tls_sec->vma \ + - align_power ((bfd_vma) 16, \ + elf_hash_table (info)->tls_sec->alignment_power)) /* These functions do relaxation for Alpha ELF. @@ -1198,7 +1200,6 @@ struct alpha_relax_info Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *relocs, *relend; struct bfd_link_info *link_info; - struct elf_link_tls_segment *tls_segment; bfd_vma gp; bfd *gotobj; asection *tsec; @@ -1224,8 +1225,6 @@ static bfd_boolean elf64_alpha_relax_gprelhilo static bfd_boolean elf64_alpha_relax_tls_get_addr PARAMS((struct alpha_relax_info *info, bfd_vma symval, Elf_Internal_Rela *irel, bfd_boolean)); -static struct elf_link_tls_segment *elf64_alpha_relax_find_tls_segment - PARAMS((struct alpha_relax_info *, struct elf_link_tls_segment *)); static bfd_boolean elf64_alpha_relax_section PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info, bfd_boolean *again)); @@ -1598,9 +1597,9 @@ elf64_alpha_relax_got_load (info, symval, irel, r_type) { bfd_vma dtp_base, tp_base; - BFD_ASSERT (info->tls_segment != NULL); - dtp_base = alpha_get_dtprel_base (info->tls_segment); - tp_base = alpha_get_tprel_base (info->tls_segment); + BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL); + dtp_base = alpha_get_dtprel_base (info->link_info); + tp_base = alpha_get_tprel_base (info->link_info); disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base); } @@ -1845,8 +1844,8 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd) bfd_vma tp_base; bfd_signed_vma disp; - BFD_ASSERT (info->tls_segment != NULL); - tp_base = alpha_get_tprel_base (info->tls_segment); + BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL); + tp_base = alpha_get_tprel_base (info->link_info); disp = symval - tp_base; if (disp >= -0x8000 && disp < 0x8000) @@ -1961,53 +1960,6 @@ elf64_alpha_relax_tls_get_addr (info, symval, irel, is_gd) return TRUE; } -static struct elf_link_tls_segment * -elf64_alpha_relax_find_tls_segment (info, seg) - struct alpha_relax_info *info; - struct elf_link_tls_segment *seg; -{ - bfd *output_bfd = info->sec->output_section->owner; - asection *o; - unsigned int align; - bfd_vma base, end; - - for (o = output_bfd->sections; o ; o = o->next) - if ((o->flags & SEC_THREAD_LOCAL) != 0 - && (o->flags & SEC_LOAD) != 0) - break; - if (!o) - return NULL; - - base = o->vma; - align = 0; - - do - { - bfd_vma size; - - if (bfd_get_section_alignment (output_bfd, o) > align) - align = bfd_get_section_alignment (output_bfd, o); - - size = o->_raw_size; - if (size == 0 && (o->flags & SEC_HAS_CONTENTS) == 0) - { - struct bfd_link_order *lo; - for (lo = o->link_order_head; lo ; lo = lo->next) - if (size < lo->offset + lo->size) - size = lo->offset + lo->size; - } - end = o->vma + size; - o = o->next; - } - while (o && (o->flags & SEC_THREAD_LOCAL)); - - seg->start = base; - seg->size = end - base; - seg->align = align; - - return seg; -} - static bfd_boolean elf64_alpha_relax_section (abfd, sec, link_info, again) bfd *abfd; @@ -2021,7 +1973,6 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) Elf_Internal_Sym *isymbuf = NULL; struct alpha_elf_got_entry **local_got_entries; struct alpha_relax_info info; - struct elf_link_tls_segment tls_segment; /* We are not currently changing any sizes, so only one pass. */ *again = FALSE; @@ -2079,11 +2030,6 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) goto error_return; } - /* Compute the TLS segment information. The version normally found in - elf_hash_table (link_info)->tls_segment isn't built until final_link. - ??? Probably should look into extracting this into a common function. */ - info.tls_segment = elf64_alpha_relax_find_tls_segment (&info, &tls_segment); - for (irel = internal_relocs; irel < irelend; irel++) { bfd_vma symval; @@ -2137,7 +2083,7 @@ elf64_alpha_relax_section (abfd, sec, link_info, again) if (r_type == R_ALPHA_TLSLDM) { info.tsec = bfd_abs_section_ptr; - symval = alpha_get_tprel_base (info.tls_segment); + symval = alpha_get_tprel_base (info.link_info); } else { @@ -4294,7 +4240,6 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; - struct elf_link_tls_segment *tls_segment; asection *sgot, *srel, *srelgot; bfd *dynobj, *gotobj; bfd_vma gp, tp_base, dtp_base; @@ -4348,11 +4293,10 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries; - tls_segment = elf_hash_table (info)->tls_segment; - if (tls_segment) + if (elf_hash_table (info)->tls_sec != NULL) { - dtp_base = alpha_get_dtprel_base (tls_segment); - tp_base = alpha_get_tprel_base (tls_segment); + dtp_base = alpha_get_dtprel_base (info); + tp_base = alpha_get_tprel_base (info); } else dtp_base = tp_base = 0; @@ -4674,13 +4618,13 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, } else if (r_type == R_ALPHA_DTPREL64) { - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); value -= dtp_base; goto default_reloc; } else if (r_type == R_ALPHA_TPREL64) { - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); if (!info->shared) { value -= tp_base; @@ -4760,7 +4704,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, value = 0; else { - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); value -= dtp_base; } bfd_put_64 (output_bfd, value, @@ -4783,7 +4727,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, bfd_archive_filename (input_bfd), h->root.root.root.string); ret_val = FALSE; } - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); value -= dtp_base; if (r_type == R_ALPHA_DTPRELHI) value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); @@ -4806,7 +4750,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, bfd_archive_filename (input_bfd), h->root.root.root.string); ret_val = FALSE; } - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); value -= tp_base; if (r_type == R_ALPHA_TPRELHI) value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1); @@ -4827,7 +4771,7 @@ elf64_alpha_relocate_section (output_bfd, info, input_bfd, input_section, value = 0; else { - BFD_ASSERT(tls_segment != NULL); + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); if (r_type == R_ALPHA_GOTDTPREL) value -= dtp_base; else if (!info->shared) diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index da3edc4703..d6291f4e04 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -2837,9 +2837,6 @@ struct ppc_link_hash_table asection *brlt; asection *relbrlt; - /* Short-cut to first output tls section. */ - asection *tls_sec; - /* Shortcut to .__tls_get_addr. */ struct elf_link_hash_entry *tls_get_addr; @@ -5172,22 +5169,14 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info) return TRUE; } -/* Set htab->tls_sec. */ +/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ -bfd_boolean +asection * ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) { - asection *tls; struct ppc_link_hash_table *htab; - for (tls = obfd->sections; tls != NULL; tls = tls->next) - if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) - == (SEC_THREAD_LOCAL | SEC_LOAD)) - break; - htab = ppc_hash_table (info); - htab->tls_sec = tls; - if (htab->tls_get_addr != NULL) { struct elf_link_hash_entry *h = htab->tls_get_addr; @@ -5199,7 +5188,7 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) htab->tls_get_addr = h; } - return tls != NULL; + return _bfd_elf_tls_setup (obfd, info); } /* Run through all the TLS relocs looking for optimization @@ -5282,7 +5271,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) is_local = TRUE; value += sym_sec->output_offset; value += sym_sec->output_section->vma; - value -= htab->tls_sec->vma; + value -= htab->elf.tls_sec->vma; ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) < (bfd_vma) 1 << 32); } @@ -7690,8 +7679,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, { /* Was an LD reloc. */ r_symndx = 0; - rel->r_addend = htab->tls_sec->vma + DTP_OFFSET; - rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET; + rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; + rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; } else if (toc_symndx != 0) r_symndx = toc_symndx; @@ -8096,7 +8085,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, { outrel.r_addend += relocation; if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL)) - outrel.r_addend -= htab->tls_sec->vma; + outrel.r_addend -= htab->elf.tls_sec->vma; } loc = relgot->contents; loc += (relgot->reloc_count++ @@ -8113,7 +8102,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, relocation = 1; else if (tls_type != 0) { - relocation -= htab->tls_sec->vma + DTP_OFFSET; + relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; if (tls_type == (TLS_TLS | TLS_TPREL)) relocation += DTP_OFFSET - TP_OFFSET; @@ -8223,7 +8212,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: case R_PPC64_TPREL16_HIGHESTA: - addend -= htab->tls_sec->vma + TP_OFFSET; + addend -= htab->elf.tls_sec->vma + TP_OFFSET; if (info->shared) /* The TPREL16 relocs shouldn't really be used in shared libs as they will result in DT_TEXTREL being set, but @@ -8241,7 +8230,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_DTPREL16_HIGHERA: case R_PPC64_DTPREL16_HIGHEST: case R_PPC64_DTPREL16_HIGHESTA: - addend -= htab->tls_sec->vma + DTP_OFFSET; + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; break; case R_PPC64_DTPMOD64: @@ -8250,11 +8239,11 @@ ppc64_elf_relocate_section (bfd *output_bfd, goto dodyn; case R_PPC64_TPREL64: - addend -= htab->tls_sec->vma + TP_OFFSET; + addend -= htab->elf.tls_sec->vma + TP_OFFSET; goto dodyn; case R_PPC64_DTPREL64: - addend -= htab->tls_sec->vma + DTP_OFFSET; + addend -= htab->elf.tls_sec->vma + DTP_OFFSET; /* Fall thru */ /* Relocations that may need to be propagated if this is a diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h index c26df82da8..998e7e13e0 100644 --- a/bfd/elf64-ppc.h +++ b/bfd/elf64-ppc.h @@ -23,7 +23,7 @@ bfd_boolean ppc64_elf_mark_entry_syms (struct bfd_link_info *); bfd_boolean ppc64_elf_edit_opd (bfd *, struct bfd_link_info *); -bfd_boolean ppc64_elf_tls_setup +asection *ppc64_elf_tls_setup (bfd *, struct bfd_link_info *); bfd_boolean ppc64_elf_tls_optimize (bfd *, struct bfd_link_info *); diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index b299bb7f03..a55a191c3e 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -2186,10 +2186,10 @@ static bfd_vma dtpoff_base (info) struct bfd_link_info *info; { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation @@ -2200,14 +2200,12 @@ tpoff (info, address) struct bfd_link_info *info; bfd_vma address; { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); - /* If tls_segment is NULL, we should have signalled an error already. */ - if (tls_segment == NULL) + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) return 0; - return (align_power (tls_segment->size, tls_segment->align) - + tls_segment->start - address); + return htab->tls_size + htab->tls_sec->vma - address; } /* Complain if TLS instruction relocation is against an invalid diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 9c5a1ea5b9..44e60e8997 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1739,10 +1739,10 @@ elf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, static bfd_vma dtpoff_base (struct bfd_link_info *info) { - /* If tls_segment is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_segment == NULL) + /* 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_segment->start; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation @@ -1751,14 +1751,12 @@ dtpoff_base (struct bfd_link_info *info) static bfd_vma tpoff (struct bfd_link_info *info, bfd_vma address) { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); /* If tls_segment is NULL, we should have signalled an error already. */ - if (tls_segment == NULL) + if (htab->tls_sec == NULL) return 0; - return address - align_power (tls_segment->size, tls_segment->align) - - tls_segment->start; + return address - htab->tls_size - htab->tls_sec->vma; } /* Relocate an x86_64 ELF section. */ diff --git a/bfd/elflink.c b/bfd/elflink.c index 651ffd5de5..919de9c776 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2519,3 +2519,31 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h, dynamic linker will resolve them locally. */ return local_protected; } + +/* Caches some TLS segment info, and ensures that the TLS segment vma is + aligned. Returns the first TLS output section. */ + +struct bfd_section * +_bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) +{ + struct bfd_section *sec, *tls; + unsigned int align = 0; + + for (sec = obfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_THREAD_LOCAL) != 0) + break; + tls = sec; + + for (; sec != NULL && (sec->flags & SEC_THREAD_LOCAL) != 0; sec = sec->next) + if (sec->alignment_power > align) + align = sec->alignment_power; + + elf_hash_table (info)->tls_sec = tls; + + /* Ensure the alignment of the first section is the largest alignment, + so that the tls segment starts aligned. */ + if (tls != NULL) + tls->alignment_power = align; + + return tls; +} diff --git a/bfd/elflink.h b/bfd/elflink.h index aa74573f7e..7cd1bdcb94 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -2804,8 +2804,6 @@ struct elf_final_link_info asection *hash_sec; /* symbol version section (.gnu.version). */ asection *symver_sec; - /* first SHF_TLS section (if any). */ - asection *first_tls_sec; /* Buffer large enough to hold contents of any section. */ bfd_byte *contents; /* Buffer large enough to hold external relocs of any section. */ @@ -3160,14 +3158,6 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info) finfo.symshndxbuf = NULL; finfo.symbuf_count = 0; finfo.shndxbuf_size = 0; - finfo.first_tls_sec = NULL; - for (o = abfd->sections; o != NULL; o = o->next) - if ((o->flags & SEC_THREAD_LOCAL) != 0 - && (o->flags & SEC_LOAD) != 0) - { - finfo.first_tls_sec = o; - break; - } /* Count up the number of relocations we will output for each output section, so that we know the sizes of the reloc sections. We @@ -3525,38 +3515,30 @@ elf_bfd_final_link (bfd *abfd, struct bfd_link_info *info) goto error_return; } - if (finfo.first_tls_sec) + if (elf_hash_table (info)->tls_sec) { - unsigned int align = 0; - bfd_vma base = finfo.first_tls_sec->vma, end = 0; + bfd_vma base, end = 0; asection *sec; - for (sec = finfo.first_tls_sec; + for (sec = elf_hash_table (info)->tls_sec; sec && (sec->flags & SEC_THREAD_LOCAL); sec = sec->next) { bfd_vma size = sec->_raw_size; - if (bfd_get_section_alignment (abfd, sec) > align) - align = bfd_get_section_alignment (abfd, sec); - if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) + if (size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) { struct bfd_link_order *o; - size = 0; for (o = sec->link_order_head; o != NULL; o = o->next) if (size < o->offset + o->size) size = o->offset + o->size; } end = sec->vma + size; } - elf_hash_table (info)->tls_segment - = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment)); - if (elf_hash_table (info)->tls_segment == NULL) - goto error_return; - elf_hash_table (info)->tls_segment->start = base; - elf_hash_table (info)->tls_segment->size = end - base; - elf_hash_table (info)->tls_segment->align = align; + base = elf_hash_table (info)->tls_sec->vma; + end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power); + elf_hash_table (info)->tls_size = end - base; } /* Since ELF permits relocations to be against local symbols, we @@ -4503,8 +4485,8 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) { /* STT_TLS symbols are relative to PT_TLS segment base. */ - BFD_ASSERT (finfo->first_tls_sec != NULL); - sym.st_value -= finfo->first_tls_sec->vma; + BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL); + sym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma; } } } @@ -4862,8 +4844,8 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) if (ELF_ST_TYPE (osym.st_info) == STT_TLS) { /* STT_TLS symbols are relative to PT_TLS segment base. */ - BFD_ASSERT (finfo->first_tls_sec != NULL); - osym.st_value -= finfo->first_tls_sec->vma; + BFD_ASSERT (elf_hash_table (finfo->info)->tls_sec != NULL); + osym.st_value -= elf_hash_table (finfo->info)->tls_sec->vma; } } @@ -5219,8 +5201,10 @@ elf_link_input_bfd (struct elf_final_link_info *finfo, bfd *input_bfd) { /* STT_TLS symbols are relative to PT_TLS segment base. */ - BFD_ASSERT (finfo->first_tls_sec != NULL); - sym.st_value -= finfo->first_tls_sec->vma; + BFD_ASSERT (elf_hash_table (finfo->info) + ->tls_sec != NULL); + sym.st_value -= (elf_hash_table (finfo->info) + ->tls_sec->vma); } } diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index 8a109e921f..8fae4eefa6 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -3544,12 +3544,10 @@ static bfd_vma elfNN_ia64_tprel_base (info) struct bfd_link_info *info; { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + asection *tls_sec = elf_hash_table (info)->tls_sec; - BFD_ASSERT (tls_segment != NULL); - return (tls_segment->start - - align_power ((bfd_vma) 16, tls_segment->align)); + BFD_ASSERT (tls_sec != NULL); + return tls_sec->vma - align_power ((bfd_vma) 16, tls_sec->alignment_power); } /* Return the base VMA address which should be subtracted from real addresses @@ -3560,8 +3558,8 @@ static bfd_vma elfNN_ia64_dtprel_base (info) struct bfd_link_info *info; { - BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL); - return elf_hash_table (info)->tls_segment->start; + BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); + return elf_hash_table (info)->tls_sec->vma; } /* Called through qsort to sort the .IA_64.unwind section during a diff --git a/ld/ChangeLog b/ld/ChangeLog index 83350bd996..7e6e10f67c 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,8 @@ +2003-11-04 Alan Modra + + * emultempl/elf32.em (gld${EMULATION_NAME}_before_allocation): Call + _bfd_elf_tls_setup. + 2003-10-31 Nick Clifton * ldlang.c (lookup_name): When looking for a previously loaded diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 33cff6aca6..6e1f815d5f 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -845,6 +845,9 @@ gld${EMULATION_NAME}_before_allocation (void) const char *rpath; asection *sinterp; + if (link_info.hash->creator->flavour == bfd_target_elf_flavour) + _bfd_elf_tls_setup (output_bfd, &link_info); + /* If we are going to make any variable assignments, we need to let the ELF backend know about them in case the variables are referred to by dynamic objects. */ -- 2.34.1