X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfxx-sparc.c;h=f5fe41fcbc77433d09ce97a50a7d6aaa64f940a6;hb=7a0801a90405cc2ff07b7b9f04abb4ec9184fd43;hp=6da70a32f86861429f42f063377f5adb83c5904a;hpb=62d7a5f67e8130a28b0555fff3aa27b0b6d3074d;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c index 6da70a32f8..f5fe41fcbc 100644 --- a/bfd/elfxx-sparc.c +++ b/bfd/elfxx-sparc.c @@ -1,11 +1,11 @@ /* SPARC-specific support for ELF - Copyright 2005, 2006 Free Software Foundation, Inc. + Copyright 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,12 +15,14 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + /* This file handles functionality common to the different SPARC ABI's. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" #include "libiberty.h" @@ -256,7 +258,12 @@ static reloc_howto_type _bfd_sparc_elf_howto_table[] = HOWTO(R_SPARC_TLS_DTPOFF32,0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF32",FALSE,0,0xffffffff,TRUE), HOWTO(R_SPARC_TLS_DTPOFF64,0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF64",FALSE,0,MINUS_ONE,TRUE), HOWTO(R_SPARC_TLS_TPOFF32,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF32",FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE) + HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE), + HOWTO(R_SPARC_GOTDATA_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_HIX22",FALSE,0,0x003fffff, FALSE), + HOWTO(R_SPARC_GOTDATA_LOX10,0,2,0,FALSE,0,complain_overflow_dont, sparc_elf_lox10_reloc, "R_SPARC_GOTDATA_LOX10",FALSE,0,0x000003ff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_OP_HIX22",FALSE,0,0x003fffff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP_LOX10,0,2,0,FALSE,0,complain_overflow_dont, sparc_elf_lox10_reloc, "R_SPARC_GOTDATA_OP_LOX10",FALSE,0,0x000003ff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOTDATA_OP",FALSE,0,0x00000000,TRUE), }; static reloc_howto_type sparc_vtinherit_howto = HOWTO (R_SPARC_GNU_VTINHERIT, 0,2,0,FALSE,0,complain_overflow_dont, NULL, "R_SPARC_GNU_VTINHERIT", FALSE,0, 0, FALSE); @@ -347,6 +354,11 @@ static const struct elf_reloc_map sparc_reloc_map[] = { BFD_RELOC_SPARC_H44, R_SPARC_H44 }, { BFD_RELOC_SPARC_M44, R_SPARC_M44 }, { BFD_RELOC_SPARC_L44, R_SPARC_L44 }, + { BFD_RELOC_SPARC_GOTDATA_HIX22, R_SPARC_GOTDATA_HIX22 }, + { BFD_RELOC_SPARC_GOTDATA_LOX10, R_SPARC_GOTDATA_LOX10 }, + { BFD_RELOC_SPARC_GOTDATA_OP_HIX22, R_SPARC_GOTDATA_OP_HIX22 }, + { BFD_RELOC_SPARC_GOTDATA_OP_LOX10, R_SPARC_GOTDATA_OP_LOX10 }, + { BFD_RELOC_SPARC_GOTDATA_OP, R_SPARC_GOTDATA_OP }, { BFD_RELOC_SPARC_REGISTER, R_SPARC_REGISTER }, { BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT }, { BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY }, @@ -384,6 +396,30 @@ _bfd_sparc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, return NULL; } +reloc_howto_type * +_bfd_sparc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (_bfd_sparc_elf_howto_table) + / sizeof (_bfd_sparc_elf_howto_table[0])); + i++) + if (_bfd_sparc_elf_howto_table[i].name != NULL + && strcasecmp (_bfd_sparc_elf_howto_table[i].name, r_name) == 0) + return &_bfd_sparc_elf_howto_table[i]; + + if (strcasecmp (sparc_vtinherit_howto.name, r_name) == 0) + return &sparc_vtinherit_howto; + if (strcasecmp (sparc_vtentry_howto.name, r_name) == 0) + return &sparc_vtentry_howto; + if (strcasecmp (sparc_rev32_howto.name, r_name) == 0) + return &sparc_rev32_howto; + + return NULL; +} + reloc_howto_type * _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type) { @@ -484,17 +520,16 @@ struct _bfd_sparc_elf_obj_tdata #define _bfd_sparc_elf_local_got_tls_type(abfd) \ (_bfd_sparc_elf_tdata (abfd)->local_got_tls_type) +#define is_sparc_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == SPARC_ELF_TDATA) + bfd_boolean _bfd_sparc_elf_mkobject (bfd *abfd) { - if (abfd->tdata.any == NULL) - { - bfd_size_type amt = sizeof (struct _bfd_sparc_elf_obj_tdata); - abfd->tdata.any = bfd_zalloc (abfd, amt); - if (abfd->tdata.any == NULL) - return FALSE; - } - return bfd_elf_mkobject (abfd); + return bfd_elf_allocate_object (abfd, sizeof (struct _bfd_sparc_elf_obj_tdata), + SPARC_ELF_TDATA); } static void @@ -510,27 +545,14 @@ sparc_put_word_64 (bfd *bfd, bfd_vma val, void *ptr) } static void -sparc_elf_append_rela_64 (bfd *abfd ATTRIBUTE_UNUSED, - asection *s ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel ATTRIBUTE_UNUSED) -{ -#ifdef BFD64 - Elf64_External_Rela *loc64; - - loc64 = (Elf64_External_Rela *) s->contents; - loc64 += s->reloc_count++; - bfd_elf64_swap_reloca_out (abfd, rel, (bfd_byte *) loc64); -#endif -} - -static void -sparc_elf_append_rela_32 (bfd *abfd, asection *s, Elf_Internal_Rela *rel) +sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) { - Elf32_External_Rela *loc32; + const struct elf_backend_data *bed; + bfd_byte *loc; - loc32 = (Elf32_External_Rela *) s->contents; - loc32 += s->reloc_count++; - bfd_elf32_swap_reloca_out (abfd, rel, (bfd_byte *) loc32); + bed = get_elf_backend_data (abfd); + loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); + bed->s->swap_reloca_out (abfd, rel, loc); } static bfd_vma @@ -749,9 +771,6 @@ static const bfd_vma sparc_vxworks_shared_plt_entry[] = #define SPARC_ELF_PUT_WORD(htab, bfd, val, ptr) \ htab->put_word(bfd, val, ptr) -#define SPARC_ELF_APPEND_RELA(htab, bfd, sec, rela) \ - htab->append_rela(bfd, sec, rela) - #define SPARC_ELF_R_INFO(htab, in_rel, index, type) \ htab->r_info(in_rel, index, type) @@ -827,7 +846,6 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd) if (ABI_64_P (abfd)) { ret->put_word = sparc_put_word_64; - ret->append_rela = sparc_elf_append_rela_64; ret->r_info = sparc_elf_r_info_64; ret->r_symndx = sparc_elf_r_symndx_64; ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF64; @@ -843,7 +861,6 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd) else { ret->put_word = sparc_put_word_32; - ret->append_rela = sparc_elf_append_rela_32; ret->r_info = sparc_elf_r_info_32; ret->r_symndx = sparc_elf_r_symndx_32; ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF32; @@ -882,13 +899,7 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info) htab->sgot = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (htab->sgot != NULL); - htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", - SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY); + htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got"); if (htab->srelgot == NULL || ! bfd_set_section_alignment (dynobj, htab->srelgot, htab->word_align_power)) @@ -1082,7 +1093,7 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, return TRUE; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); local_got_offsets = elf_local_got_offsets (abfd); @@ -1092,6 +1103,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, num_relocs = NUM_SHDR_ENTRIES (& elf_section_data (sec)->rel_hdr); else num_relocs = sec->reloc_count; + + BFD_ASSERT (is_sparc_elf (abfd) || num_relocs == 0); + rel_end = relocs + num_relocs; for (rel = relocs; rel < rel_end; rel++) { @@ -1168,6 +1182,10 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: case R_SPARC_TLS_GD_HI22: case R_SPARC_TLS_GD_LO10: /* This symbol requires a global offset table entry. */ @@ -1180,6 +1198,10 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: tls_type = GOT_NORMAL; break; case R_SPARC_TLS_GD_HI22: @@ -1301,6 +1323,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, goto r_sparc_plt32; break; } + /* PR 7027: We need similar behaviour for 64-bit binaries. */ + else if (r_type == R_SPARC_WPLT30) + break; /* It does not make sense to have a procedure linkage table entry for a local symbol. */ @@ -1420,42 +1445,15 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, section in dynobj and make room for the reloc. */ if (sreloc == NULL) { - const char *name; - bfd *dynobj; - - name = (bfd_elf_string_from_elf_section - (abfd, - elf_elfheader (abfd)->e_shstrndx, - elf_section_data (sec)->rel_hdr.sh_name)); - if (name == NULL) - return FALSE; - - BFD_ASSERT (strncmp (name, ".rela", 5) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - name + 5) == 0); - if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; - dynobj = htab->elf.dynobj; - sreloc = bfd_get_section_by_name (dynobj, name); + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, htab->elf.dynobj, htab->word_align_power, + abfd, /*rela?*/ TRUE); + if (sreloc == NULL) - { - flagword flags; - - flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - sreloc = bfd_make_section_with_flags (dynobj, - name, - flags); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, - htab->word_align_power)) - return FALSE; - } - elf_section_data (sec)->sreloc = sreloc; + return FALSE; } /* If this is a global symbol, we count the number of @@ -1467,15 +1465,19 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Track dynamic relocs needed for local syms too. We really need local syms available to do this easily. Oh well. */ - asection *s; void *vpp; + Elf_Internal_Sym *isym; - s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, - sec, r_symndx); - if (s == NULL) + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + if (isym == NULL) return FALSE; + s = bfd_section_from_elf_index (abfd, isym->st_shndx); + if (s == NULL) + s = sec; + vpp = &elf_section_data (s)->local_dynrel; head = (struct _bfd_sparc_elf_dyn_relocs **) vpp; } @@ -1508,7 +1510,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, break; case R_SPARC_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) return FALSE; break; @@ -1532,35 +1536,14 @@ _bfd_sparc_elf_gc_mark_hook (asection *sec, Elf_Internal_Sym *sym) { if (h != NULL) - { - struct _bfd_sparc_elf_link_hash_table *htab; - - htab = _bfd_sparc_elf_hash_table (info); - switch (SPARC_ELF_R_TYPE (rel->r_info)) + switch (SPARC_ELF_R_TYPE (rel->r_info)) { case R_SPARC_GNU_VTINHERIT: case R_SPARC_GNU_VTENTRY: - break; - - default: - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; - - case bfd_link_hash_common: - return h->root.u.c.p->section; - - default: - break; - } + return NULL; } - } - else - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); - return NULL; + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } /* Update the got entry reference counts for the section being removed. */ @@ -1574,10 +1557,15 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel, *relend; + if (info->relocatable) + return TRUE; + + BFD_ASSERT (is_sparc_elf (abfd) || sec->reloc_count == 0); + elf_section_data (sec)->local_dynrel = NULL; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); @@ -1626,6 +1614,10 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: if (h != NULL) { if (h->got.refcount > 0) @@ -1716,7 +1708,6 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, struct _bfd_sparc_elf_link_hash_entry * eh; struct _bfd_sparc_elf_dyn_relocs *p; asection *s; - unsigned int power_of_two; htab = _bfd_sparc_elf_hash_table (info); @@ -1833,29 +1824,9 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > htab->align_power_max) - power_of_two = htab->align_power_max; - - /* Apply the required alignment. */ s = htab->sdynbss; - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (dynobj, s)) - { - if (! bfd_set_section_alignment (dynobj, s, power_of_two)) - return FALSE; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - return TRUE; + return _bfd_elf_adjust_dynamic_copy (h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -2041,6 +2012,19 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) } } + if (htab->is_vxworks) + { + struct _bfd_sparc_elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) + *pp = p->next; + else + pp = &p->next; + } + } + /* Also discard relocs on undefined weak syms with non-default visibility. */ if (eh->dyn_relocs != NULL @@ -2186,7 +2170,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr; asection *srel; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + if (! is_sparc_elf (ibfd)) continue; for (s = ibfd->sections; s != NULL; s = s->next) @@ -2203,6 +2187,13 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, linker script /DISCARD/, so we'll be discarding the relocs too. */ } + else if (htab->is_vxworks + && strcmp (p->sec->output_section->name, + ".tls_vars") == 0) + { + /* Relocations in vxworks .tls_vars sections are + handled specially by the loader. */ + } else if (p->count != 0) { srel = elf_section_data (p->sec)->sreloc; @@ -2217,7 +2208,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, if (!local_got) continue; - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; local_tls_type = _bfd_sparc_elf_local_got_tls_type (ibfd); @@ -2290,7 +2281,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, /* Strip this section if we don't need it; see the comment below. */ } - else if (strncmp (s->name, ".rela", 5) == 0) + else if (CONST_STRNEQ (s->name, ".rela")) { if (s->size != 0) { @@ -2428,6 +2419,9 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, eht->dynsymcount++; } } + if (htab->is_vxworks + && !elf_vxworks_add_dynamic_entries (output_bfd, info)) + return FALSE; } #undef add_dynamic_entry @@ -2457,6 +2451,10 @@ _bfd_sparc_elf_relax_section (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *link_info ATTRIBUTE_UNUSED, bfd_boolean *again) { + if (link_info->relocatable) + (*link_info->callbacks->einfo) + (_("%P%F: --relax and -r may not be used together\n")); + *again = FALSE; sec_do_relax (section) = 1; return TRUE; @@ -2492,10 +2490,14 @@ tpoff (struct bfd_link_info *info, bfd_vma address) /* Relocate a SPARC ELF section. */ bfd_boolean -_bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, - bfd *input_bfd, asection *input_section, - bfd_byte *contents, Elf_Internal_Rela *relocs, - Elf_Internal_Sym *local_syms, asection **local_sections) +_bfd_sparc_elf_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) { struct _bfd_sparc_elf_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; @@ -2506,12 +2508,10 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; int num_relocs; - - if (info->relocatable) - return TRUE; + bfd_boolean is_vxworks_tls; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); @@ -2521,6 +2521,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, got_base = elf_hash_table (info)->hgot->root.u.def.value; sreloc = elf_section_data (input_section)->sreloc; + /* We have to handle relocations in vxworks .tls_vars sections + specially, because the dynamic loader is 'weird'. */ + is_vxworks_tls = (htab->is_vxworks && info->shared + && !strcmp (input_section->output_section->name, + ".tls_vars")); rel = relocs; if (ABI_64_P (output_bfd)) @@ -2553,7 +2558,6 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } howto = _bfd_sparc_elf_howto_table + r_type; - /* This is a final link. */ r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info); h = NULL; sym = NULL; @@ -2585,8 +2589,37 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } } + if (sec != NULL && elf_discarded_section (sec)) + { + /* For relocs against symbols from removed linkonce + sections, or sections discarded by a linker script, we + just want the section contents zeroed. Avoid any + special processing. */ + _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); + rel->r_info = 0; + rel->r_addend = 0; + continue; + } + + if (info->relocatable) + continue; + switch (r_type) { + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: + /* We don't support these code transformation optimizations + yet, so just leave the sequence alone and treat as + GOT22/GOT10. */ + if (r_type == R_SPARC_GOTDATA_HIX22 + || r_type == R_SPARC_GOTDATA_OP_HIX22) + r_type = R_SPARC_GOT22; + else + r_type = R_SPARC_GOT10; + /* Fall through. */ + case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: @@ -2666,7 +2699,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, 0, R_SPARC_RELATIVE); outrel.r_addend = relocation; relocation = 0; - SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &outrel); + sparc_elf_append_rela (output_bfd, s, &outrel); } SPARC_ELF_PUT_WORD (htab, output_bfd, relocation, @@ -2705,6 +2738,9 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (h == NULL) break; } + /* PR 7027: We need similar behaviour for 64-bit binaries. */ + else if (r_type == R_SPARC_WPLT30 && h == NULL) + break; else { BFD_ASSERT (h != NULL); @@ -2773,11 +2809,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_L44: case R_SPARC_UA64: r_sparc_plt32: - /* r_symndx will be zero only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - if (r_symndx == 0 - || (input_section->flags & SEC_ALLOC) == 0) + if ((input_section->flags & SEC_ALLOC) == 0 + || is_vxworks_tls) break; if ((info->shared @@ -2885,6 +2918,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { long indx; + outrel.r_addend = relocation + rel->r_addend; + if (is_plt) sec = htab->splt; @@ -2899,9 +2934,20 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { asection *osec; + /* We are turning this relocation into one + against a section symbol. It would be + proper to subtract the symbol's value, + osec->vma, from the emitted reloc addend, + but ld.so expects buggy relocs. */ osec = sec->output_section; indx = elf_section_data (osec)->dynindx; + if (indx == 0) + { + osec = htab->elf.text_index_section; + indx = elf_section_data (osec)->dynindx; + } + /* FIXME: we really should be able to link non-pic shared libraries. */ if (indx == 0) @@ -2915,12 +2961,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } } - outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx, r_type); - outrel.r_addend = relocation + rel->r_addend; + outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx, + r_type); } } - SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel); + sparc_elf_append_rela (output_bfd, sreloc, &outrel); /* This reloc will be computed at runtime, so there's no need to do anything now. */ @@ -3028,7 +3074,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, else outrel.r_addend = 0; outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx, dr_type); - SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel); + sparc_elf_append_rela (output_bfd, htab->srelgot, &outrel); if (r_type == R_SPARC_TLS_GD_HI22 || r_type == R_SPARC_TLS_GD_LO10) @@ -3049,7 +3095,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx, SPARC_ELF_DTPOFF_RELOC (htab)); outrel.r_offset += SPARC_ELF_WORD_BYTES (htab); - SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel); + sparc_elf_append_rela (output_bfd, htab->srelgot, + &outrel); } } else if (dr_type == SPARC_ELF_DTPMOD_RELOC (htab)) @@ -3118,7 +3165,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + rel->r_addend; } - SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel); + sparc_elf_append_rela (output_bfd, sreloc, &outrel); continue; } relocation = tpoff (info, relocation); @@ -3226,6 +3273,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } continue; + case R_SPARC_GOTDATA_OP: + /* We don't support gotdata code transformation optimizations + yet, so simply leave the sequence as-is. */ + continue; + case R_SPARC_TLS_IE_LD: case R_SPARC_TLS_IE_LDX: if (! info->shared && (h == NULL || h->dynindx == -1)) @@ -3639,9 +3691,11 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, { bfd *dynobj; struct _bfd_sparc_elf_link_hash_table *htab; + const struct elf_backend_data *bed; htab = _bfd_sparc_elf_hash_table (info); dynobj = htab->elf.dynobj; + bed = get_elf_backend_data (output_bfd); if (h->plt.offset != (bfd_vma) -1) { @@ -3711,18 +3765,8 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, thus .plt[4] has corresponding .rela.plt[0] and so on. */ loc = srela->contents; -#ifdef BFD64 - if (ABI_64_P (output_bfd)) - { - loc += rela_index * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - } - else -#endif - { - loc += rela_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } + loc += rela_index * bed->s->sizeof_rela; + bed->s->swap_reloca_out (output_bfd, &rela, loc); if (!h->def_regular) { @@ -3779,7 +3823,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, SPARC_ELF_PUT_WORD (htab, output_bfd, 0, sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - SPARC_ELF_APPEND_RELA (htab, output_bfd, srela, &rela); + sparc_elf_append_rela (output_bfd, srela, &rela); } if (h->needs_copy) @@ -3799,7 +3843,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, + h->root.u.def.section->output_offset); rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_COPY); rela.r_addend = 0; - SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &rela); + sparc_elf_append_rela (output_bfd, s, &rela); } /* Mark some specially defined symbols as absolute. On VxWorks, @@ -3815,83 +3859,30 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, /* Finish up the dynamic sections. */ -#ifdef BFD64 static bfd_boolean -sparc64_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, - bfd *dynobj, asection *sdyn, - asection *splt ATTRIBUTE_UNUSED) +sparc_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, + bfd *dynobj, asection *sdyn, + asection *splt ATTRIBUTE_UNUSED) { - Elf64_External_Dyn *dyncon, *dynconend; - int stt_regidx = -1; - - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) - { - Elf_Internal_Dyn dyn; - const char *name; - bfd_boolean size; - - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); - - switch (dyn.d_tag) - { - case DT_PLTGOT: name = ".plt"; size = FALSE; break; - case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break; - case DT_JMPREL: name = ".rela.plt"; size = FALSE; break; - case DT_SPARC_REGISTER: - if (stt_regidx == -1) - { - stt_regidx = - _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1); - if (stt_regidx == -1) - return FALSE; - } - dyn.d_un.d_val = stt_regidx++; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - /* fallthrough */ - default: name = NULL; size = FALSE; break; - } - - if (name != NULL) - { - asection *s; - - s = bfd_get_section_by_name (output_bfd, name); - if (s == NULL) - dyn.d_un.d_val = 0; - else - { - if (! size) - dyn.d_un.d_ptr = s->vma; - else - dyn.d_un.d_val = s->size; - } - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - return TRUE; -} -#endif - -static bfd_boolean -sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, - bfd *dynobj, asection *sdyn, - asection *splt ATTRIBUTE_UNUSED) -{ - Elf32_External_Dyn *dyncon, *dynconend; struct _bfd_sparc_elf_link_hash_table *htab; + const struct elf_backend_data *bed; + bfd_byte *dyncon, *dynconend; + size_t dynsize; + int stt_regidx = -1; + bfd_boolean abi_64_p; htab = _bfd_sparc_elf_hash_table (info); - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) + bed = get_elf_backend_data (output_bfd); + dynsize = bed->s->sizeof_dyn; + dynconend = sdyn->contents + sdyn->size; + abi_64_p = ABI_64_P (output_bfd); + for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize) { Elf_Internal_Dyn dyn; const char *name; bfd_boolean size; - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); + bed->s->swap_dyn_in (dynobj, dyncon, &dyn); if (htab->is_vxworks && dyn.d_tag == DT_RELASZ) { @@ -3900,7 +3891,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, if (htab->srelplt) { dyn.d_un.d_val -= htab->srelplt->size; - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } } else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT) @@ -3911,8 +3902,23 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, { dyn.d_un.d_val = (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset); - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + else if (htab->is_vxworks + && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); + else if (abi_64_p && dyn.d_tag == DT_SPARC_REGISTER) + { + if (stt_regidx == -1) + { + stt_regidx = + _bfd_elf_link_lookup_local_dynindx (info, output_bfd, -1); + if (stt_regidx == -1) + return FALSE; } + dyn.d_un.d_val = stt_regidx++; + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } else { @@ -3921,7 +3927,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, case DT_PLTGOT: name = ".plt"; size = FALSE; break; case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break; case DT_JMPREL: name = ".rela.plt"; size = FALSE; break; - default: name = NULL; size = FALSE; break; + default: name = NULL; size = FALSE; break; } if (name != NULL) @@ -3938,7 +3944,7 @@ sparc32_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, else dyn.d_un.d_val = s->size; } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } } } @@ -4052,20 +4058,12 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i if (elf_hash_table (info)->dynamic_sections_created) { asection *splt; - bfd_boolean ret; splt = bfd_get_section_by_name (dynobj, ".plt"); BFD_ASSERT (splt != NULL && sdyn != NULL); -#ifdef BFD64 - if (ABI_64_P (output_bfd)) - ret = sparc64_finish_dyn (output_bfd, info, dynobj, sdyn, splt); - else -#endif - ret = sparc32_finish_dyn (output_bfd, info, dynobj, sdyn, splt); - - if (ret != TRUE) - return ret; + if (!sparc_finish_dyn (output_bfd, info, dynobj, sdyn, splt)) + return FALSE; /* Initialize the contents of the .plt section. */ if (splt->size > 0) @@ -4087,7 +4085,8 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i } elf_section_data (splt->output_section)->this_hdr.sh_entsize - = htab->plt_entry_size; + = (htab->is_vxworks || !ABI_64_P (output_bfd)) + ? 0 : htab->plt_entry_size; } /* Set the first entry in the global offset table to the address of