From a7f2871e66570d025ce909c16bd53be5ff814191 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 21 Sep 2009 11:51:02 +0000 Subject: [PATCH] include/elf/ * ppc.h (DT_PPC_TLSOPT): Define. * ppc64.h (DT_PPC64_TLSOPT): Define. bfd/ * elf32-ppc.c (TLS_GET_ADDR_GLINK_SIZE): Define. (ADD_3_12_2, BEQLR, CMPWI_11_0, LWZ_11_3, LWZ_12_3): Define. (MR_0_3, MR_3_0): Define. (struct ppc_elf_link_hash_table): Add no_tls_get_addr_opt. (ppc_elf_select_plt_layout): Save emit_stub_syms param earlier. (ppc_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash table. Check for presense of __tls_get_addr_opt (allocate_dynrelocs): Increase glink entry size for __tls_get_addr. (ppc_elf_size_dynamic_sections): Add DT_PPC_TLS_OPT tag. (write_glink_stub): Add param p. (ppc_elf_relocate_section): Adjust write_glink_stub call. (ppc_elf_finish_dynamic_symbol): Emit special glink call stub for __tls_get_addr. * elf32-ppc.h (ppc_elf_tls_setup): Update prototype. * elf64-ppc.c (struct ppc_link_hash_table): Add no_tls_get_addr_opt. (ppc64_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash table. Check for presense of __tls_get_addr_opt. (ppc64_elf_size_dynamic_sections): Add DT_PPC64_TLS_OPT tag. (LD_R11_0R3, LD_R12_0R3, MR_R0_R3, CMPDI_R11_0, ADD_R3_R12_R13, BEQLR, MR_R3_R0, MFLR_R11, STD_R11_0R1, BCTRL, LD_R11_0R1, LD_R2_0R1, MTLR_R11): Define. (build_tls_get_addr_stub): New function. (ppc_build_one_stub): Call it. (ppc_size_one_stub): Add extra size for __tls_get_addr stub. (ppc64_elf_relocate_section): Don't change nop to ld 2,40(1) for __tls_get_addr plt call. * elf64-ppc.h (ppc64_elf_tls_setup): Update prototype. binutils/ * readelf.c (get_ppc_dynamic_type): Add TLSOPT. (get_ppc64_dynamic_type): Likewise. ld/ * emultempl/ppc32elf.em (no_tls_get_addr_opt): New var. (ppc_before_allocation): Pass to ppc_elf_tls_setup. (OPTION_NO_TLS_GET_ADDR_OPT): Define. Redefine other options in terms of previous option. (PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add --no-tls-get-addr-optimize. (PARSE_AND_LIST_ARGS_CASES): Handle it. * emultempl/ppc64elf.em (no_tls_get_addr_opt): New var. (ppc_before_allocation): Pass to ppc64_elf_tls_setup. (OPTION_NO_TLS_GET_ADDR_OPT): Define. (PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add --no-tls-get-addr-optimize. (PARSE_AND_LIST_ARGS_CASES): Handle it. ld/testsuite/ * ld-powerpc/tlslib.s: Delete dot-symbol entry syms. Add __tls_get_addr_opt. * ld-powerpc/tlslib32.s: Add __tls_get_addr_opt. * ld-powerpc/oldtlslib.s: New file, old-abi version of tlslib.s. * ld-powerpc/powerpc.exp: Build old-abi library and use it in two new link tests. * ld-powerpc/tlsexe.d: Update for new __tls_get_addr stub. * ld-powerpc/tlsexe.g, * ld-powerpc/tlsexe.r, *ld-powerpc/tlsexe32.d, * ld-powerpc/tlsexe32.g, * ld-powerpc/tlsexe32.r, * ld-powerpc/tlsexetoc.d, * ld-powerpc/tlsexetoc.g, * ld-powerpc/tlsexetoc.r: Likewise. --- bfd/ChangeLog | 30 ++++++ bfd/elf32-ppc.c | 111 ++++++++++++++++++-- bfd/elf32-ppc.h | 2 +- bfd/elf64-ppc.c | 155 +++++++++++++++++++++++++++- bfd/elf64-ppc.h | 2 +- binutils/ChangeLog | 5 + binutils/readelf.c | 10 +- include/elf/ChangeLog | 5 + include/elf/ppc.h | 5 +- include/elf/ppc64.h | 3 + ld/ChangeLog | 16 +++ ld/emultempl/ppc32elf.em | 20 +++- ld/emultempl/ppc64elf.em | 15 ++- ld/testsuite/ChangeLog | 14 +++ ld/testsuite/ld-powerpc/oldtlslib.s | 29 ++++++ ld/testsuite/ld-powerpc/powerpc.exp | 11 ++ ld/testsuite/ld-powerpc/tlsexe.d | 24 ++++- ld/testsuite/ld-powerpc/tlsexe.g | 2 +- ld/testsuite/ld-powerpc/tlsexe.r | 12 +-- ld/testsuite/ld-powerpc/tlsexe32.d | 4 +- ld/testsuite/ld-powerpc/tlsexe32.g | 2 +- ld/testsuite/ld-powerpc/tlsexe32.r | 6 +- ld/testsuite/ld-powerpc/tlsexetoc.d | 28 +++-- ld/testsuite/ld-powerpc/tlsexetoc.g | 2 +- ld/testsuite/ld-powerpc/tlsexetoc.r | 12 +-- ld/testsuite/ld-powerpc/tlslib.s | 11 +- ld/testsuite/ld-powerpc/tlslib32.s | 4 +- 27 files changed, 475 insertions(+), 65 deletions(-) create mode 100644 ld/testsuite/ld-powerpc/oldtlslib.s diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a4f99e79f4d..9900119f37b 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,33 @@ +2009-09-21 Alan Modra + + * elf32-ppc.c (TLS_GET_ADDR_GLINK_SIZE): Define. + (ADD_3_12_2, BEQLR, CMPWI_11_0, LWZ_11_3, LWZ_12_3): Define. + (MR_0_3, MR_3_0): Define. + (struct ppc_elf_link_hash_table): Add no_tls_get_addr_opt. + (ppc_elf_select_plt_layout): Save emit_stub_syms param earlier. + (ppc_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash + table. Check for presense of __tls_get_addr_opt + (allocate_dynrelocs): Increase glink entry size for __tls_get_addr. + (ppc_elf_size_dynamic_sections): Add DT_PPC_TLS_OPT tag. + (write_glink_stub): Add param p. + (ppc_elf_relocate_section): Adjust write_glink_stub call. + (ppc_elf_finish_dynamic_symbol): Emit special glink call stub for + __tls_get_addr. + * elf32-ppc.h (ppc_elf_tls_setup): Update prototype. + * elf64-ppc.c (struct ppc_link_hash_table): Add no_tls_get_addr_opt. + (ppc64_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash + table. Check for presense of __tls_get_addr_opt. + (ppc64_elf_size_dynamic_sections): Add DT_PPC64_TLS_OPT tag. + (LD_R11_0R3, LD_R12_0R3, MR_R0_R3, CMPDI_R11_0, ADD_R3_R12_R13, + BEQLR, MR_R3_R0, MFLR_R11, STD_R11_0R1, BCTRL, LD_R11_0R1, + LD_R2_0R1, MTLR_R11): Define. + (build_tls_get_addr_stub): New function. + (ppc_build_one_stub): Call it. + (ppc_size_one_stub): Add extra size for __tls_get_addr stub. + (ppc64_elf_relocate_section): Don't change nop to ld 2,40(1) for + __tls_get_addr plt call. + * elf64-ppc.h (ppc64_elf_tls_setup): Update prototype. + 2009-09-19 Richard Sandiford * elf-bfd.h (eh_cie_fde): Add personality_offset and diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index bbe94dba987..95058a233db 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -61,6 +61,7 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc /* For new-style .glink and .plt. */ #define GLINK_PLTRESOLVE 16*4 #define GLINK_ENTRY_SIZE 4*4 +#define TLS_GET_ADDR_GLINK_SIZE 12*4 /* VxWorks uses its own plt layout, filled in by the static linker. */ @@ -135,17 +136,24 @@ static const bfd_vma ppc_elf_vxworks_pic_plt0_entry #define ADDIS_12_12 0x3d8c0000 #define ADDI_11_11 0x396b0000 #define ADD_0_11_11 0x7c0b5a14 +#define ADD_3_12_2 0x7c6c1214 #define ADD_11_0_11 0x7d605a14 #define B 0x48000000 #define BCL_20_31 0x429f0005 #define BCTR 0x4e800420 +#define BEQLR 0x4d820020 +#define CMPWI_11_0 0x2c0b0000 #define LIS_11 0x3d600000 #define LIS_12 0x3d800000 #define LWZU_0_12 0x840c0000 #define LWZ_0_12 0x800c0000 +#define LWZ_11_3 0x81630000 #define LWZ_11_11 0x816b0000 #define LWZ_11_30 0x817e0000 +#define LWZ_12_3 0x81830000 #define LWZ_12_12 0x818c0000 +#define MR_0_3 0x7c601b78 +#define MR_3_0 0x7c030378 #define MFLR_0 0x7c0802a6 #define MFLR_12 0x7d8802a6 #define MTCTR_0 0x7c0903a6 @@ -2754,6 +2762,9 @@ struct ppc_elf_link_hash_table /* Set if we should emit symbols for stubs. */ unsigned int emit_stub_syms:1; + /* Set if __tls_get_addr optimization should not be done. */ + unsigned int no_tls_get_addr_opt:1; + /* True if the target system is VxWorks. */ unsigned int is_vxworks:1; @@ -4277,6 +4288,8 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, htab = ppc_elf_hash_table (info); + htab->emit_stub_syms = emit_stub_syms; + if (htab->plt_type == PLT_UNSET) { if (plt_style == PLT_OLD) @@ -4310,8 +4323,6 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW) info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd); - htab->emit_stub_syms = emit_stub_syms; - BFD_ASSERT (htab->plt_type != PLT_VXWORKS); if (htab->plt_type == PLT_NEW) @@ -4539,11 +4550,62 @@ ppc_elf_gc_sweep_hook (bfd *abfd, generic ELF tls_setup function. */ asection * -ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) +ppc_elf_tls_setup (bfd *obfd, + struct bfd_link_info *info, + int no_tls_get_addr_opt) { 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); + if (!no_tls_get_addr_opt) + { + struct elf_link_hash_entry *opt, *tga; + opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", + FALSE, FALSE, TRUE); + if (opt != NULL + && (opt->root.type == bfd_link_hash_defined + || opt->root.type == bfd_link_hash_defweak)) + { + /* If glibc supports an optimized __tls_get_addr call stub, + signalled by the presence of __tls_get_addr_opt, and we'll + be calling __tls_get_addr via a plt call stub, then + make __tls_get_addr point to __tls_get_addr_opt. */ + tga = htab->tls_get_addr; + if (htab->elf.dynamic_sections_created + && tga != NULL + && (tga->type == STT_FUNC + || tga->needs_plt) + && !(SYMBOL_CALLS_LOCAL (info, tga) + || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT + && tga->root.type == bfd_link_hash_undefweak))) + { + struct plt_entry *ent; + ent = find_plt_ent (&tga->plt.plist, NULL, 0); + if (ent != NULL + && ent->plt.refcount > 0) + { + tga->root.type = bfd_link_hash_indirect; + tga->root.u.i.link = &opt->root; + ppc_elf_copy_indirect_symbol (info, opt, tga); + if (opt->dynindx != -1) + { + /* Use __tls_get_addr_opt in dynamic relocations. */ + opt->dynindx = -1; + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + opt->dynstr_index); + if (!bfd_elf_link_record_dynamic_symbol (info, opt)) + return FALSE; + } + htab->tls_get_addr = opt; + } + } + } + else + no_tls_get_addr_opt = TRUE; + } + htab->no_tls_get_addr_opt = no_tls_get_addr_opt; if (htab->plt_type == PLT_NEW && htab->plt != NULL && htab->plt->output_section != NULL) @@ -4552,8 +4614,6 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE; } - htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", - FALSE, FALSE, TRUE); return _bfd_elf_tls_setup (obfd, info); } @@ -5144,6 +5204,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { glink_offset = s->size; s->size += GLINK_ENTRY_SIZE; + if (h == htab->tls_get_addr + && !htab->no_tls_get_addr_opt) + s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE; } if (!doneone && !info->shared @@ -5820,6 +5883,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { if (!add_dynamic_entry (DT_PPC_GOT, 0)) return FALSE; + if (!htab->no_tls_get_addr_opt + && htab->tls_get_addr != NULL + && htab->tls_get_addr->plt.plist != NULL + && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) + return FALSE; } if (relocs) @@ -6474,18 +6542,16 @@ elf_finish_pointer_linker_section (bfd *input_bfd, #define PPC_HA(v) PPC_HI ((v) + 0x8000) static void -write_glink_stub (struct plt_entry *ent, asection *plt_sec, +write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p, struct bfd_link_info *info) { struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); bfd *output_bfd = info->output_bfd; bfd_vma plt; - unsigned char *p; plt = ((ent->plt.offset & ~1) + plt_sec->output_section->vma + plt_sec->output_offset); - p = (unsigned char *) htab->glink->contents + ent->glink_offset; if (info->shared) { @@ -7045,7 +7111,9 @@ ppc_elf_relocate_section (bfd *output_bfd, } if (h == NULL && (ent->glink_offset & 1) == 0) { - write_glink_stub (ent, htab->iplt, info); + unsigned char *p = ((unsigned char *) htab->glink->contents + + ent->glink_offset); + write_glink_stub (ent, htab->iplt, p, info); ent->glink_offset |= 1; } @@ -8274,12 +8342,35 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, || !htab->elf.dynamic_sections_created || h->dynindx == -1) { + unsigned char *p; asection *splt = htab->plt; if (!htab->elf.dynamic_sections_created || h->dynindx == -1) splt = htab->iplt; - write_glink_stub (ent, splt, info); + p = (unsigned char *) htab->glink->contents + ent->glink_offset; + + if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt) + { + bfd_put_32 (output_bfd, LWZ_11_3, p); + p += 4; + bfd_put_32 (output_bfd, LWZ_12_3 + 4, p); + p += 4; + bfd_put_32 (output_bfd, MR_0_3, p); + p += 4; + bfd_put_32 (output_bfd, CMPWI_11_0, p); + p += 4; + bfd_put_32 (output_bfd, ADD_3_12_2, p); + p += 4; + bfd_put_32 (output_bfd, BEQLR, p); + p += 4; + bfd_put_32 (output_bfd, MR_3_0, p); + p += 4; + bfd_put_32 (output_bfd, NOP, p); + p += 4; + } + + write_glink_stub (ent, splt, p, info); if (!info->shared) /* We only need one non-PIC glink stub. */ diff --git a/bfd/elf32-ppc.h b/bfd/elf32-ppc.h index ef1f0accdb3..4becb302a89 100644 --- a/bfd/elf32-ppc.h +++ b/bfd/elf32-ppc.h @@ -28,6 +28,6 @@ enum ppc_elf_plt_type int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *, enum ppc_elf_plt_type, int); -asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *); +asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *, int); bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *); void ppc_elf_set_sdata_syms (bfd *, struct bfd_link_info *); diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 99bfec2806a..35757b85d5c 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3771,6 +3771,9 @@ struct ppc_link_hash_table /* Set if we should emit symbols for stubs. */ unsigned int emit_stub_syms:1; + /* Set if __tls_get_addr optimization should not be done. */ + unsigned int no_tls_get_addr_opt:1; + /* Support for multiple toc sections. */ unsigned int no_multi_toc:1; unsigned int multi_toc_needed:1; @@ -7218,7 +7221,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info, /* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ asection * -ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) +ppc64_elf_tls_setup (bfd *obfd, + struct bfd_link_info *info, + int no_tls_get_addr_opt) { struct ppc_link_hash_table *htab; @@ -7226,9 +7231,83 @@ ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) htab->tls_get_addr = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, ".__tls_get_addr", FALSE, FALSE, TRUE)); + /* Move dynamic linking info to the function descriptor sym. */ + if (htab->tls_get_addr != NULL) + func_desc_adjust (&htab->tls_get_addr->elf, info); htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *) elf_link_hash_lookup (&htab->elf, "__tls_get_addr", FALSE, FALSE, TRUE)); + if (!no_tls_get_addr_opt) + { + struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd; + + opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt", + FALSE, FALSE, TRUE); + if (opt != NULL) + func_desc_adjust (opt, info); + opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt", + FALSE, FALSE, TRUE); + if (opt_fd != NULL + && (opt_fd->root.type == bfd_link_hash_defined + || opt_fd->root.type == bfd_link_hash_defweak)) + { + /* If glibc supports an optimized __tls_get_addr call stub, + signalled by the presence of __tls_get_addr_opt, and we'll + be calling __tls_get_addr via a plt call stub, then + make __tls_get_addr point to __tls_get_addr_opt. */ + tga_fd = &htab->tls_get_addr_fd->elf; + if (htab->elf.dynamic_sections_created + && tga_fd != NULL + && (tga_fd->type == STT_FUNC + || tga_fd->needs_plt) + && !(SYMBOL_CALLS_LOCAL (info, tga_fd) + || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT + && tga_fd->root.type == bfd_link_hash_undefweak))) + { + struct plt_entry *ent; + + for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next) + if (ent->plt.refcount > 0) + break; + if (ent != NULL) + { + tga_fd->root.type = bfd_link_hash_indirect; + tga_fd->root.u.i.link = &opt_fd->root; + ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd); + if (opt_fd->dynindx != -1) + { + /* Use __tls_get_addr_opt in dynamic relocations. */ + opt_fd->dynindx = -1; + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + opt_fd->dynstr_index); + if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd)) + return FALSE; + } + htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd; + tga = &htab->tls_get_addr->elf; + if (opt != NULL && tga != NULL) + { + tga->root.type = bfd_link_hash_indirect; + tga->root.u.i.link = &opt->root; + ppc64_elf_copy_indirect_symbol (info, opt, tga); + _bfd_elf_link_hash_hide_symbol (info, opt, + tga->forced_local); + htab->tls_get_addr = (struct ppc_link_hash_entry *) opt; + } + htab->tls_get_addr_fd->oh = htab->tls_get_addr; + htab->tls_get_addr_fd->is_func_descriptor = 1; + if (htab->tls_get_addr != NULL) + { + htab->tls_get_addr->oh = htab->tls_get_addr_fd; + htab->tls_get_addr->is_func = 1; + } + } + } + } + else + no_tls_get_addr_opt = TRUE; + } + htab->no_tls_get_addr_opt = no_tls_get_addr_opt; return _bfd_elf_tls_setup (obfd, info); } @@ -8666,6 +8745,12 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } + if (!htab->no_tls_get_addr_opt + && htab->tls_get_addr_fd != NULL + && htab->tls_get_addr_fd->elf.plt.plist != NULL + && !add_dynamic_entry (DT_PPC64_TLSOPT, 0)) + return FALSE; + if (relocs) { if (!add_dynamic_entry (DT_RELA, 0) @@ -8859,6 +8944,49 @@ build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r) return p; } +/* Build a special .plt call stub for __tls_get_addr. */ + +#define LD_R11_0R3 0xe9630000 +#define LD_R12_0R3 0xe9830000 +#define MR_R0_R3 0x7c601b78 +#define CMPDI_R11_0 0x2c2b0000 +#define ADD_R3_R12_R13 0x7c6c6a14 +#define BEQLR 0x4d820020 +#define MR_R3_R0 0x7c030378 +#define MFLR_R11 0x7d6802a6 +#define STD_R11_0R1 0xf9610000 +#define BCTRL 0x4e800421 +#define LD_R11_0R1 0xe9610000 +#define LD_R2_0R1 0xe8410000 +#define MTLR_R11 0x7d6803a6 + +static inline bfd_byte * +build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset, + Elf_Internal_Rela *r) +{ + bfd_put_32 (obfd, LD_R11_0R3 + 0, p), p += 4; + bfd_put_32 (obfd, LD_R12_0R3 + 8, p), p += 4; + bfd_put_32 (obfd, MR_R0_R3, p), p += 4; + bfd_put_32 (obfd, CMPDI_R11_0, p), p += 4; + bfd_put_32 (obfd, ADD_R3_R12_R13, p), p += 4; + bfd_put_32 (obfd, BEQLR, p), p += 4; + bfd_put_32 (obfd, MR_R3_R0, p), p += 4; + bfd_put_32 (obfd, MFLR_R11, p), p += 4; + bfd_put_32 (obfd, STD_R11_0R1 + 32, p), p += 4; + + if (r != NULL) + r[0].r_offset += 9 * 4; + p = build_plt_stub (obfd, p, offset, r); + bfd_put_32 (obfd, BCTRL, p - 4); + + bfd_put_32 (obfd, LD_R11_0R1 + 32, p), p += 4; + bfd_put_32 (obfd, LD_R2_0R1 + 40, p), p += 4; + bfd_put_32 (obfd, MTLR_R11, p), p += 4; + bfd_put_32 (obfd, BLR, p), p += 4; + + return p; +} + static Elf_Internal_Rela * get_relocs (asection *sec, int count) { @@ -9227,7 +9355,13 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) r[0].r_offset += 2; r[0].r_addend = dest; } - p = build_plt_stub (htab->stub_bfd, loc, off, r); + if (stub_entry->h != NULL + && (stub_entry->h == htab->tls_get_addr_fd + || stub_entry->h == htab->tls_get_addr) + && !htab->no_tls_get_addr_opt) + p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r); + else + p = build_plt_stub (htab->stub_bfd, loc, off, r); size = p - loc; break; @@ -9316,6 +9450,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) size -= 4; if (PPC_HA (off + 16) != PPC_HA (off)) size += 4; + if (stub_entry->h != NULL + && (stub_entry->h == htab->tls_get_addr_fd + || stub_entry->h == htab->tls_get_addr) + && !htab->no_tls_get_addr_opt) + size += 13 * 4; if (info->emitrelocations) { stub_entry->stub_sec->reloc_count @@ -11255,8 +11394,16 @@ ppc64_elf_relocate_section (bfd *output_bfd, if (nop == NOP || nop == CROR_151515 || nop == CROR_313131) { - bfd_put_32 (input_bfd, LD_R2_40R1, - contents + rel->r_offset + 4); + if (h != NULL + && (h == htab->tls_get_addr_fd + || h == htab->tls_get_addr) + && !htab->no_tls_get_addr_opt) + { + /* Special stub used, leave nop alone. */ + } + else + bfd_put_32 (input_bfd, LD_R2_40R1, + contents + rel->r_offset + 4); can_plt_call = TRUE; } } diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h index 687b4a1bf0d..e5f71404124 100644 --- a/bfd/elf64-ppc.h +++ b/bfd/elf64-ppc.h @@ -24,7 +24,7 @@ void ppc64_elf_init_stub_bfd bfd_boolean ppc64_elf_edit_opd (bfd *, struct bfd_link_info *, bfd_boolean); asection *ppc64_elf_tls_setup - (bfd *, struct bfd_link_info *); +(bfd *, struct bfd_link_info *, int); bfd_boolean ppc64_elf_tls_optimize (bfd *, struct bfd_link_info *); bfd_boolean ppc64_elf_edit_toc diff --git a/binutils/ChangeLog b/binutils/ChangeLog index f03ccf0aea6..e049c1d5c22 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,8 @@ +2009-09-21 Alan Modra + + * readelf.c (get_ppc_dynamic_type): Add TLSOPT. + (get_ppc64_dynamic_type): Likewise. + 2009-09-18 Nick Clifton * po/es.po: Updated Spanish translation. diff --git a/binutils/readelf.c b/binutils/readelf.c index 64630f5f765..c20c84af0a9 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1470,7 +1470,8 @@ get_ppc_dynamic_type (unsigned long type) { switch (type) { - case DT_PPC_GOT: return "PPC_GOT"; + case DT_PPC_GOT: return "PPC_GOT"; + case DT_PPC_TLSOPT: return "PPC_TLSOPT"; default: return NULL; } @@ -1481,9 +1482,10 @@ get_ppc64_dynamic_type (unsigned long type) { switch (type) { - case DT_PPC64_GLINK: return "PPC64_GLINK"; - case DT_PPC64_OPD: return "PPC64_OPD"; - case DT_PPC64_OPDSZ: return "PPC64_OPDSZ"; + case DT_PPC64_GLINK: return "PPC64_GLINK"; + case DT_PPC64_OPD: return "PPC64_OPD"; + case DT_PPC64_OPDSZ: return "PPC64_OPDSZ"; + case DT_PPC64_TLSOPT: return "PPC64_TLSOPT"; default: return NULL; } diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index b7df2acafbe..a33fb843bf2 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,8 @@ +2009-09-21 Alan Modra + + * ppc.h (DT_PPC_TLSOPT): Define. + * ppc64.h (DT_PPC64_TLSOPT): Define. + 2009-08-10 Daniel Gutson * arm.h: (SHT_ARM_DEBUGOVERLAY): New define. diff --git a/include/elf/ppc.h b/include/elf/ppc.h index 14c643a549e..e2de0ad76f8 100644 --- a/include/elf/ppc.h +++ b/include/elf/ppc.h @@ -153,7 +153,10 @@ END_RELOC_NUMBERS (R_PPC_max) ((R) >= R_PPC_TLS && (R) <= R_PPC_GOT_DTPREL16_HA) /* Specify the value of _GLOBAL_OFFSET_TABLE_. */ -#define DT_PPC_GOT DT_LOPROC +#define DT_PPC_GOT (DT_LOPROC) + +/* Specify that tls descriptors should be optimized. */ +#define DT_PPC_TLSOPT (DT_LOPROC + 1) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/include/elf/ppc64.h b/include/elf/ppc64.h index da54f3f947d..04ddcd94c54 100644 --- a/include/elf/ppc64.h +++ b/include/elf/ppc64.h @@ -165,4 +165,7 @@ END_RELOC_NUMBERS (R_PPC64_max) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) +/* Specify that tls descriptors should be optimized. */ +#define DT_PPC64_TLSOPT (DT_LOPROC + 3) + #endif /* _ELF_PPC64_H */ diff --git a/ld/ChangeLog b/ld/ChangeLog index 5226599b1c0..9c16d6a6218 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,19 @@ +2009-09-21 Alan Modra + + * emultempl/ppc32elf.em (no_tls_get_addr_opt): New var. + (ppc_before_allocation): Pass to ppc_elf_tls_setup. + (OPTION_NO_TLS_GET_ADDR_OPT): Define. Redefine other options in + terms of previous option. + (PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add + --no-tls-get-addr-optimize. + (PARSE_AND_LIST_ARGS_CASES): Handle it. + * emultempl/ppc64elf.em (no_tls_get_addr_opt): New var. + (ppc_before_allocation): Pass to ppc64_elf_tls_setup. + (OPTION_NO_TLS_GET_ADDR_OPT): Define. + (PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add + --no-tls-get-addr-optimize. + (PARSE_AND_LIST_ARGS_CASES): Handle it. + 2009-09-18 Nick Clifton * po/es.po: Updated Spanish translation. diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em index c54f35ca5c3..2295ae90d19 100644 --- a/ld/emultempl/ppc32elf.em +++ b/ld/emultempl/ppc32elf.em @@ -33,6 +33,7 @@ fragment < +.*: 48 01 01 85 bl .*<__tls_get_addr_opt@plt> .*: 3c 62 00 00 addis r3,r2,0 .*: 38 63 90 1c addi r3,r3,-28644 .*: 3c 62 00 00 addis r3,r2,0 @@ -44,4 +44,4 @@ Disassembly of section \.got: .*: 4e 80 00 21 blrl .* <_GLOBAL_OFFSET_TABLE_>: -.*: 01 81 02 b4 00 00 00 00 00 00 00 00 .* +.*: 01 81 02 b8 00 00 00 00 00 00 00 00 .* diff --git a/ld/testsuite/ld-powerpc/tlsexe32.g b/ld/testsuite/ld-powerpc/tlsexe32.g index 14b7f8cff5a..c2023a8c6b4 100644 --- a/ld/testsuite/ld-powerpc/tlsexe32.g +++ b/ld/testsuite/ld-powerpc/tlsexe32.g @@ -8,4 +8,4 @@ Contents of section \.got: .* 00000000 00000000 00000000 4e800021 .* -.* 018102b4 00000000 00000000 .* +.* 018102b8 00000000 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlsexe32.r b/ld/testsuite/ld-powerpc/tlsexe32.r index 86a0ab8683b..f2c1a4528a7 100644 --- a/ld/testsuite/ld-powerpc/tlsexe32.r +++ b/ld/testsuite/ld-powerpc/tlsexe32.r @@ -57,16 +57,16 @@ Relocation section '\.rela\.dyn' at offset .* contains 2 entries: Relocation section '\.rela\.plt' at offset .* contains 1 entries: Offset +Info +Type +Sym\. Value +Symbol's Name \+ Addend -[0-9a-f ]+R_PPC_JMP_SLOT[0-9a-f ]+__tls_get_addr \+ 0 +[0-9a-f ]+R_PPC_JMP_SLOT[0-9a-f ]+__tls_get_addr_opt \+ 0 Symbol table '\.dynsym' contains [0-9]+ entries: +Num: +Value +Size Type +Bind +Vis +Ndx Name .* NOTYPE +LOCAL +DEFAULT +UND .* TLS +GLOBAL DEFAULT +UND gd -.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr .* TLS +GLOBAL DEFAULT +UND ld .* NOTYPE +GLOBAL DEFAULT +ABS __end .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start +.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt .* NOTYPE +GLOBAL DEFAULT +ABS _edata .* NOTYPE +GLOBAL DEFAULT +ABS _end @@ -96,7 +96,6 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* OBJECT +LOCAL +HIDDEN +11 _GLOBAL_OFFSET_TABLE_ .* TLS +GLOBAL DEFAULT +UND gd .* TLS +GLOBAL DEFAULT +9 le0 -.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr .* TLS +GLOBAL DEFAULT +9 ld0 .* TLS +GLOBAL DEFAULT +9 le1 .* TLS +GLOBAL DEFAULT +UND ld @@ -105,6 +104,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +GLOBAL DEFAULT +9 ld2 .* TLS +GLOBAL DEFAULT +9 ld1 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start +.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt .* NOTYPE +GLOBAL DEFAULT +ABS _edata .* NOTYPE +GLOBAL DEFAULT +ABS _end .* TLS +GLOBAL DEFAULT +9 gd0 diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.d b/ld/testsuite/ld-powerpc/tlsexetoc.d index d6a0388813e..83b1aca960f 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.d +++ b/ld/testsuite/ld-powerpc/tlsexetoc.d @@ -8,21 +8,34 @@ Disassembly of section \.text: -.* <_start-0x18>: +.* <_start-0x4c>: +.* e9 63 00 00 ld r11,0\(r3\) +.* e9 83 00 08 ld r12,8\(r3\) +.* 7c 60 1b 78 mr r0,r3 +.* 2c 2b 00 00 cmpdi r11,0 +.* 7c 6c 6a 14 add r3,r12,r13 +.* 4d 82 00 20 beqlr +.* 7c 03 03 78 mr r3,r0 +.* 7d 68 02 a6 mflr r11 +.* f9 61 00 20 std r11,32\(r1\) .* f8 41 00 28 std r2,40\(r1\) .* e9 62 80 70 ld r11,-32656\(r2\) .* 7d 69 03 a6 mtctr r11 .* e9 62 80 80 ld r11,-32640\(r2\) .* e8 42 80 78 ld r2,-32648\(r2\) -.* 4e 80 04 20 bctr +.* 4e 80 04 21 bctrl +.* e9 61 00 20 ld r11,32\(r1\) +.* e8 41 00 28 ld r2,40\(r1\) +.* 7d 68 03 a6 mtlr r11 +.* 4e 80 00 20 blr .* <_start>: .* 38 62 80 08 addi r3,r2,-32760 -.* 4b ff ff e5 bl .* -.* e8 41 00 28 ld r2,40\(r1\) +.* 4b ff ff b1 bl .* +.* 60 00 00 00 nop .* 38 62 80 18 addi r3,r2,-32744 -.* 4b ff ff d9 bl .* -.* e8 41 00 28 ld r2,40\(r1\) +.* 4b ff ff a5 bl .* +.* 60 00 00 00 nop .* 3c 6d 00 00 addis r3,r13,0 .* 60 00 00 00 nop .* 38 63 90 38 addi r3,r3,-28616 @@ -39,8 +52,9 @@ Disassembly of section \.text: .* 89 4d 90 60 lbz r10,-28576\(r13\) .* 3d 2d 00 00 addis r9,r13,0 .* 99 49 90 68 stb r10,-28568\(r9\) +.* 60 00 00 00 nop .* 00 00 00 00 .* -.* 00 01 02 18 .* +.* 00 01 02 28 .* .* 7d 88 02 a6 mflr r12 .* 42 9f 00 05 bcl- 20,4\*cr7\+so,.* .* 7d 68 02 a6 mflr r11 diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.g b/ld/testsuite/ld-powerpc/tlsexetoc.g index df3994ceb0f..387e9cddca0 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.g +++ b/ld/testsuite/ld-powerpc/tlsexetoc.g @@ -7,7 +7,7 @@ .*: +file format elf64-powerpc Contents of section \.got: -.* 00000000 10018568 00000000 00000000 .* +.* 00000000 100185b0 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000001 .* .* 00000000 00000000 00000000 00000001 .* diff --git a/ld/testsuite/ld-powerpc/tlsexetoc.r b/ld/testsuite/ld-powerpc/tlsexetoc.r index e16bbf481e2..d1f75dfc6ff 100644 --- a/ld/testsuite/ld-powerpc/tlsexetoc.r +++ b/ld/testsuite/ld-powerpc/tlsexetoc.r @@ -16,10 +16,10 @@ Section Headers: +\[[ 0-9]+\] \.dynstr +.* +\[[ 0-9]+\] \.rela\.dyn +.* +\[[ 0-9]+\] \.rela\.plt +.* - +\[[ 0-9]+\] \.text +PROGBITS .* 0+b8 0+ +AX +0 +0 +8 + +\[[ 0-9]+\] \.text +PROGBITS .* 0+f0 0+ +AX +0 +0 +8 +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8 +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8 - +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+150 10 +WA +4 +0 +8 + +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8 +\[[ 0-9]+\] \.branch_lt +PROGBITS .* 0+ 0+ +WA +0 +0 +8 +\[[ 0-9]+\] \.got +PROGBITS .* 0+58 08 +WA +0 +0 +8 +\[[ 0-9]+\] \.plt +.* @@ -59,15 +59,15 @@ Relocation section '\.rela\.dyn' at offset .* contains 3 entries: Relocation section '\.rela\.plt' at offset .* contains 1 entries: +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend -[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr \+ 0 +[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr_opt \+ 0 Symbol table '\.dynsym' contains [0-9]+ entries: +Num: +Value +Size Type +Bind +Vis +Ndx Name .* NOTYPE +LOCAL +DEFAULT +UND .* TLS +GLOBAL DEFAULT +UND gd -.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr .* TLS +GLOBAL DEFAULT +UND ld .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start +.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt .* NOTYPE +GLOBAL DEFAULT +ABS _edata .* NOTYPE +GLOBAL DEFAULT +ABS _end @@ -96,10 +96,9 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +LOCAL +DEFAULT +8 le5 .* NOTYPE +LOCAL +DEFAULT +12 \.Lie0 .* OBJECT +LOCAL +HIDDEN +10 _DYNAMIC -.* FUNC +LOCAL +DEFAULT +UND \.__tls_get_addr +.* (FUNC|NOTYPE) +LOCAL +DEFAULT +UND \.__tls_get_addr(|_opt) .* TLS +GLOBAL DEFAULT +UND gd .* TLS +GLOBAL DEFAULT +9 le0 -.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr .* TLS +GLOBAL DEFAULT +9 ld0 .* TLS +GLOBAL DEFAULT +9 le1 .* TLS +GLOBAL DEFAULT +UND ld @@ -107,6 +106,7 @@ Symbol table '\.symtab' contains [0-9]+ entries: .* TLS +GLOBAL DEFAULT +9 ld2 .* TLS +GLOBAL DEFAULT +9 ld1 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start +.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt .* NOTYPE +GLOBAL DEFAULT +ABS _edata .* NOTYPE +GLOBAL DEFAULT +ABS _end .* TLS +GLOBAL DEFAULT +9 gd0 diff --git a/ld/testsuite/ld-powerpc/tlslib.s b/ld/testsuite/ld-powerpc/tlslib.s index 08f27a27f2b..59c40d20899 100644 --- a/ld/testsuite/ld-powerpc/tlslib.s +++ b/ld/testsuite/ld-powerpc/tlslib.s @@ -1,10 +1,12 @@ - .global .__tls_get_addr,__tls_get_addr,gd,ld - .type .__tls_get_addr,@function + .global __tls_get_addr,__tls_get_addr_opt,gd,ld + .type __tls_get_addr,@function + .type __tls_get_addr_opt,@function .section ".opd","aw",@progbits __tls_get_addr: +__tls_get_addr_opt: .align 3 - .quad .__tls_get_addr + .quad .L.__tls_get_addr .quad .TOC.@tocbase .quad 0 @@ -17,5 +19,6 @@ gd: .space 8 ld: .long 0xc0ffee .text -.__tls_get_addr: +.L.__tls_get_addr: blr + .size __tls_get_addr,. - .L.__tls_get_addr diff --git a/ld/testsuite/ld-powerpc/tlslib32.s b/ld/testsuite/ld-powerpc/tlslib32.s index 98cd3e9175e..14dc9668637 100644 --- a/ld/testsuite/ld-powerpc/tlslib32.s +++ b/ld/testsuite/ld-powerpc/tlslib32.s @@ -1,5 +1,6 @@ - .global __tls_get_addr,gd,ld + .global __tls_get_addr,__tls_get_addr_opt,gd,ld .type __tls_get_addr,@function + .type __tls_get_addr_opt,@function .section ".tbss","awT",@nobits .align 2 @@ -11,4 +12,5 @@ ld: .long 0xc0ffee .text __tls_get_addr: +__tls_get_addr_opt: blr -- 2.30.2