/* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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)
{
return &sparc_rev32_howto;
default:
- BFD_ASSERT (r_type < (unsigned int) R_SPARC_max_std);
+ if (r_type >= (unsigned int) R_SPARC_max_std)
+ {
+ (*_bfd_error_handler) (_("invalid relocation type %d"),
+ (int) r_type);
+ r_type = R_SPARC_NONE;
+ }
return &_bfd_sparc_elf_howto_table[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, asection *s, Elf_Internal_Rela *rel)
+sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
{
- 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);
-}
-
-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
-sparc_elf_r_info_64 (Elf_Internal_Rela *in_rel, bfd_vma index, bfd_vma type)
+sparc_elf_r_info_64 (Elf_Internal_Rela *in_rel ATTRIBUTE_UNUSED,
+ bfd_vma index ATTRIBUTE_UNUSED,
+ bfd_vma type ATTRIBUTE_UNUSED)
{
return ELF64_R_INFO (index,
(in_rel ?
static bfd_vma
sparc_elf_r_symndx_64 (bfd_vma r_info)
{
- return ELF64_R_SYM (r_info);
+ bfd_vma r_symndx = ELF32_R_SYM (r_info);
+ return (r_symndx >> 24);
}
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;
htab->sgot = bfd_get_section_by_name (dynobj, ".got");
BFD_ASSERT (htab->sgot != NULL);
- htab->srelgot = bfd_make_section (dynobj, ".rela.got");
+ 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);
if (htab->srelgot == NULL
- || ! bfd_set_section_flags (dynobj, htab->srelgot, SEC_ALLOC
- | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY)
|| ! 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 ();
/* Copy the extra info we tack onto an elf_link_hash_entry. */
void
-_bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
+_bfd_sparc_elf_copy_indirect_symbol (struct bfd_link_info *info,
struct elf_link_hash_entry *dir,
struct elf_link_hash_entry *ind)
{
struct _bfd_sparc_elf_dyn_relocs **pp;
struct _bfd_sparc_elf_dyn_relocs *p;
- if (ind->root.type == bfd_link_hash_indirect)
- abort ();
-
- /* Add reloc counts against the weak sym to the strong sym
+ /* Add reloc counts against the indirect sym to the direct sym
list. Merge any entries against the same section. */
for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
{
edir->tls_type = eind->tls_type;
eind->tls_type = GOT_UNKNOWN;
}
- _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
static int
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++)
{
if (r_symndx < symtab_hdr->sh_info)
h = NULL;
else
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
/* Compatibility with old R_SPARC_REV32 reloc conflicting
with R_SPARC_TLS_GD_HI22. */
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;
-
- sreloc = bfd_make_section (dynobj, name);
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
- if (sreloc == NULL
- || ! bfd_set_section_flags (dynobj, sreloc, flags)
- || ! 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
easily. Oh well. */
asection *s;
+ void *vpp;
+
s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
sec, r_symndx);
if (s == NULL)
return FALSE;
- head = ((struct _bfd_sparc_elf_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
+ vpp = &elf_section_data (s)->local_dynrel;
+ head = (struct _bfd_sparc_elf_dyn_relocs **) vpp;
}
p = *head;
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);
return TRUE;
}
+ if (h->size == 0)
+ {
+ (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+ h->root.root.string);
+ return TRUE;
+ }
+
/* We must allocate the symbol in our .dynbss section, which will
become part of the .bss section of the executable. There will be
an entry for this symbol in the .dynsym section. The dynamic
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. */
if (s->size >= (SPARC_ELF_WORD_BYTES(htab) == 8 ?
- (bfd_vma)1 << 32 : 0x400000))
+ (((bfd_vma)1 << 31) << 1) : 0x400000))
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
/* 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)
{
struct _bfd_sparc_elf_dyn_relocs *p;
- for (p = *((struct _bfd_sparc_elf_dyn_relocs **)
- &elf_section_data (s)->local_dynrel);
- p != NULL;
- p = p->next)
+ for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
{
if (!bfd_is_abs_section (p->sec)
&& bfd_is_abs_section (p->sec->output_section))
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. */
memory for them. */
for (s = dynobj->sections; s != NULL; s = s->next)
{
- const char *name;
- bfd_boolean strip = FALSE;
-
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
- /* It's OK to base decisions on the section name, because none
- of the dynobj section names depend upon the input files. */
- name = bfd_get_section_name (dynobj, s);
-
- if (strncmp (name, ".rela", 5) == 0)
+ if (s == htab->splt
+ || s == htab->sgot
+ || s == htab->sdynbss
+ || s == htab->sgotplt)
{
- if (s->size == 0)
- {
- /* If we don't need this section, strip it from the
- output file. This is to handle .rela.bss and
- .rel.plt. We must create it in
- create_dynamic_sections, because it must be created
- before the linker maps input sections to output
- sections. The linker does that before
- adjust_dynamic_symbol is called, and it is that
- function which decides whether anything needs to go
- into these sections. */
- strip = TRUE;
- }
- else
+ /* Strip this section if we don't need it; see the
+ comment below. */
+ }
+ else if (CONST_STRNEQ (s->name, ".rela"))
+ {
+ if (s->size != 0)
{
/* We use the reloc_count field as a counter if we need
to copy relocs into the output file. */
s->reloc_count = 0;
}
}
- else if (s != htab->splt && s != htab->sgot)
+ else
{
- /* It's not one of our sections, so don't allocate space. */
+ /* It's not one of our sections. */
continue;
}
- if (strip)
+ if (s->size == 0)
{
- _bfd_strip_section_from_output (info, s);
+ /* If we don't need this section, strip it from the
+ output file. This is mostly to handle .rela.bss and
+ .rela.plt. We must create both sections in
+ create_dynamic_sections, because they must be created
+ before the linker maps input sections to output
+ sections. The linker does that before
+ adjust_dynamic_symbol is called, and it is that
+ function which decides whether anything needs to go
+ into these sections. */
+ s->flags |= SEC_EXCLUDE;
continue;
}
+ if ((s->flags & SEC_HAS_CONTENTS) == 0)
+ continue;
+
/* Allocate memory for the section contents. Zero the memory
for the benefit of .rela.plt, which has 4 unused entries
at the beginning, and we don't want garbage. */
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
- if (s->contents == NULL && s->size != 0)
+ if (s->contents == NULL)
return FALSE;
}
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))
&& !((input_section->flags & SEC_DEBUGGING) != 0
&& h->def_dynamic))
(*_bfd_error_handler)
- (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+ (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
(long) rel->r_offset,
+ howto->name,
h->root.root.string);
r = bfd_reloc_continue;
{
const char *name;
+ /* The Solaris native linker silently disregards overflows.
+ We don't, but this breaks stabs debugging info, whose
+ relocations are only 32-bits wide. Ignore overflows in
+ this case and also for discarded entries. */
+ if ((r_type == R_SPARC_32 || r_type == R_SPARC_DISP32)
+ && (((input_section->flags & SEC_DEBUGGING) != 0
+ && strcmp (bfd_section_name (input_bfd,
+ input_section),
+ ".stab") == 0)
+ || _bfd_elf_section_offset (output_bfd, info,
+ input_section,
+ rel->r_offset)
+ == (bfd_vma)-1))
+ break;
+
if (h != NULL)
- name = NULL;
+ {
+ /* Assume this is a call protected by other code that
+ detect the symbol is undefined. If this is the case,
+ we can safely ignore the overflow. If not, the
+ program is hosed anyway, and a little warning isn't
+ going to help. */
+ if (h->root.type == bfd_link_hash_undefweak
+ && howto->pc_relative)
+ break;
+
+ name = NULL;
+ }
else
{
name = bfd_elf_string_from_elf_section (input_bfd,
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;
- if (ABI_64_P (output_bfd))
- {
- loc += rela_index * sizeof (Elf64_External_Rela);
- bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
- }
- else
- {
- 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. */
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;
}
-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);
- if (ABI_64_P (output_bfd))
- ret = sparc64_finish_dyn (output_bfd, info, dynobj, sdyn, splt);
- else
- 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