X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=2b457d6d9bfe43e6a89151c7121fa4a1c0c4d254;hb=cf35638d431e230d51d54550e8a249e730264ea5;hp=542928d4d4254862c2c0caac443a35f4b0371a2a;hpb=91e21fb75f551371192d1138db38b0ee73d59b71;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 542928d4d4..2b457d6d9b 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -1,6 +1,6 @@ /* PowerPC-specific support for 32-bit ELF Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -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 @@ -1300,7 +1308,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_EMB_SDAI16", /* name */ FALSE, /* partial_inplace */ @@ -1317,7 +1325,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield, /* complain_on_overflow */ + complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_PPC_EMB_SDA2I16", /* name */ FALSE, /* partial_inplace */ @@ -1372,7 +1380,7 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ - TRUE, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ @@ -1788,7 +1796,7 @@ struct ppc_elf_obj_tdata #define is_ppc_elf(bfd) \ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ - && elf_object_id (bfd) == PPC32_ELF_TDATA) + && elf_object_id (bfd) == PPC32_ELF_DATA) /* Override the generic function because we store some extras. */ @@ -1796,7 +1804,7 @@ static bfd_boolean ppc_elf_mkobject (bfd *abfd) { return bfd_elf_allocate_object (abfd, sizeof (struct ppc_elf_obj_tdata), - PPC32_ELF_TDATA); + PPC32_ELF_DATA); } /* Fix bad default arch selected for a 32 bit input bfd when the @@ -1850,7 +1858,7 @@ ppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); /* pr_reg */ offset = 72; @@ -1986,9 +1994,6 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *shdr, asection *asect) { - if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE) - shdr->sh_flags |= SHF_EXCLUDE; - if ((asect->flags & SEC_SORT_ENTRIES) != 0) shdr->sh_type = SHT_ORDERED; @@ -2069,12 +2074,13 @@ typedef struct apuinfo_list apuinfo_list; static apuinfo_list *head; - +static bfd_boolean apuinfo_set; static void apuinfo_list_init (void) { head = NULL; + apuinfo_set = FALSE; } static void @@ -2151,123 +2157,93 @@ ppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) { bfd *ibfd; asection *asec; - char *buffer; - unsigned num_input_sections; - bfd_size_type output_section_size; + char *buffer = NULL; + bfd_size_type largest_input_size = 0; unsigned i; - unsigned num_entries; - unsigned long offset; unsigned long length; const char *error_message = NULL; if (link_info == NULL) return; - /* Scan the input bfds, looking for apuinfo sections. */ - num_input_sections = 0; - output_section_size = 0; - - for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) - { - asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); - if (asec) - { - ++ num_input_sections; - output_section_size += asec->size; - } - } - - /* We need at least one input sections - in order to make merging worthwhile. */ - if (num_input_sections < 1) - return; - - /* Just make sure that the output section exists as well. */ - asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); - if (asec == NULL) - return; - - /* Allocate a buffer for the contents of the input sections. */ - buffer = bfd_malloc (output_section_size); - if (buffer == NULL) - return; - - offset = 0; apuinfo_list_init (); /* Read in the input sections contents. */ for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) { unsigned long datum; - char *ptr; asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); if (asec == NULL) continue; + error_message = _("corrupt %s section in %B"); length = asec->size; - if (length < 24) + if (length < 20) + goto fail; + + apuinfo_set = TRUE; + if (largest_input_size < asec->size) { - error_message = _("corrupt or empty %s section in %B"); - goto fail; + if (buffer) + free (buffer); + largest_input_size = asec->size; + buffer = bfd_malloc (largest_input_size); + if (!buffer) + return; } if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 - || (bfd_bread (buffer + offset, length, ibfd) != length)) + || (bfd_bread (buffer, length, ibfd) != length)) { error_message = _("unable to read in %s section from %B"); goto fail; } - /* Process the contents of the section. */ - ptr = buffer + offset; - error_message = _("corrupt %s section in %B"); - /* Verify the contents of the header. Note - we have to extract the values this way in order to allow for a host whose endian-ness is different from the target. */ - datum = bfd_get_32 (ibfd, ptr); + datum = bfd_get_32 (ibfd, buffer); if (datum != sizeof APUINFO_LABEL) goto fail; - datum = bfd_get_32 (ibfd, ptr + 8); + datum = bfd_get_32 (ibfd, buffer + 8); if (datum != 0x2) goto fail; - if (strcmp (ptr + 12, APUINFO_LABEL) != 0) + if (strcmp (buffer + 12, APUINFO_LABEL) != 0) goto fail; /* Get the number of bytes used for apuinfo entries. */ - datum = bfd_get_32 (ibfd, ptr + 4); + datum = bfd_get_32 (ibfd, buffer + 4); if (datum + 20 != length) goto fail; - /* Make sure that we do not run off the end of the section. */ - if (offset + length > output_section_size) - goto fail; - /* Scan the apuinfo section, building a list of apuinfo numbers. */ for (i = 0; i < datum; i += 4) - apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + i)); - - /* Update the offset. */ - offset += length; + apuinfo_list_add (bfd_get_32 (ibfd, buffer + 20 + i)); } error_message = NULL; - /* Compute the size of the output section. */ - num_entries = apuinfo_list_length (); - output_section_size = 20 + num_entries * 4; + if (apuinfo_set) + { + /* Compute the size of the output section. */ + unsigned num_entries = apuinfo_list_length (); - asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + /* Set the output section size, if it exists. */ + asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); - if (! bfd_set_section_size (abfd, asec, output_section_size)) - ibfd = abfd, - error_message = _("warning: unable to set size of %s section in %B"); + if (asec && ! bfd_set_section_size (abfd, asec, 20 + num_entries * 4)) + { + ibfd = abfd; + error_message = _("warning: unable to set size of %s section in %B"); + } + } fail: - free (buffer); + if (buffer) + free (buffer); if (error_message) (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME); @@ -2282,8 +2258,7 @@ ppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED, asection *asec, bfd_byte *contents ATTRIBUTE_UNUSED) { - return (apuinfo_list_length () - && strcmp (asec->name, APUINFO_SECTION_NAME) == 0); + return apuinfo_set && strcmp (asec->name, APUINFO_SECTION_NAME) == 0; } /* Finally we can generate the output section. */ @@ -2301,7 +2276,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) if (asec == NULL) return; - if (apuinfo_list_length () == 0) + if (!apuinfo_set) return; length = asec->size; @@ -2733,7 +2708,7 @@ struct ppc_elf_link_hash_table /* The bfd that forced an old-style PLT. */ bfd *old_bfd; - + /* TLS local dynamic got entry handling. */ union { bfd_signed_vma refcount; @@ -2754,6 +2729,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; @@ -2768,10 +2746,20 @@ struct ppc_elf_link_hash_table struct sym_cache sym_cache; }; +/* Rename some of the generic section flags to better document how they + are used here. */ + +/* Nonzero if this section has TLS related relocations. */ +#define has_tls_reloc sec_flg0 + +/* Nonzero if this section has a call to __tls_get_addr. */ +#define has_tls_get_addr_call sec_flg1 + /* Get the PPC ELF linker hash table from a link_info structure. */ #define ppc_elf_hash_table(p) \ - ((struct ppc_elf_link_hash_table *) (p)->hash) + (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ + == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL) /* Create an entry in a PPC ELF linker hash table. */ @@ -2815,7 +2803,8 @@ ppc_elf_link_hash_table_create (bfd *abfd) if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, ppc_elf_link_hash_newfunc, - sizeof (struct ppc_elf_link_hash_entry))) + sizeof (struct ppc_elf_link_hash_entry), + PPC32_ELF_DATA)) { free (ret); return NULL; @@ -3122,16 +3111,18 @@ ppc_elf_add_symbol_hook (bfd *abfd, *valp = sym->st_size; } - if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + if ((abfd->flags & DYNAMIC) == 0 + && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE; return TRUE; } static bfd_boolean -create_sdata_sym (struct ppc_elf_link_hash_table *htab, - elf_linker_section_t *lsect) +create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect) { + struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); + lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name, TRUE, FALSE, TRUE); if (lsect->sym == NULL) @@ -3139,6 +3130,7 @@ create_sdata_sym (struct ppc_elf_link_hash_table *htab, if (lsect->sym->root.type == bfd_link_hash_new) lsect->sym->non_elf = 0; lsect->sym->ref_regular = 1; + _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE); return TRUE; } @@ -3168,7 +3160,7 @@ ppc_elf_create_linker_section (bfd *abfd, return FALSE; lsect->section = s; - return create_sdata_sym (htab, lsect); + return create_sdata_sym (info, lsect); } /* Find a linker generated pointer with a given addend and type. */ @@ -3310,6 +3302,8 @@ update_plt_info (bfd *abfd, struct plt_entry **plist, { struct plt_entry *ent; + if (addend < 32768) + sec = NULL; for (ent = *plist; ent != NULL; ent = ent->next) if (ent->sec == sec && ent->addend == addend) break; @@ -3430,7 +3424,6 @@ ppc_elf_check_relocs (bfd *abfd, enum elf_ppc_reloc_type r_type; struct elf_link_hash_entry *h; int tls_type; - struct plt_entry **ifunc; r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -3458,47 +3451,38 @@ ppc_elf_check_relocs (bfd *abfd, } tls_type = 0; - ifunc = NULL; r_type = ELF32_R_TYPE (rel->r_info); - if (!htab->is_vxworks) + if (h == NULL && !htab->is_vxworks) { - if (h != NULL) - { - if (h->type == STT_GNU_IFUNC) - ifunc = &h->plt.plist; - } - else + Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + if (isym == NULL) + return FALSE; + + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC + && (!info->shared + || is_branch_reloc (r_type))) { - Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache, - abfd, r_symndx); - if (isym == NULL) + struct plt_entry **ifunc; + bfd_vma addend; + + ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, + PLT_IFUNC); + if (ifunc == NULL) return FALSE; - if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC - && (!info->shared - || is_branch_reloc (r_type))) + /* STT_GNU_IFUNC symbols must have a PLT entry; + In a non-pie executable even when there are + no plt calls. */ + addend = 0; + if (r_type == R_PPC_PLTREL24) { - bfd_vma addend; - - ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, - PLT_IFUNC); - if (ifunc == NULL) - return FALSE; - - /* STT_GNU_IFUNC symbols must have a PLT entry; - In a non-pie executable even when there are - no plt calls. */ - addend = 0; - if (r_type == R_PPC_PLTREL24) - { - ppc_elf_tdata (abfd)->makes_plt_call = 1; - if (info->shared) - addend = rel->r_addend; - } - if (!update_plt_info (abfd, ifunc, - addend < 32768 ? NULL : got2, addend)) - return FALSE; + ppc_elf_tdata (abfd)->makes_plt_call = 1; + if (info->shared) + addend = rel->r_addend; } + if (!update_plt_info (abfd, ifunc, got2, addend)) + return FALSE; } } @@ -3633,13 +3617,8 @@ ppc_elf_check_relocs (bfd *abfd, break; case R_PPC_SDAREL16: - if (info->shared) - { - bad_shared_reloc (abfd, r_type); - return FALSE; - } if (htab->sdata[0].sym == NULL - && !create_sdata_sym (htab, &htab->sdata[0])) + && !create_sdata_sym (info, &htab->sdata[0])) return FALSE; if (h != NULL) { @@ -3655,7 +3634,7 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; } if (htab->sdata[1].sym == NULL - && !create_sdata_sym (htab, &htab->sdata[1])) + && !create_sdata_sym (info, &htab->sdata[1])) return FALSE; if (h != NULL) { @@ -3672,10 +3651,10 @@ ppc_elf_check_relocs (bfd *abfd, return FALSE; } if (htab->sdata[0].sym == NULL - && !create_sdata_sym (htab, &htab->sdata[0])) + && !create_sdata_sym (info, &htab->sdata[0])) return FALSE; if (htab->sdata[1].sym == NULL - && !create_sdata_sym (htab, &htab->sdata[1])) + && !create_sdata_sym (info, &htab->sdata[1])) return FALSE; if (h != NULL) { @@ -3740,8 +3719,7 @@ ppc_elf_check_relocs (bfd *abfd, addend = rel->r_addend; } h->needs_plt = 1; - if (!update_plt_info (abfd, &h->plt.plist, - addend < 32768 ? NULL : got2, addend)) + if (!update_plt_info (abfd, &h->plt.plist, got2, addend)) return FALSE; } break; @@ -3772,10 +3750,9 @@ ppc_elf_check_relocs (bfd *abfd, case R_PPC_EMB_MRKREF: case R_PPC_NONE: case R_PPC_max: - case R_PPC_RELAX32: - case R_PPC_RELAX32PC: - case R_PPC_RELAX32_PLT: - case R_PPC_RELAX32PC_PLT: + case R_PPC_RELAX: + case R_PPC_RELAX_PLT: + case R_PPC_RELAX_PLTREL24: break; /* These should only appear in dynamic objects. */ @@ -3953,7 +3930,7 @@ ppc_elf_check_relocs (bfd *abfd, || !h->def_regular))) { struct ppc_elf_dyn_relocs *p; - struct ppc_elf_dyn_relocs **head; + struct ppc_elf_dyn_relocs **rel_head; #ifdef DEBUG fprintf (stderr, @@ -3978,7 +3955,7 @@ ppc_elf_check_relocs (bfd *abfd, relocations we need for this symbol. */ if (h != NULL) { - head = &ppc_elf_hash_entry (h)->dyn_relocs; + rel_head = &ppc_elf_hash_entry (h)->dyn_relocs; } else { @@ -3999,17 +3976,17 @@ ppc_elf_check_relocs (bfd *abfd, s = sec; vpp = &elf_section_data (s)->local_dynrel; - head = (struct ppc_elf_dyn_relocs **) vpp; + rel_head = (struct ppc_elf_dyn_relocs **) vpp; } - p = *head; + p = *rel_head; if (p == NULL || p->sec != sec) { p = bfd_alloc (htab->elf.dynobj, sizeof *p); if (p == NULL) return FALSE; - p->next = *head; - *head = p; + p->next = *rel_head; + *rel_head = p; p->sec = sec; p->count = 0; p->pc_count = 0; @@ -4067,15 +4044,15 @@ ppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd); else if (out_attr->i == 1 && in_attr->i == 3) _bfd_error_handler - (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), + (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), obfd, ibfd); else if (out_attr->i == 3 && in_attr->i == 1) _bfd_error_handler - (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), + (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"), ibfd, obfd); else if (out_attr->i == 3 && in_attr->i == 2) _bfd_error_handler - (_("Warning: %B uses soft float, %B uses single-precision hard float"), + (_("Warning: %B uses soft float, %B uses single-precision hard float"), ibfd, obfd); else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3)) _bfd_error_handler @@ -4280,6 +4257,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) @@ -4313,8 +4292,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) @@ -4478,7 +4455,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, struct plt_entry *ent; ent = find_plt_ent (&h->plt.plist, NULL, 0); - if (ent->plt.refcount > 0) + if (ent != NULL && ent->plt.refcount > 0) ent->plt.refcount -= 1; } } @@ -4526,7 +4503,7 @@ ppc_elf_gc_sweep_hook (bfd *abfd, if (r_type == R_PPC_PLTREL24 && info->shared) addend = rel->r_addend; ent = find_plt_ent (&h->plt.plist, got2, addend); - if (ent->plt.refcount > 0) + if (ent != NULL && ent->plt.refcount > 0) ent->plt.refcount -= 1; } break; @@ -4542,11 +4519,63 @@ 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; + for (ent = tga->plt.plist; ent != NULL; ent = ent->next) + if (ent->plt.refcount > 0) + break; + if (ent != NULL) + { + 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) @@ -4555,8 +4584,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); } @@ -4612,6 +4639,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, { Elf_Internal_Sym *locsyms = NULL; Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd); + asection *got2 = bfd_get_section_by_name (ibfd, ".got2"); for (sec = ibfd->sections; sec != NULL; sec = sec->next) if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) @@ -4705,6 +4733,13 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, else continue; + case R_PPC_TLSGD: + case R_PPC_TLSLD: + expecting_tls_get_addr = 2; + tls_set = 0; + tls_clear = 0; + break; + default: continue; } @@ -4712,7 +4747,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, if (pass == 0) { if (!expecting_tls_get_addr - || !sec->has_tls_get_addr_call) + || (expecting_tls_get_addr == 1 + && !sec->has_tls_get_addr_call)) continue; if (rel + 1 < relend @@ -4728,6 +4764,23 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, break; } + if (expecting_tls_get_addr) + { + struct plt_entry *ent; + bfd_vma addend = 0; + + if (info->shared + && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24) + addend = rel[1].r_addend; + ent = find_plt_ent (&htab->tls_get_addr->plt.plist, + got2, addend); + if (ent != NULL && ent->plt.refcount > 0) + ent->plt.refcount -= 1; + + if (expecting_tls_get_addr == 2) + continue; + } + if (h != NULL) { tls_mask = &ppc_elf_hash_entry (h)->tls_mask; @@ -4735,7 +4788,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, } else { - Elf_Internal_Sym *sym; bfd_signed_vma *lgot_refs; struct plt_entry **local_plt; char *lgot_masks; @@ -4754,7 +4806,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, return FALSE; } } - sym = locsyms + r_symndx; lgot_refs = elf_local_got_refcounts (ibfd); if (lgot_refs == NULL) abort (); @@ -4772,16 +4823,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, *got_count -= 1; } - if (expecting_tls_get_addr) - { - struct plt_entry *ent; - - ent = find_plt_ent (&htab->tls_get_addr->plt.plist, - NULL, 0); - if (ent != NULL && ent->plt.refcount > 0) - ent->plt.refcount -= 1; - } - *tls_mask |= tls_set; *tls_mask &= ~tls_clear; } @@ -5147,6 +5188,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 @@ -5183,7 +5227,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* If this symbol is not defined in a regular file, and we are not generating a shared - library, then set the symbol to this location + library, then set the symbol to this location in the .plt. This is to avoid text relocations, and is required to make function pointers compare as equal between @@ -5559,6 +5603,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, local_plt = (struct plt_entry **) end_local_got; end_local_plt = local_plt + locsymcount; lgot_masks = (char *) end_local_plt; + for (; local_got < end_local_got; ++local_got, ++lgot_masks) if (*local_got > 0) { @@ -5602,7 +5647,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, for (ent = *local_plt; ent != NULL; ent = ent->next) if (ent->plt.refcount > 0) { - asection *s = htab->iplt; + s = htab->iplt; if (!doneone) { @@ -5660,6 +5705,18 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, htab->elf.hgot->root.u.def.value = g_o_t; } + if (info->shared) + { + struct elf_link_hash_entry *sda = htab->sdata[0].sym; + if (sda != NULL + && !(sda->root.type == bfd_link_hash_defined + || sda->root.type == bfd_link_hash_defweak)) + { + sda->root.type = bfd_link_hash_defined; + sda->root.u.def.section = htab->elf.hgot->root.u.def.section; + sda->root.u.def.value = htab->elf.hgot->root.u.def.value; + } + } if (htab->glink != NULL && htab->glink->size != 0 @@ -5811,6 +5868,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) @@ -5857,23 +5919,25 @@ ppc_elf_hash_symbol (struct elf_link_hash_entry *h) #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) +/* Relaxation trampolines. r12 is available for clobbering (r11, is + used for some functions that are allowed to break the ABI). */ static const int shared_stub_entry[] = { 0x7c0802a6, /* mflr 0 */ 0x429f0005, /* bcl 20, 31, .Lxxx */ - 0x7d6802a6, /* mflr 11 */ - 0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */ - 0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */ + 0x7d8802a6, /* mflr 12 */ + 0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */ + 0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */ 0x7c0803a6, /* mtlr 0 */ - 0x7d6903a6, /* mtctr 11 */ + 0x7d8903a6, /* mtctr 12 */ 0x4e800420, /* bctr */ }; static const int stub_entry[] = { - 0x3d600000, /* lis 11,xxx@ha */ - 0x396b0000, /* addi 11,11,xxx@l */ - 0x7d6903a6, /* mtctr 11 */ + 0x3d800000, /* lis 12,xxx@ha */ + 0x398c0000, /* addi 12,12,xxx@l */ + 0x7d8903a6, /* mtctr 12 */ 0x4e800420, /* bctr */ }; @@ -5887,6 +5951,8 @@ ppc_elf_relax_section (bfd *abfd, { struct one_fixup *next; asection *tsec; + /* Final link, can use the symbol offset. For a + relocatable link we use the symbol's index. */ bfd_vma toff; bfd_vma trampoff; }; @@ -5901,12 +5967,14 @@ ppc_elf_relax_section (bfd *abfd, struct ppc_elf_link_hash_table *htab; bfd_size_type trampoff; asection *got2; + bfd_boolean maybe_pasted; *again = FALSE; /* Nothing to do if there are no relocations, and no need to do - anything with non-alloc sections. */ + anything with non-alloc or non-code sections. */ if ((isec->flags & SEC_ALLOC) == 0 + || (isec->flags & SEC_CODE) == 0 || (isec->flags & SEC_RELOC) == 0 || isec->reloc_count == 0) return TRUE; @@ -5916,10 +5984,13 @@ ppc_elf_relax_section (bfd *abfd, anyway. */ if (link_info->relocatable && link_info->shared) return TRUE; - + trampoff = (isec->size + 3) & (bfd_vma) -4; + maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0 + || strcmp (isec->output_section->name, ".fini") == 0); /* Space for a branch around any trampolines. */ - trampoff += 4; + if (maybe_pasted) + trampoff += 4; symtab_hdr = &elf_symtab_hdr (abfd); @@ -5936,7 +6007,7 @@ ppc_elf_relax_section (bfd *abfd, for (irel = internal_relocs; irel < irelend; irel++) { unsigned long r_type = ELF32_R_TYPE (irel->r_info); - bfd_vma symaddr, reladdr, toff, roff; + bfd_vma toff, roff; asection *tsec; struct one_fixup *f; size_t insn_offset = 0; @@ -6018,7 +6089,7 @@ ppc_elf_relax_section (bfd *abfd, || h->root.type == bfd_link_hash_undefweak) { tsec = bfd_und_section_ptr; - toff = 0; + toff = link_info->relocatable ? indx : 0; } else continue; @@ -6119,19 +6190,22 @@ ppc_elf_relax_section (bfd *abfd, if (tsec->output_section == NULL) continue; - symaddr = tsec->output_section->vma + tsec->output_offset + toff; - roff = irel->r_offset; - reladdr = isec->output_section->vma + isec->output_offset + roff; /* If the branch is in range, no need to do anything. */ if (tsec != bfd_und_section_ptr && (!link_info->relocatable /* A relocatable link may have sections moved during final link, so do not presume they remain in range. */ - || tsec->output_section == isec->output_section) - && symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) - continue; + || tsec->output_section == isec->output_section)) + { + bfd_vma symaddr, reladdr; + + symaddr = tsec->output_section->vma + tsec->output_offset + toff; + reladdr = isec->output_section->vma + isec->output_offset + roff; + if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) + continue; + } /* Look for an existing fixup to this address. */ for (f = fixups; f ; f = f->next) @@ -6153,28 +6227,28 @@ ppc_elf_relax_section (bfd *abfd, { size = 4 * ARRAY_SIZE (shared_stub_entry); insn_offset = 12; - stub_rtype = R_PPC_RELAX32PC; } else { size = 4 * ARRAY_SIZE (stub_entry); insn_offset = 0; - stub_rtype = R_PPC_RELAX32; } - - if (R_PPC_RELAX32_PLT - R_PPC_RELAX32 - != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC) - abort (); + stub_rtype = R_PPC_RELAX; if (tsec == htab->plt || tsec == htab->glink) - stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32; + { + stub_rtype = R_PPC_RELAX_PLT; + if (r_type == R_PPC_PLTREL24) + stub_rtype = R_PPC_RELAX_PLTREL24; + } /* Hijack the old relocation. Since we need two relocations for this use a "composite" reloc. */ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), stub_rtype); irel->r_offset = trampoff + insn_offset; - if (r_type == R_PPC_PLTREL24) + if (r_type == R_PPC_PLTREL24 + && stub_rtype != R_PPC_RELAX_PLTREL24) irel->r_addend = 0; /* Record the fixup so we don't do it again this section. */ @@ -6241,7 +6315,6 @@ ppc_elf_relax_section (bfd *abfd, { const int *stub; bfd_byte *dest; - bfd_vma val; int i, size; do @@ -6257,12 +6330,15 @@ ppc_elf_relax_section (bfd *abfd, goto error_return; isec->size = (isec->size + 3) & (bfd_vma) -4; - /* Branch around the trampolines. */ - val = B + trampoff - isec->size; dest = contents + isec->size; + /* Branch around the trampolines. */ + if (maybe_pasted) + { + bfd_vma val = B + trampoff - isec->size; + bfd_put_32 (abfd, val, dest); + dest += 4; + } isec->size = trampoff; - bfd_put_32 (abfd, val, dest); - dest += 4; if (link_info->shared) { @@ -6318,7 +6394,7 @@ ppc_elf_relax_section (bfd *abfd, Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count) * sizeof (*new_relocs)); unsigned ix; - + if (!new_relocs) goto error_return; memcpy (new_relocs, internal_relocs, @@ -6344,7 +6420,7 @@ ppc_elf_relax_section (bfd *abfd, { /* Convert the internal relax relocs to external form. */ for (irel = internal_relocs; irel < irelend; irel++) - if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX32) + if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX) { unsigned long r_symndx = ELF32_R_SYM (irel->r_info); @@ -6360,7 +6436,7 @@ ppc_elf_relax_section (bfd *abfd, irel++; } } - + return TRUE; error_return: @@ -6437,9 +6513,10 @@ elf_finish_pointer_linker_section (bfd *input_bfd, linker_section_ptr->offset += 1; } - relocation = (lsect->section->output_offset + relocation = (lsect->section->output_section->vma + + lsect->section->output_offset + linker_section_ptr->offset - 1 - - 0x8000); + - SYM_VAL (lsect->sym)); #ifdef DEBUG fprintf (stderr, @@ -6447,9 +6524,7 @@ elf_finish_pointer_linker_section (bfd *input_bfd, lsect->name, (long) relocation, (long) relocation); #endif - /* Subtract out the addend, because it will get added back in by the normal - processing. */ - return relocation - linker_section_ptr->addend; + return relocation; } #define PPC_LO(v) ((v) & 0xffff) @@ -6457,18 +6532,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) { @@ -6519,6 +6592,102 @@ write_glink_stub (struct plt_entry *ent, asection *plt_sec, } } +/* Return true if symbol is defined statically. */ + +static bfd_boolean +is_static_defined (struct elf_link_hash_entry *h) +{ + return ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && h->root.u.def.section != NULL + && h->root.u.def.section->output_section != NULL); +} + +/* If INSN is an opcode that may be used with an @tls operand, return + the transformed insn for TLS optimisation, otherwise return 0. If + REG is non-zero only match an insn with RB or RA equal to REG. */ + +unsigned int +_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) +{ + unsigned int rtra; + + if ((insn & (0x3f << 26)) != 31 << 26) + return 0; + + if (reg == 0 || ((insn >> 11) & 0x1f) == reg) + rtra = insn & ((1 << 26) - (1 << 16)); + else if (((insn >> 16) & 0x1f) == reg) + rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5); + else + return 0; + + if ((insn & (0x3ff << 1)) == 266 << 1) + /* add -> addi. */ + insn = 14 << 26; + else if ((insn & (0x1f << 1)) == 23 << 1 + && ((insn & (0x1f << 6)) < 14 << 6 + || ((insn & (0x1f << 6)) >= 16 << 6 + && (insn & (0x1f << 6)) < 24 << 6))) + /* load and store indexed -> dform. */ + insn = (32 | ((insn >> 6) & 0x1f)) << 26; + else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1) + /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ + insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1); + else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1) + /* lwax -> lwa. */ + insn = (58 << 26) | 2; + else + return 0; + insn |= rtra; + return insn; +} + +/* If INSN is an opcode that may be used with an @tprel operand, return + the transformed insn for an undefined weak symbol, ie. with the + thread pointer REG operand removed. Otherwise return 0. */ + +unsigned int +_bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg) +{ + if ((insn & (0x1f << 16)) == reg << 16 + && ((insn & (0x3f << 26)) == 14u << 26 /* addi */ + || (insn & (0x3f << 26)) == 15u << 26 /* addis */ + || (insn & (0x3f << 26)) == 32u << 26 /* lwz */ + || (insn & (0x3f << 26)) == 34u << 26 /* lbz */ + || (insn & (0x3f << 26)) == 36u << 26 /* stw */ + || (insn & (0x3f << 26)) == 38u << 26 /* stb */ + || (insn & (0x3f << 26)) == 40u << 26 /* lhz */ + || (insn & (0x3f << 26)) == 42u << 26 /* lha */ + || (insn & (0x3f << 26)) == 44u << 26 /* sth */ + || (insn & (0x3f << 26)) == 46u << 26 /* lmw */ + || (insn & (0x3f << 26)) == 47u << 26 /* stmw */ + || (insn & (0x3f << 26)) == 48u << 26 /* lfs */ + || (insn & (0x3f << 26)) == 50u << 26 /* lfd */ + || (insn & (0x3f << 26)) == 52u << 26 /* stfs */ + || (insn & (0x3f << 26)) == 54u << 26 /* stfd */ + || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */ + && (insn & 3) != 1) + || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */ + && ((insn & 3) == 0 || (insn & 3) == 3)))) + { + insn &= ~(0x1f << 16); + } + else if ((insn & (0x1f << 21)) == reg << 21 + && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */ + || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */ + || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */)) + { + insn &= ~(0x1f << 21); + insn |= (insn & (0x1f << 16)) << 5; + if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */) + insn -= 2 >> 26; /* convert to ori,oris */ + } + else + insn = 0; + return insn; +} + /* The RELOCATE_SECTION function is called by the ELF backend linker to handle the relocations for a section. @@ -6564,7 +6733,6 @@ ppc_elf_relocate_section (bfd *output_bfd, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; Elf_Internal_Rela outrel; - bfd_byte *loc; asection *got2, *sreloc = NULL; bfd_vma *local_got_offsets; bfd_boolean ret = TRUE; @@ -6608,7 +6776,7 @@ ppc_elf_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; bfd_vma relocation; - bfd_vma branch_bit, insn, from; + bfd_vma branch_bit, from; bfd_boolean unresolved_reloc; bfd_boolean warned; unsigned int tls_type, tls_mask, tls_gd; @@ -6706,6 +6874,7 @@ ppc_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { bfd_vma insn; + insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c020000; /* addis 0,2,0 */ @@ -6719,37 +6888,12 @@ ppc_elf_relocate_section (bfd *output_bfd, if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_TPREL) == 0) { - bfd_vma insn, rtra; + bfd_vma insn; + insn = bfd_get_32 (output_bfd, contents + rel->r_offset); - if ((insn & ((31 << 26) | (31 << 11))) - == ((31 << 26) | (2 << 11))) - rtra = insn & ((1 << 26) - (1 << 16)); - else if ((insn & ((31 << 26) | (31 << 16))) - == ((31 << 26) | (2 << 16))) - rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); - else + insn = _bfd_elf_ppc_at_tls_transform (insn, 2); + if (insn == 0) abort (); - if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) - /* add -> addi. */ - insn = 14 << 26; - else if ((insn & (31 << 1)) == 23 << 1 - && ((insn & (31 << 6)) < 14 << 6 - || ((insn & (31 << 6)) >= 16 << 6 - && (insn & (31 << 6)) < 24 << 6))) - /* load and store indexed -> dform. */ - insn = (32 | ((insn >> 6) & 31)) << 26; - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & (0x1a << 6)) == 0) - /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ - insn = (((58 | ((insn >> 6) & 4)) << 26) - | ((insn >> 6) & 1)); - else if ((insn & (31 << 1)) == 21 << 1 - && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) - /* lwax -> lwa. */ - insn = (58 << 26) | 2; - else - abort (); - insn |= rtra; bfd_put_32 (output_bfd, insn, contents + rel->r_offset); r_type = R_PPC_TPREL16_LO; rel->r_info = ELF32_R_INFO (r_symndx, r_type); @@ -6820,9 +6964,7 @@ ppc_elf_relocate_section (bfd *output_bfd, insn1 |= 32 << 26; /* lwz */ if (offset != (bfd_vma) -1) { - rel[1].r_info - = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), - R_PPC_NONE); + rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); insn2 = 0x7c631214; /* add 3,3,2 */ bfd_put_32 (output_bfd, insn2, contents + offset); } @@ -6843,9 +6985,9 @@ ppc_elf_relocate_section (bfd *output_bfd, if (local_sections[r_symndx] == sec) break; if (r_symndx >= symtab_hdr->sh_info) - r_symndx = 0; + r_symndx = STN_UNDEF; rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != 0) + if (r_symndx != STN_UNDEF) rel->r_addend -= (local_syms[r_symndx].st_value + sec->output_offset + sec->output_section->vma); @@ -6896,8 +7038,7 @@ ppc_elf_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, insn2, contents + offset); /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (offset == rel[1].r_offset); - rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), - R_PPC_NONE); + rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); } break; @@ -6912,9 +7053,9 @@ ppc_elf_relocate_section (bfd *output_bfd, if (local_sections[r_symndx] == sec) break; if (r_symndx >= symtab_hdr->sh_info) - r_symndx = 0; + r_symndx = STN_UNDEF; rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; - if (r_symndx != 0) + if (r_symndx != STN_UNDEF) rel->r_addend -= (local_syms[r_symndx].st_value + sec->output_offset + sec->output_section->vma); @@ -6926,8 +7067,7 @@ ppc_elf_relocate_section (bfd *output_bfd, contents + rel->r_offset - d_offset); /* Zap the reloc on the _tls_get_addr call too. */ BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset); - rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), - R_PPC_NONE); + rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE); rel--; continue; } @@ -6950,20 +7090,24 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Branch not taken prediction relocations. */ case R_PPC_ADDR14_BRNTAKEN: case R_PPC_REL14_BRNTAKEN: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset); - insn &= ~BRANCH_PREDICT_BIT; - insn |= branch_bit; + { + bfd_vma insn; - from = (rel->r_offset - + input_section->output_offset - + input_section->output_section->vma); + insn = bfd_get_32 (output_bfd, contents + rel->r_offset); + insn &= ~BRANCH_PREDICT_BIT; + insn |= branch_bit; - /* Invert 'y' bit if not the default. */ - if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) - insn ^= BRANCH_PREDICT_BIT; + from = (rel->r_offset + + input_section->output_offset + + input_section->output_section->vma); - bfd_put_32 (output_bfd, insn, contents + rel->r_offset); - break; + /* Invert 'y' bit if not the default. */ + if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) + insn ^= BRANCH_PREDICT_BIT; + + bfd_put_32 (output_bfd, insn, contents + rel->r_offset); + break; + } } ifunc = NULL; @@ -7017,7 +7161,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; } @@ -7192,6 +7338,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || h->root.type != bfd_link_hash_undefweak)) { asection *rsec = htab->relgot; + bfd_byte * loc; outrel.r_offset = (htab->got->output_section->vma + htab->got->output_offset @@ -7343,6 +7490,21 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_TPREL16_LO: case R_PPC_TPREL16_HI: case R_PPC_TPREL16_HA: + if (h != NULL + && h->root.type == bfd_link_hash_undefweak + && h->dynindx == -1) + { + /* Make this relocation against an undefined weak symbol + resolve to zero. This is really just a tweak, since + code using weak externs ought to check that they are + defined before using them. */ + bfd_byte *p = contents + rel->r_offset - d_offset; + unsigned int insn = bfd_get_32 (output_bfd, p); + insn = _bfd_elf_ppc_at_tprel_transform (insn, 2); + if (insn != 0) + bfd_put_32 (output_bfd, insn, p); + break; + } 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 @@ -7423,7 +7585,7 @@ ppc_elf_relocate_section (bfd *output_bfd, && !h->def_regular)) { int skip; - + bfd_byte * loc; #ifdef DEBUG fprintf (stderr, "ppc_elf_relocate_section needs to " "create relocation for %s\n", @@ -7444,9 +7606,9 @@ ppc_elf_relocate_section (bfd *output_bfd, } skip = 0; - outrel.r_offset = - _bfd_elf_section_offset (output_bfd, info, input_section, - rel->r_offset); + outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, + input_section, + rel->r_offset); if (outrel.r_offset == (bfd_vma) -1 || outrel.r_offset == (bfd_vma) -2) skip = (int) outrel.r_offset; @@ -7496,7 +7658,7 @@ ppc_elf_relocate_section (bfd *output_bfd, sym_name); ret = FALSE; } - else if (r_symndx == 0 || bfd_is_abs_section (sec)) + else if (r_symndx == STN_UNDEF || bfd_is_abs_section (sec)) ; else if (sec == NULL || sec->owner == NULL) { @@ -7557,12 +7719,20 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; - case R_PPC_RELAX32PC_PLT: - case R_PPC_RELAX32_PLT: + case R_PPC_RELAX_PLT: + case R_PPC_RELAX_PLTREL24: if (h != NULL) { - struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2, - info->shared ? addend : 0); + struct plt_entry *ent; + bfd_vma got2_addend = 0; + + if (r_type == R_PPC_RELAX_PLTREL24) + { + if (info->shared) + got2_addend = addend; + addend = 0; + } + ent = find_plt_ent (&h->plt.plist, got2, got2_addend); if (htab->plt_type == PLT_NEW) relocation = (htab->glink->output_section->vma + htab->glink->output_offset @@ -7572,18 +7742,14 @@ ppc_elf_relocate_section (bfd *output_bfd, + htab->plt->output_offset + ent->plt.offset); } - if (r_type == R_PPC_RELAX32_PLT) - goto relax32; /* Fall thru */ - case R_PPC_RELAX32PC: - relocation -= (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset - 4); - /* Fall thru */ + case R_PPC_RELAX: + if (info->shared) + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset - 4); - case R_PPC_RELAX32: - relax32: { unsigned long t0; unsigned long t1; @@ -7620,17 +7786,29 @@ ppc_elf_relocate_section (bfd *output_bfd, /* Indirect .sdata relocation. */ case R_PPC_EMB_SDAI16: BFD_ASSERT (htab->sdata[0].section != NULL); + if (!is_static_defined (htab->sdata[0].sym)) + { + unresolved_reloc = TRUE; + break; + } relocation = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0], h, relocation, rel); + addend = 0; break; /* Indirect .sdata2 relocation. */ case R_PPC_EMB_SDA2I16: BFD_ASSERT (htab->sdata[1].section != NULL); + if (!is_static_defined (htab->sdata[1].sym)) + { + unresolved_reloc = TRUE; + break; + } relocation = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1], h, relocation, rel); + addend = 0; break; /* Handle the TOC16 reloc. We want to use the offset within the .got @@ -7683,12 +7861,16 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_SDAREL16: { const char *name; + struct elf_link_hash_entry *sda = htab->sdata[0].sym; - if (sec == NULL || sec->output_section == NULL) + if (sec == NULL + || sec->output_section == NULL + || !is_static_defined (sda)) { unresolved_reloc = TRUE; break; } + addend -= SYM_VAL (sda); name = bfd_get_section_name (abfd, sec->output_section); if (! ((CONST_STRNEQ (name, ".sdata") @@ -7704,7 +7886,6 @@ ppc_elf_relocate_section (bfd *output_bfd, howto->name, name); } - addend -= SYM_VAL (htab->sdata[0].sym); } break; @@ -7712,12 +7893,16 @@ ppc_elf_relocate_section (bfd *output_bfd, case R_PPC_EMB_SDA2REL: { const char *name; + struct elf_link_hash_entry *sda = htab->sdata[1].sym; - if (sec == NULL || sec->output_section == NULL) + if (sec == NULL + || sec->output_section == NULL + || !is_static_defined (sda)) { unresolved_reloc = TRUE; break; } + addend -= SYM_VAL (sda); name = bfd_get_section_name (abfd, sec->output_section); if (! (CONST_STRNEQ (name, ".sdata2") @@ -7730,12 +7915,7 @@ ppc_elf_relocate_section (bfd *output_bfd, sym_name, howto->name, name); - - bfd_set_error (bfd_error_bad_value); - ret = FALSE; - continue; } - addend -= SYM_VAL (htab->sdata[1].sym); } break; @@ -7745,6 +7925,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { const char *name; int reg; + struct elf_link_hash_entry *sda = NULL; if (sec == NULL || sec->output_section == NULL) { @@ -7759,13 +7940,13 @@ ppc_elf_relocate_section (bfd *output_bfd, && (name[5] == 0 || name[5] == '.')))) { reg = 13; - addend -= SYM_VAL (htab->sdata[0].sym); + sda = htab->sdata[0].sym; } else if (CONST_STRNEQ (name, ".sdata2") || CONST_STRNEQ (name, ".sbss2")) { reg = 2; - addend -= SYM_VAL (htab->sdata[1].sym); + sda = htab->sdata[1].sym; } else if (strcmp (name, ".PPC.EMB.sdata0") == 0 || strcmp (name, ".PPC.EMB.sbss0") == 0) @@ -7787,8 +7968,20 @@ ppc_elf_relocate_section (bfd *output_bfd, continue; } + if (sda != NULL) + { + if (!is_static_defined (sda)) + { + unresolved_reloc = TRUE; + break; + } + addend -= SYM_VAL (sda); + } + if (r_type == R_PPC_EMB_SDA21) - { /* fill in register field */ + { + bfd_vma insn; /* Fill in register field. */ + insn = bfd_get_32 (output_bfd, contents + rel->r_offset); insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); bfd_put_32 (output_bfd, insn, contents + rel->r_offset); @@ -8010,7 +8203,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, { bfd_vma got_offset; const bfd_vma *plt_entry; - + /* The first three entries in .got.plt are reserved. */ got_offset = (reloc_index + 3) * 4; @@ -8051,7 +8244,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, low-order 16 bits of the load instruction. */ /* NOTE: It appears that this is now an index rather than a prescaled offset. */ - bfd_put_32 (output_bfd, + bfd_put_32 (output_bfd, plt_entry[4] | reloc_index, htab->plt->contents + ent->plt.offset + 16); /* This instruction is a PC-relative branch whose target is @@ -8060,8 +8253,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, The address is encoded in bits 6-29, inclusive. The value stored is right-shifted by two bits, permitting a 26-bit offset. */ - bfd_put_32 (output_bfd, - (plt_entry[5] + bfd_put_32 (output_bfd, + (plt_entry[5] | (-(ent->plt.offset + 20) & 0x03fffffc)), htab->plt->contents + ent->plt.offset + 20); bfd_put_32 (output_bfd, plt_entry[6], @@ -8210,8 +8403,8 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, relocation. */ sym->st_shndx = (_bfd_elf_section_from_bfd_section (output_bfd, htab->glink->output_section)); - sym->st_value = (ent->glink_offset + - htab->glink->output_offset + sym->st_value = (ent->glink_offset + + htab->glink->output_offset + htab->glink->output_section->vma); } doneone = TRUE; @@ -8221,12 +8414,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. */ @@ -8317,7 +8533,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, dynobj = elf_hash_table (info)->dynobj; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); if (htab->is_vxworks) - splt = bfd_get_section_by_name (dynobj, ".plt"); + splt = bfd_get_section_by_name (dynobj, ".plt"); else splt = NULL; @@ -8426,9 +8642,9 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, if (splt && splt->size > 0) { /* Use the right PLT. */ - static const bfd_vma *plt_entry = NULL; - plt_entry = info->shared ? - ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry; + const bfd_vma *plt_entry = (info->shared + ? ppc_elf_vxworks_pic_plt0_entry + : ppc_elf_vxworks_plt0_entry); if (!info->shared) { @@ -8466,7 +8682,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, rela.r_addend = 0; bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); loc += sizeof (Elf32_External_Rela); - + /* Output the @l relocation for the second instruction. */ rela.r_offset = (htab->plt->output_section->vma + htab->plt->output_offset @@ -8711,6 +8927,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define TARGET_BIG_SYM bfd_elf32_powerpc_vec #define TARGET_BIG_NAME "elf32-powerpc" #define ELF_ARCH bfd_arch_powerpc +#define ELF_TARGET_ID PPC32_ELF_DATA #define ELF_MACHINE_CODE EM_PPC #ifdef __QNXTARGET__ #define ELF_MAXPAGESIZE 0x1000