/* SPARC-specific support for ELF
- Copyright 2005 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,
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"
#include "elf-bfd.h"
#include "elf/sparc.h"
#include "opcode/sparc.h"
#include "elfxx-sparc.h"
+#include "elf-vxworks.h"
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
#define MINUS_ONE (~ (bfd_vma) 0)
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);
{ 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 },
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)
{
#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)
{
- 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 TRUE;
+ return bfd_elf_allocate_object (abfd, sizeof (struct _bfd_sparc_elf_obj_tdata),
+ SPARC_ELF_TDATA);
}
static void
}
static void
-sparc_elf_append_rela_64 (bfd *abfd ATTRIBUTE_UNUSED,
- asection *s ATTRIBUTE_UNUSED,
- Elf_Internal_Rela *rel ATTRIBUTE_UNUSED)
+sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
{
-#ifdef BFD64
- Elf64_External_Rela *loc64;
+ const struct elf_backend_data *bed;
+ bfd_byte *loc;
- 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)
-{
- Elf32_External_Rela *loc32;
-
- 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
return index - 4;
}
+/* The format of the first PLT entry in a VxWorks executable. */
+static const bfd_vma sparc_vxworks_exec_plt0_entry[] =
+ {
+ 0x05000000, /* sethi %hi(_GLOBAL_OFFSET_TABLE_+8), %g2 */
+ 0x8410a000, /* or %g2, %lo(_GLOBAL_OFFSET_TABLE_+8), %g2 */
+ 0xc4008000, /* ld [ %g2 ], %g2 */
+ 0x81c08000, /* jmp %g2 */
+ 0x01000000 /* nop */
+ };
+
+/* The format of subsequent PLT entries. */
+static const bfd_vma sparc_vxworks_exec_plt_entry[] =
+ {
+ 0x03000000, /* sethi %hi(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */
+ 0x82106000, /* or %g1, %lo(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */
+ 0xc2004000, /* ld [ %g1 ], %g1 */
+ 0x81c04000, /* jmp %g1 */
+ 0x01000000, /* nop */
+ 0x03000000, /* sethi %hi(f@pltindex), %g1 */
+ 0x10800000, /* b _PLT_resolve */
+ 0x82106000 /* or %g1, %lo(f@pltindex), %g1 */
+ };
+
+/* The format of the first PLT entry in a VxWorks shared object. */
+static const bfd_vma sparc_vxworks_shared_plt0_entry[] =
+ {
+ 0xc405e008, /* ld [ %l7 + 8 ], %g2 */
+ 0x81c08000, /* jmp %g2 */
+ 0x01000000 /* nop */
+ };
+
+/* The format of subsequent PLT entries. */
+static const bfd_vma sparc_vxworks_shared_plt_entry[] =
+ {
+ 0x03000000, /* sethi %hi(f@got), %g1 */
+ 0x82106000, /* or %g1, %lo(f@got), %g1 */
+ 0xc205c001, /* ld [ %l7 + %g1 ], %g1 */
+ 0x81c04000, /* jmp %g1 */
+ 0x01000000, /* nop */
+ 0x03000000, /* sethi %hi(f@pltindex), %g1 */
+ 0x10800000, /* b _PLT_resolve */
+ 0x82106000 /* or %g1, %lo(f@pltindex), %g1 */
+ };
+
#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)
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->build_plt_entry = sparc64_plt_entry_build;
ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF64;
ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD64;
ret->tpoff_reloc = R_SPARC_TLS_TPOFF64;
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->build_plt_entry = sparc32_plt_entry_build;
ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF32;
ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD32;
ret->tpoff_reloc = R_SPARC_TLS_TPOFF32;
ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER;
}
- if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc))
+ if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
+ sizeof (struct _bfd_sparc_elf_link_hash_entry)))
{
free (ret);
return NULL;
|| ! bfd_set_section_alignment (dynobj, htab->srelgot,
htab->word_align_power))
return FALSE;
+
+ if (htab->is_vxworks)
+ {
+ htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+ if (!htab->sgotplt)
+ return FALSE;
+ }
+
return TRUE;
}
if (!info->shared)
htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+ if (htab->is_vxworks)
+ {
+ if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+ return FALSE;
+ if (info->shared)
+ {
+ htab->plt_header_size
+ = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt0_entry);
+ htab->plt_entry_size
+ = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt_entry);
+ }
+ else
+ {
+ htab->plt_header_size
+ = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt0_entry);
+ htab->plt_entry_size
+ = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt_entry);
+ }
+ }
+ else
+ {
+ if (ABI_64_P (dynobj))
+ {
+ htab->build_plt_entry = sparc64_plt_entry_build;
+ htab->plt_header_size = PLT64_HEADER_SIZE;
+ htab->plt_entry_size = PLT64_ENTRY_SIZE;
+ }
+ else
+ {
+ htab->build_plt_entry = sparc32_plt_entry_build;
+ htab->plt_header_size = PLT32_HEADER_SIZE;
+ htab->plt_entry_size = PLT32_ENTRY_SIZE;
+ }
+ }
+
if (!htab->splt || !htab->srelplt || !htab->sdynbss
|| (!info->shared && !htab->srelbss))
abort ();
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);
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++)
{
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. */
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:
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. */
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
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;
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. */
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);
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)
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);
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
{
asection *s = htab->splt;
- /* The first four entries in .plt is reserved. */
+ /* Allocate room for the header. */
if (s->size == 0)
- s->size = (SPARC_ELF_WORD_BYTES(htab) == 8 ?
- PLT64_HEADER_SIZE : PLT32_HEADER_SIZE);
+ {
+ s->size = htab->plt_header_size;
+
+ /* Allocate space for the .rela.plt.unloaded relocations. */
+ if (htab->is_vxworks && !info->shared)
+ htab->srelplt2->size = sizeof (Elf32_External_Rela) * 2;
+ }
/* The procedure linkage table size is bounded by the magnitude
of the offset we can describe in the entry. */
}
/* Make room for this entry. */
- s->size += (SPARC_ELF_WORD_BYTES(htab) == 8 ?
- PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE);
+ s->size += htab->plt_entry_size;
/* We also need to make an entry in the .rela.plt section. */
htab->srelplt->size += SPARC_ELF_RELA_BYTES (htab);
+
+ if (htab->is_vxworks)
+ {
+ /* Allocate space for the .got.plt entry. */
+ htab->sgotplt->size += 4;
+
+ /* ...and for the .rela.plt.unloaded relocations. */
+ if (!info->shared)
+ htab->srelplt2->size += sizeof (Elf32_External_Rela) * 3;
+ }
}
else
{
pp = &p->next;
}
}
+
+ 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
+ && h->root.type == bfd_link_hash_undefweak)
+ {
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ eh->dyn_relocs = NULL;
+
+ /* Make sure undefined weak symbols are output as a dynamic
+ symbol in PIEs. */
+ else if (h->dynindx == -1
+ && !h->forced_local)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+ }
}
else
{
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)
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;
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);
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
if (! ABI_64_P (output_bfd)
+ && !htab->is_vxworks
&& elf_hash_table (info)->dynamic_sections_created)
{
/* Make space for the trailing nop in .plt. */
if (s == htab->splt
|| s == htab->sgot
- || s == htab->sdynbss)
+ || s == htab->sdynbss
+ || s == htab->sgotplt)
{
/* 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)
{
eht->dynsymcount++;
}
}
+ if (htab->is_vxworks
+ && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+ return FALSE;
}
#undef add_dynamic_entry
bfd_boolean
_bfd_sparc_elf_new_section_hook (bfd *abfd, asection *sec)
{
- struct _bfd_sparc_elf_section_data *sdata;
- bfd_size_type amt = sizeof (*sdata);
+ if (!sec->used_by_bfd)
+ {
+ struct _bfd_sparc_elf_section_data *sdata;
+ bfd_size_type amt = sizeof (*sdata);
- sdata = (struct _bfd_sparc_elf_section_data *) bfd_zalloc (abfd, amt);
- if (sdata == NULL)
- return FALSE;
- sec->used_by_bfd = (PTR) sdata;
+ sdata = bfd_zalloc (abfd, amt);
+ if (sdata == NULL)
+ return FALSE;
+ sec->used_by_bfd = sdata;
+ }
return _bfd_elf_new_section_hook (abfd, sec);
}
/* 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;
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);
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))
}
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;
}
}
+ 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:
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,
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);
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
{
long indx;
+ outrel.r_addend = relocation + rel->r_addend;
+
if (is_plt)
sec = htab->splt;
{
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)
}
}
- 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. */
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)
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))
+ 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);
}
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))
return TRUE;
}
+/* Build a VxWorks PLT entry. PLT_INDEX is the index of the PLT entry
+ and PLT_OFFSET is the byte offset from the start of .plt. GOT_OFFSET
+ is the offset of the associated .got.plt entry from
+ _GLOBAL_OFFSET_TABLE_. */
+
+static void
+sparc_vxworks_build_plt_entry (bfd *output_bfd, struct bfd_link_info *info,
+ bfd_vma plt_offset, bfd_vma plt_index,
+ bfd_vma got_offset)
+{
+ bfd_vma got_base;
+ const bfd_vma *plt_entry;
+ struct _bfd_sparc_elf_link_hash_table *htab;
+ bfd_byte *loc;
+ Elf_Internal_Rela rela;
+
+ htab = _bfd_sparc_elf_hash_table (info);
+ if (info->shared)
+ {
+ plt_entry = sparc_vxworks_shared_plt_entry;
+ got_base = 0;
+ }
+ else
+ {
+ plt_entry = sparc_vxworks_exec_plt_entry;
+ got_base = (htab->elf.hgot->root.u.def.value
+ + htab->elf.hgot->root.u.def.section->output_offset
+ + htab->elf.hgot->root.u.def.section->output_section->vma);
+ }
+
+ /* Fill in the entry in the procedure linkage table. */
+ bfd_put_32 (output_bfd, plt_entry[0] + ((got_base + got_offset) >> 10),
+ htab->splt->contents + plt_offset);
+ bfd_put_32 (output_bfd, plt_entry[1] + ((got_base + got_offset) & 0x3ff),
+ htab->splt->contents + plt_offset + 4);
+ bfd_put_32 (output_bfd, plt_entry[2],
+ htab->splt->contents + plt_offset + 8);
+ bfd_put_32 (output_bfd, plt_entry[3],
+ htab->splt->contents + plt_offset + 12);
+ bfd_put_32 (output_bfd, plt_entry[4],
+ htab->splt->contents + plt_offset + 16);
+ bfd_put_32 (output_bfd, plt_entry[5] + (plt_index >> 10),
+ htab->splt->contents + plt_offset + 20);
+ /* PC-relative displacement for a branch to the start of
+ the PLT section. */
+ bfd_put_32 (output_bfd, plt_entry[6] + (((-plt_offset - 24) >> 2)
+ & 0x003fffff),
+ htab->splt->contents + plt_offset + 24);
+ bfd_put_32 (output_bfd, plt_entry[7] + (plt_index & 0x3ff),
+ htab->splt->contents + plt_offset + 28);
+
+ /* Fill in the .got.plt entry, pointing initially at the
+ second half of the PLT entry. */
+ BFD_ASSERT (htab->sgotplt != NULL);
+ bfd_put_32 (output_bfd,
+ htab->splt->output_section->vma
+ + htab->splt->output_offset
+ + plt_offset + 20,
+ htab->sgotplt->contents + got_offset);
+
+ /* Add relocations to .rela.plt.unloaded. */
+ if (!info->shared)
+ {
+ loc = (htab->srelplt2->contents
+ + (2 + 3 * plt_index) * sizeof (Elf32_External_Rela));
+
+ /* Relocate the initial sethi. */
+ rela.r_offset = (htab->splt->output_section->vma
+ + htab->splt->output_offset
+ + plt_offset);
+ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+ rela.r_addend = got_offset;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* Likewise the following or. */
+ rela.r_offset += 4;
+ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* Relocate the .got.plt entry. */
+ rela.r_offset = (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + got_offset);
+ rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32);
+ rela.r_addend = plt_offset + 20;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ }
+}
+
/* Finish up dynamic symbol handling. We set the contents of various
dynamic sections here. */
{
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)
{
asection *srela;
Elf_Internal_Rela rela;
bfd_byte *loc;
- bfd_vma r_offset;
+ bfd_vma r_offset, got_offset;
int rela_index;
/* This symbol has an entry in the PLT. Set it up. */
srela = htab->srelplt;
BFD_ASSERT (splt != NULL && srela != NULL);
- /* Fill in the entry in the procedure linkage table. */
- rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt,
- h->plt.offset, splt->size,
- &r_offset);
-
/* Fill in the entry in the .rela.plt section. */
- rela.r_offset = r_offset
- + (splt->output_section->vma + splt->output_offset);
- if (! ABI_64_P (output_bfd)
- || h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
+ if (htab->is_vxworks)
{
+ /* Work out the index of this PLT entry. */
+ rela_index = ((h->plt.offset - htab->plt_header_size)
+ / htab->plt_entry_size);
+
+ /* Calculate the offset of the associated .got.plt entry.
+ The first three entries are reserved. */
+ got_offset = (rela_index + 3) * 4;
+
+ sparc_vxworks_build_plt_entry (output_bfd, info, h->plt.offset,
+ rela_index, got_offset);
+
+
+ /* On VxWorks, the relocation points to the .got.plt entry,
+ not the .plt entry. */
+ rela.r_offset = (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset
+ + got_offset);
rela.r_addend = 0;
}
else
{
- rela.r_addend = -(h->plt.offset + 4)
- -(splt->output_section->vma + splt->output_offset);
+ /* Fill in the entry in the procedure linkage table. */
+ rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt,
+ h->plt.offset, splt->size,
+ &r_offset);
+
+ rela.r_offset = r_offset
+ + (splt->output_section->vma + splt->output_offset);
+ if (! ABI_64_P (output_bfd)
+ || h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE))
+ {
+ rela.r_addend = 0;
+ }
+ else
+ {
+ rela.r_addend = (-(h->plt.offset + 4)
+ - splt->output_section->vma
+ - splt->output_offset);
+ }
}
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_JMP_SLOT);
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)
{
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)
+ 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. */
+ /* Mark some specially defined symbols as absolute. On VxWorks,
+ _GLOBAL_OFFSET_TABLE_ is not absolute: it is relative to the
+ ".got" section. Likewise _PROCEDURE_LINKAGE_TABLE_ and ".plt". */
if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+ || (!htab->is_vxworks
+ && (h == htab->elf.hgot || h == htab->elf.hplt)))
sym->st_shndx = SHN_ABS;
return TRUE;
/* 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;
+ 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;
- dyncon = (Elf64_External_Dyn *) sdyn->contents;
- dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
- for (; dyncon < dynconend; dyncon++)
+ htab = _bfd_sparc_elf_hash_table (info);
+ 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_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
+ bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
- switch (dyn.d_tag)
+ if (htab->is_vxworks && dyn.d_tag == DT_RELASZ)
+ {
+ /* On VxWorks, DT_RELASZ should not include the relocations
+ in .rela.plt. */
+ if (htab->srelplt)
+ {
+ dyn.d_un.d_val -= htab->srelplt->size;
+ bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
+ }
+ else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT)
+ {
+ /* On VxWorks, DT_PLTGOT should point to the start of the GOT,
+ not to the start of the PLT. */
+ if (htab->sgotplt)
+ {
+ dyn.d_un.d_val = (htab->sgotplt->output_section->vma
+ + htab->sgotplt->output_offset);
+ 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)
{
- 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 =
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;
+ bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
}
-
- if (name != NULL)
+ else
{
- asection *s;
+ 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;
+ default: name = NULL; size = FALSE; break;
+ }
- s = bfd_get_section_by_name (output_bfd, name);
- if (s == NULL)
- dyn.d_un.d_val = 0;
- else
+ if (name != NULL)
{
- if (! size)
- dyn.d_un.d_ptr = s->vma;
+ asection *s;
+
+ s = bfd_get_section_by_name (output_bfd, name);
+ if (s == NULL)
+ dyn.d_un.d_val = 0;
else
- dyn.d_un.d_val = s->size;
+ {
+ if (! size)
+ dyn.d_un.d_ptr = s->vma;
+ else
+ dyn.d_un.d_val = s->size;
+ }
+ bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
}
- 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 ATTRIBUTE_UNUSED,
- bfd *dynobj, asection *sdyn,
- asection *splt ATTRIBUTE_UNUSED)
+/* Install the first PLT entry in a VxWorks executable and make sure that
+ .rela.plt.unloaded relocations have the correct symbol indexes. */
+
+static void
+sparc_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
{
- Elf32_External_Dyn *dyncon, *dynconend;
+ struct _bfd_sparc_elf_link_hash_table *htab;
+ Elf_Internal_Rela rela;
+ bfd_vma got_base;
+ bfd_byte *loc;
- dyncon = (Elf32_External_Dyn *) sdyn->contents;
- dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
- for (; dyncon < dynconend; dyncon++)
- {
- Elf_Internal_Dyn dyn;
- const char *name;
- bfd_boolean size;
+ htab = _bfd_sparc_elf_hash_table (info);
- bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+ /* Calculate the absolute value of _GLOBAL_OFFSET_TABLE_. */
+ got_base = (htab->elf.hgot->root.u.def.section->output_section->vma
+ + htab->elf.hgot->root.u.def.section->output_offset
+ + htab->elf.hgot->root.u.def.value);
+
+ /* Install the initial PLT entry. */
+ bfd_put_32 (output_bfd,
+ sparc_vxworks_exec_plt0_entry[0] + ((got_base + 8) >> 10),
+ htab->splt->contents);
+ bfd_put_32 (output_bfd,
+ sparc_vxworks_exec_plt0_entry[1] + ((got_base + 8) & 0x3ff),
+ htab->splt->contents + 4);
+ bfd_put_32 (output_bfd,
+ sparc_vxworks_exec_plt0_entry[2],
+ htab->splt->contents + 8);
+ bfd_put_32 (output_bfd,
+ sparc_vxworks_exec_plt0_entry[3],
+ htab->splt->contents + 12);
+ bfd_put_32 (output_bfd,
+ sparc_vxworks_exec_plt0_entry[4],
+ htab->splt->contents + 16);
+
+ loc = htab->srelplt2->contents;
+
+ /* Add an unloaded relocation for the initial entry's "sethi". */
+ rela.r_offset = (htab->splt->output_section->vma
+ + htab->splt->output_offset);
+ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+ rela.r_addend = 8;
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* Likewise the following "or". */
+ rela.r_offset += 4;
+ rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+ bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* Fix up the remaining .rela.plt.unloaded relocations. They may have
+ the wrong symbol index for _G_O_T_ or _P_L_T_ depending on the order
+ in which symbols were output. */
+ while (loc < htab->srelplt2->contents + htab->srelplt2->size)
+ {
+ Elf_Internal_Rela rel;
+
+ /* The entry's initial "sethi" (against _G_O_T_). */
+ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22);
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* The following "or" (also against _G_O_T_). */
+ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+ rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10);
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+ loc += sizeof (Elf32_External_Rela);
+
+ /* The .got.plt entry (against _P_L_T_). */
+ bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+ rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32);
+ bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+ loc += sizeof (Elf32_External_Rela);
+ }
+}
- 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;
- default: name = NULL; size = FALSE; break;
- }
+/* Install the first PLT entry in a VxWorks shared object. */
- if (name != NULL)
- {
- asection *s;
+static void
+sparc_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info)
+{
+ struct _bfd_sparc_elf_link_hash_table *htab;
+ unsigned int i;
- 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_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
- }
- }
- return TRUE;
+ htab = _bfd_sparc_elf_hash_table (info);
+ for (i = 0; i < ARRAY_SIZE (sparc_vxworks_shared_plt0_entry); i++)
+ bfd_put_32 (output_bfd, sparc_vxworks_shared_plt0_entry[i],
+ htab->splt->contents + i * 4);
}
bfd_boolean
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)
{
- if (ABI_64_P (output_bfd))
- memset (splt->contents, 0, 4 * PLT64_ENTRY_SIZE);
+ if (htab->is_vxworks)
+ {
+ if (info->shared)
+ sparc_vxworks_finish_shared_plt (output_bfd, info);
+ else
+ sparc_vxworks_finish_exec_plt (output_bfd, info);
+ }
else
{
- memset (splt->contents, 0, 4 * PLT32_ENTRY_SIZE);
- bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP,
- splt->contents + splt->size - 4);
+ memset (splt->contents, 0, htab->plt_header_size);
+ if (!ABI_64_P (output_bfd))
+ bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP,
+ splt->contents + splt->size - 4);
}
}
- elf_section_data (splt->output_section)->this_hdr.sh_entsize =
- (ABI_64_P (output_bfd) ? PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE);
+ elf_section_data (splt->output_section)->this_hdr.sh_entsize
+ = (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