diff options
author | Alan Modra <amodra@gmail.com> | 2009-09-21 11:51:02 +0000 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2009-09-21 11:51:02 +0000 |
commit | a7f2871e66570d025ce909c16bd53be5ff814191 (patch) | |
tree | dad2750ab64db9b81da21b0f7fb646de7b1bad85 /bfd/elf32-ppc.c | |
parent | e0d602ecffb0256181ea45c653d261973c819d2b (diff) | |
download | gdb-a7f2871e66570d025ce909c16bd53be5ff814191.zip gdb-a7f2871e66570d025ce909c16bd53be5ff814191.tar.gz gdb-a7f2871e66570d025ce909c16bd53be5ff814191.tar.bz2 |
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.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 111 |
1 files changed, 101 insertions, 10 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index bbe94db..95058a2 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. */ |