X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=6e4cbc1238ebd0a70dfc36a800b04e77776ab2d7;hb=c16153aed7cc77c39bb5e78b2880a9792e1d0554;hp=0c372f00a4155545578dc69a4566ca3cebe02aa0;hpb=32af9f6e558c4f6bb55d36a317d2ec43b29d4bb6;p=binutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 0c372f00a41..6e4cbc1238e 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. @@ -1796,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. */ @@ -1804,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 @@ -2159,123 +2159,92 @@ 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; + + 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; - 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 (num_entries) + { + /* Set the output section size, if it exists. */ + asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); + 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); @@ -2779,10 +2748,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. */ @@ -2826,7 +2805,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; @@ -3133,7 +3113,8 @@ 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; @@ -3445,7 +3426,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) @@ -3473,46 +3453,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, 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; } } @@ -6669,6 +6641,51 @@ _bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg) 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. @@ -7471,6 +7488,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