/* VAX series support for 32-bit ELF
Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
Contributed by Matt Thomas <matt@3am-software.com>.
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. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
Elf_Internal_Sym *);
static bfd_boolean elf_vax_finish_dynamic_sections (bfd *,
struct bfd_link_info *);
+static bfd_vma elf_vax_plt_sym_val (bfd_vma, const asection *,
+ const arelent *);
static bfd_boolean elf32_vax_set_private_flags (bfd *, flagword);
static bfd_boolean elf32_vax_merge_private_bfd_data (bfd *, bfd *);
return 0;
}
+static reloc_howto_type *
+reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++)
+ if (howto_table[i].name != NULL
+ && strcasecmp (howto_table[i].name, r_name) == 0)
+ return &howto_table[i];
+
+ return NULL;
+}
+
#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup reloc_name_lookup
#define ELF_ARCH bfd_arch_vax
/* end code generated by elf.el */
\f
static const bfd_byte elf_vax_plt_entry[PLT_ENTRY_SIZE] =
{
- 0x40, 0x00, /* .word ^M<r6> */
- 0x16, 0xef, /* jsb L^(pc) */
+ 0xfc, 0x0f, /* .word ^M<r11:r2> */
+ 0x16, 0xef, /* jsb L^(pc) */
0, 0, 0, 0, /* replaced with offset to start of .plt */
0, 0, 0, 0, /* index into .rela.plt */
};
bfd_vma got_addend;
};
-/* VAX ELF linker hash table. */
-
-struct elf_vax_link_hash_table
-{
- struct elf_link_hash_table root;
-};
-
/* Declare this now that the above structures are defined. */
static bfd_boolean elf_vax_discard_copies (struct elf_vax_link_hash_entry *,
- PTR);
+ void *);
/* Declare this now that the above structures are defined. */
static bfd_boolean elf_vax_instantiate_got_entries (struct elf_link_hash_entry *,
- PTR);
+ void *);
/* Traverse an VAX ELF linker hash table. */
#define elf_vax_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
- (&(table)->root, \
+ ((table), \
(bfd_boolean (*) (struct elf_link_hash_entry *, PTR)) (func), \
(info)))
-/* Get the VAX ELF linker hash table from a link_info structure. */
-
-#define elf_vax_hash_table(p) ((struct elf_vax_link_hash_table *) (p)->hash)
-
/* Create an entry in an VAX ELF linker hash table. */
static struct bfd_hash_entry *
static struct bfd_link_hash_table *
elf_vax_link_hash_table_create (bfd *abfd)
{
- struct elf_vax_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct elf_vax_link_hash_table);
+ struct elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct elf_link_hash_table);
ret = bfd_malloc (amt);
if (ret == NULL)
return NULL;
- if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+ if (!_bfd_elf_link_hash_table_init (ret, abfd,
elf_vax_link_hash_newfunc,
- sizeof (struct elf_vax_link_hash_entry)))
+ sizeof (struct elf_vax_link_hash_entry),
+ GENERIC_ELF_DATA))
{
free (ret);
return NULL;
}
- return &ret->root.root;
+ return &ret->root;
}
/* Keep vax-specific flags in the ELF header */
static bfd_boolean
elf32_vax_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
{
- flagword out_flags;
flagword in_flags;
if ( bfd_get_flavour (ibfd) != bfd_target_elf_flavour
return TRUE;
in_flags = elf_elfheader (ibfd)->e_flags;
- out_flags = elf_elfheader (obfd)->e_flags;
if (!elf_flags_init (obfd))
{
switch (ELF32_R_TYPE (rel->r_info))
{
case R_VAX_GOT32:
- if (h != NULL
- && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ BFD_ASSERT (h != NULL);
+ if (h->forced_local
+ || h == elf_hash_table (info)->hgot
+ || h == elf_hash_table (info)->hplt)
+ break;
+
+ /* If this is a local symbol, we resolve it directly without
+ creating a global offset table entry. */
+ if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
break;
/* This symbol requires a global offset table entry. */
h->got.refcount++;
if (eh->got_addend != (bfd_vma) rel->r_addend)
(*_bfd_error_handler)
- (_("%s: warning: GOT addend of %ld to `%s' does not match previous GOT addend of %ld"),
- bfd_get_filename (abfd), rel->r_addend,
- h->root.root.string,
- eh->got_addend);
+ (_("%s: warning: GOT addend of %ld to `%s' does"
+ " not match previous GOT addend of %ld"),
+ bfd_get_filename (abfd), rel->r_addend,
+ h->root.root.string,
+ eh->got_addend);
}
}
/* If this is a local symbol, we resolve it directly without
creating a procedure linkage table entry. */
- if (h == NULL)
- continue;
+ BFD_ASSERT (h != NULL);
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT || h->forced_local)
+ break;
h->needs_plt = 1;
if (h->plt.refcount == -1)
&& (!info->symbolic
|| !h->def_regular)))
{
- if (h != NULL)
+ if (h != NULL
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !h->forced_local)
{
/* Make sure a plt entry is created for this symbol if
it turns out to be a function defined by a dynamic
}
break;
}
+ /* If this is a local symbol, we can resolve it directly. */
+ if (h != NULL
+ && (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || h->forced_local))
+ break;
+
/* Fall through. */
case R_VAX_8:
case R_VAX_16:
case R_VAX_32:
- if (h != NULL)
+ if (h != NULL && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
{
/* Make sure a plt entry is created for this symbol if it
turns out to be a function defined by a dynamic object. */
section in dynobj and make room for this reloc. */
if (sreloc == NULL)
{
- const char *name;
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
+ if (sreloc == NULL)
return FALSE;
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && strcmp (bfd_get_section_name (abfd, sec),
- name + 5) == 0);
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- if (sreloc == NULL)
- {
- sreloc = bfd_make_section_with_flags (dynobj,
- name,
- (SEC_ALLOC
- | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY));
- if (sreloc == NULL
- || !bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
if (sec->flags & SEC_READONLY)
info->flags |= DF_TEXTREL;
}
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_VAX_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;
const Elf_Internal_Rela *rel, *relend;
bfd *dynobj;
+ if (info->relocatable)
+ return TRUE;
+
dynobj = elf_hash_table (info)->dynobj;
if (dynobj == NULL)
return TRUE;
{
bfd *dynobj;
asection *s;
- unsigned int power_of_two;
dynobj = elf_hash_table (info)->dynobj;
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 > 3)
- power_of_two = 3;
-
- /* Apply the required alignment. */
- 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);
}
/* Set the sizes of the dynamic sections. */
allocated space for them in the check_relocs routine, but we will not
fill them in in the relocate_section routine. */
if (info->shared && info->symbolic)
- elf_vax_link_hash_traverse (elf_vax_hash_table (info),
+ elf_vax_link_hash_traverse (elf_hash_table (info),
elf_vax_discard_copies,
NULL);
{
struct elf_vax_pcrel_relocs_copied *s;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct elf_vax_link_hash_entry *) h->root.root.u.i.link;
-
/* We only discard relocs for symbols defined in a regular object. */
if (!h->root.def_regular)
return TRUE;
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
if (!elf_hash_table (info)->dynamic_sections_created
- || (info->shared && info->symbolic))
+ || (info->shared && info->symbolic)
+ || h->forced_local)
{
h->got.refcount = 0;
h->got.offset = (bfd_vma) -1;
}
else if (h->got.refcount > 0)
{
+ bfd_boolean dyn;
+
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1)
{
return FALSE;
}
+ dyn = elf_hash_table (info)->dynamic_sections_created;
/* Allocate space in the .got and .rela.got sections. */
- sgot->size += 4;
- srelgot->size += sizeof (Elf32_External_Rela);
+ if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && (info->shared
+ || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
+ {
+ sgot->size += 4;
+ srelgot->size += sizeof (Elf32_External_Rela);
+ }
}
return TRUE;
bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
- bfd_vma *local_got_offsets;
bfd_vma plt_index;
bfd_vma got_offset;
asection *sgot;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- if (info->relocatable)
- return TRUE;
-
dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (input_bfd);
- local_got_offsets = elf_local_got_offsets (input_bfd);
sgot = NULL;
splt = NULL;
}
howto = howto_table + r_type;
- /* This is a final link. */
r_symndx = ELF32_R_SYM (rel->r_info);
h = NULL;
sym = NULL;
|| h->root.type == bfd_link_hash_defweak)
&& ((r_type == R_VAX_PLT32
&& h->plt.offset != (bfd_vma) -1
+ && !h->forced_local
&& elf_hash_table (info)->dynamic_sections_created)
|| (r_type == R_VAX_GOT32
- && strcmp (h->root.root.string,
- "_GLOBAL_OFFSET_TABLE_") != 0
+ && h->got.offset != (bfd_vma) -1
+ && !h->forced_local
&& elf_hash_table (info)->dynamic_sections_created
&& (! info->shared
|| (! info->symbolic && h->dynindx != -1)
&& h->def_dynamic))
&& (r_type == R_VAX_8
|| r_type == R_VAX_16
- || r_type == R_VAX_32
- || r_type == R_VAX_PC8
- || r_type == R_VAX_PC16
- || r_type == R_VAX_PC32))))
+ || r_type == R_VAX_32))))
/* In these cases, we don't need the relocation
value. We check specially because in some
obscure cases sec->output_section will be NULL. */
relocation = 0;
}
+ if (sec != NULL && elf_discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend, howto, contents);
+
+ if (info->relocatable)
+ continue;
+
switch (r_type)
{
case R_VAX_GOT32:
/* Relocation is to the address of the entry for this symbol
in the global offset table. */
- if (h == NULL || h->got.offset == (bfd_vma) -1)
+ if (h == NULL
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || h->got.offset == (bfd_vma) -1
+ || h->forced_local)
break;
/* Relocation is the offset of the entry for this symbol in
the global offset table. */
{
+ bfd_boolean dyn;
bfd_vma off;
if (sgot == NULL)
BFD_ASSERT (off != (bfd_vma) -1);
BFD_ASSERT (off < sgot->size);
- if (info->shared
- && h->dynindx == -1
- && h->def_regular)
+ dyn = elf_hash_table (info)->dynamic_sections_created;
+ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ || (info->shared
+ && SYMBOL_REFERENCES_LOCAL (info, h)))
{
/* The symbol was forced to be local
because of a version file.. We must initialize
}
break;
+ case R_VAX_PC32:
+ /* If we are creating an executable and the function this
+ reloc refers to is in a shared lib, then we made a PLT
+ entry for this symbol and need to handle the reloc like
+ a PLT reloc. */
+ if (info->shared)
+ goto r_vax_pc32_shared;
+ /* Fall through. */
case R_VAX_PLT32:
/* Relocation is to the entry for this symbol in the
procedure linkage table. */
/* Resolve a PLTxx reloc against a local symbol directly,
without using the procedure linkage table. */
- if (h == NULL)
+ if (h == NULL
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || h->forced_local)
break;
if (h->plt.offset == (bfd_vma) -1
if (sgotplt == NULL)
{
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
- BFD_ASSERT (splt != NULL);
+ BFD_ASSERT (sgotplt != NULL);
}
plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
The first two are reserved. */
got_offset = (plt_index + 3) * 4;
- /* We want the relocate to point into the .got.plt instead
+ /* We want the relocation to point into the .got.plt instead
of the plt itself. */
relocation = (sgotplt->output_section->vma
+ sgotplt->output_offset
case R_VAX_PC8:
case R_VAX_PC16:
- case R_VAX_PC32:
- if (h == NULL)
+ r_vax_pc32_shared:
+ if (h == NULL
+ || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || h->forced_local)
break;
/* Fall through. */
case R_VAX_8:
case R_VAX_16:
case R_VAX_32:
if (info->shared
- && r_symndx != 0
+ && r_symndx != STN_UNDEF
&& (input_section->flags & SEC_ALLOC) != 0
&& ((r_type != R_VAX_PC8
&& r_type != R_VAX_PC16
&& r_type != R_VAX_PC32)
- || (!info->symbolic
- || !h->def_regular)))
+ || ((input_section->flags & SEC_CODE)
+ && (!info->symbolic
+ || (!h->def_regular && h->type != STT_SECTION)))))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
time. */
if (sreloc == NULL)
{
- const char *name;
-
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
+ sreloc = _bfd_elf_get_dynamic_reloc_section
+ (input_bfd, input_section, /*rela?*/ TRUE);
+ if (sreloc == NULL)
return FALSE;
-
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && strcmp (bfd_get_section_name (input_bfd,
- input_section),
- name + 5) == 0);
-
- sreloc = bfd_get_section_by_name (dynobj, name);
- BFD_ASSERT (sreloc != NULL);
}
skip = FALSE;
return TRUE;
}
+static enum elf_reloc_type_class
+elf_vax_reloc_type_class (const Elf_Internal_Rela *rela)
+{
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ case R_VAX_RELATIVE:
+ return reloc_class_relative;
+ case R_VAX_JMP_SLOT:
+ return reloc_class_plt;
+ case R_VAX_COPY:
+ return reloc_class_copy;
+ default:
+ return reloc_class_normal;
+ }
+}
+
+static bfd_vma
+elf_vax_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ return plt->vma + (i + 1) * PLT_ENTRY_SIZE;
+}
+
#define TARGET_LITTLE_SYM bfd_elf32_vax_vec
#define TARGET_LITTLE_NAME "elf32-vax"
#define ELF_MACHINE_CODE EM_VAX
elf_vax_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
elf_vax_finish_dynamic_sections
+#define elf_backend_reloc_type_class elf_vax_reloc_type_class
#define elf_backend_gc_mark_hook elf_vax_gc_mark_hook
#define elf_backend_gc_sweep_hook elf_vax_gc_sweep_hook
+#define elf_backend_plt_sym_val elf_vax_plt_sym_val
#define bfd_elf32_bfd_merge_private_bfd_data \
elf32_vax_merge_private_bfd_data
#define bfd_elf32_bfd_set_private_flags \