aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-ppc.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2009-09-21 11:51:02 +0000
committerAlan Modra <amodra@gmail.com>2009-09-21 11:51:02 +0000
commita7f2871e66570d025ce909c16bd53be5ff814191 (patch)
treedad2750ab64db9b81da21b0f7fb646de7b1bad85 /bfd/elf32-ppc.c
parente0d602ecffb0256181ea45c653d261973c819d2b (diff)
downloadgdb-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.c111
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. */