Line 1... |
Line 1... |
/* VAX series support for 32-bit ELF
|
/* VAX series support for 32-bit ELF
|
Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
|
2004, 2005, 2006, 2007 Free Software Foundation, Inc.
|
2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
Contributed by Matt Thomas <matt@3am-software.com>.
|
Contributed by Matt Thomas <matt@3am-software.com>.
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
Line 45... |
Line 45... |
static bfd_boolean elf_vax_finish_dynamic_symbol (bfd *, struct bfd_link_info *,
|
static bfd_boolean elf_vax_finish_dynamic_symbol (bfd *, struct bfd_link_info *,
|
struct elf_link_hash_entry *,
|
struct elf_link_hash_entry *,
|
Elf_Internal_Sym *);
|
Elf_Internal_Sym *);
|
static bfd_boolean elf_vax_finish_dynamic_sections (bfd *,
|
static bfd_boolean elf_vax_finish_dynamic_sections (bfd *,
|
struct bfd_link_info *);
|
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_set_private_flags (bfd *, flagword);
|
static bfd_boolean elf32_vax_merge_private_bfd_data (bfd *, bfd *);
|
static bfd_boolean elf32_vax_merge_private_bfd_data (bfd *, bfd *);
|
static bfd_boolean elf32_vax_print_private_bfd_data (bfd *, PTR);
|
static bfd_boolean elf32_vax_print_private_bfd_data (bfd *, PTR);
|
|
|
Line 366... |
Line 368... |
|
|
/* Subsequent entries in a procedure linkage table look like this. */
|
/* Subsequent entries in a procedure linkage table look like this. */
|
|
|
static const bfd_byte elf_vax_plt_entry[PLT_ENTRY_SIZE] =
|
static const bfd_byte elf_vax_plt_entry[PLT_ENTRY_SIZE] =
|
{
|
{
|
0x40, 0x00, /* .word ^M<r6> */
|
0xfc, 0x0f, /* .word ^M<r11:r2> */
|
0x16, 0xef, /* jsb L^(pc) */
|
0x16, 0xef, /* jsb L^(pc) */
|
0, 0, 0, 0, /* replaced with offset to start of .plt */
|
0, 0, 0, 0, /* replaced with offset to start of .plt */
|
0, 0, 0, 0, /* index into .rela.plt */
|
0, 0, 0, 0, /* index into .rela.plt */
|
};
|
};
|
|
|
Line 597... |
Line 599... |
}
|
}
|
|
|
switch (ELF32_R_TYPE (rel->r_info))
|
switch (ELF32_R_TYPE (rel->r_info))
|
{
|
{
|
case R_VAX_GOT32:
|
case R_VAX_GOT32:
|
if (h != NULL
|
BFD_ASSERT (h != NULL);
|
&& strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
|
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;
|
break;
|
|
|
/* This symbol requires a global offset table entry. */
|
/* This symbol requires a global offset table entry. */
|
|
|
if (dynobj == NULL)
|
if (dynobj == NULL)
|
Line 652... |
Line 661... |
else
|
else
|
{
|
{
|
h->got.refcount++;
|
h->got.refcount++;
|
if (eh->got_addend != (bfd_vma) rel->r_addend)
|
if (eh->got_addend != (bfd_vma) rel->r_addend)
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%s: warning: GOT addend of %ld to `%s' does not match previous GOT addend of %ld"),
|
(_("%s: warning: GOT addend of %ld to `%s' does"
|
|
" not match previous GOT addend of %ld"),
|
bfd_get_filename (abfd), rel->r_addend,
|
bfd_get_filename (abfd), rel->r_addend,
|
h->root.root.string,
|
h->root.root.string,
|
eh->got_addend);
|
eh->got_addend);
|
|
|
}
|
}
|
Line 671... |
Line 681... |
don't need to generate a procedure linkage table entry
|
don't need to generate a procedure linkage table entry
|
after all. */
|
after all. */
|
|
|
/* If this is a local symbol, we resolve it directly without
|
/* If this is a local symbol, we resolve it directly without
|
creating a procedure linkage table entry. */
|
creating a procedure linkage table entry. */
|
if (h == NULL)
|
BFD_ASSERT (h != NULL);
|
continue;
|
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT || h->forced_local)
|
|
break;
|
|
|
h->needs_plt = 1;
|
h->needs_plt = 1;
|
if (h->plt.refcount == -1)
|
if (h->plt.refcount == -1)
|
h->plt.refcount = 1;
|
h->plt.refcount = 1;
|
else
|
else
|
Line 700... |
Line 711... |
&& (sec->flags & SEC_ALLOC) != 0
|
&& (sec->flags & SEC_ALLOC) != 0
|
&& h != NULL
|
&& h != NULL
|
&& (!info->symbolic
|
&& (!info->symbolic
|
|| !h->def_regular)))
|
|| !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
|
/* Make sure a plt entry is created for this symbol if
|
it turns out to be a function defined by a dynamic
|
it turns out to be a function defined by a dynamic
|
object. */
|
object. */
|
if (h->plt.refcount == -1)
|
if (h->plt.refcount == -1)
|
Line 712... |
Line 725... |
else
|
else
|
h->plt.refcount++;
|
h->plt.refcount++;
|
}
|
}
|
break;
|
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. */
|
/* Fall through. */
|
case R_VAX_8:
|
case R_VAX_8:
|
case R_VAX_16:
|
case R_VAX_16:
|
case R_VAX_32:
|
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
|
/* Make sure a plt entry is created for this symbol if it
|
turns out to be a function defined by a dynamic object. */
|
turns out to be a function defined by a dynamic object. */
|
if (h->plt.refcount == -1)
|
if (h->plt.refcount == -1)
|
h->plt.refcount = 1;
|
h->plt.refcount = 1;
|
Line 736... |
Line 755... |
/* When creating a shared object, we must copy these
|
/* When creating a shared object, we must copy these
|
reloc types into the output file. We create a reloc
|
reloc types into the output file. We create a reloc
|
section in dynobj and make room for this reloc. */
|
section in dynobj and make room for this reloc. */
|
if (sreloc == NULL)
|
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)
|
|
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)
|
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;
|
return FALSE;
|
}
|
|
if (sec->flags & SEC_READONLY)
|
if (sec->flags & SEC_READONLY)
|
info->flags |= DF_TEXTREL;
|
info->flags |= DF_TEXTREL;
|
}
|
}
|
|
|
sreloc->size += sizeof (Elf32_External_Rela);
|
sreloc->size += sizeof (Elf32_External_Rela);
|
Line 1325... |
Line 1322... |
|
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
|
|
|
if (!elf_hash_table (info)->dynamic_sections_created
|
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.refcount = 0;
|
h->got.offset = (bfd_vma) -1;
|
h->got.offset = (bfd_vma) -1;
|
h->plt.refcount = 0;
|
h->plt.refcount = 0;
|
h->plt.offset = (bfd_vma) -1;
|
h->plt.offset = (bfd_vma) -1;
|
}
|
}
|
else if (h->got.refcount > 0)
|
else if (h->got.refcount > 0)
|
{
|
{
|
|
bfd_boolean dyn;
|
|
|
/* Make sure this symbol is output as a dynamic symbol. */
|
/* Make sure this symbol is output as a dynamic symbol. */
|
if (h->dynindx == -1)
|
if (h->dynindx == -1)
|
{
|
{
|
if (!bfd_elf_link_record_dynamic_symbol (info, h))
|
if (!bfd_elf_link_record_dynamic_symbol (info, h))
|
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
|
dyn = elf_hash_table (info)->dynamic_sections_created;
|
/* Allocate space in the .got and .rela.got sections. */
|
/* Allocate space in the .got and .rela.got sections. */
|
|
if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|
|
&& (info->shared
|
|
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
|
|
{
|
sgot->size += 4;
|
sgot->size += 4;
|
srelgot->size += sizeof (Elf32_External_Rela);
|
srelgot->size += sizeof (Elf32_External_Rela);
|
}
|
}
|
|
}
|
|
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
/* Relocate an VAX ELF section. */
|
/* Relocate an VAX ELF section. */
|
Line 1429... |
Line 1435... |
|
|
if ((h->root.type == bfd_link_hash_defined
|
if ((h->root.type == bfd_link_hash_defined
|
|| h->root.type == bfd_link_hash_defweak)
|
|| h->root.type == bfd_link_hash_defweak)
|
&& ((r_type == R_VAX_PLT32
|
&& ((r_type == R_VAX_PLT32
|
&& h->plt.offset != (bfd_vma) -1
|
&& h->plt.offset != (bfd_vma) -1
|
|
&& !h->forced_local
|
&& elf_hash_table (info)->dynamic_sections_created)
|
&& elf_hash_table (info)->dynamic_sections_created)
|
|| (r_type == R_VAX_GOT32
|
|| (r_type == R_VAX_GOT32
|
&& strcmp (h->root.root.string,
|
&& h->got.offset != (bfd_vma) -1
|
"_GLOBAL_OFFSET_TABLE_") != 0
|
&& !h->forced_local
|
&& elf_hash_table (info)->dynamic_sections_created
|
&& elf_hash_table (info)->dynamic_sections_created
|
&& (! info->shared
|
&& (! info->shared
|
|| (! info->symbolic && h->dynindx != -1)
|
|| (! info->symbolic && h->dynindx != -1)
|
|| !h->def_regular))
|
|| !h->def_regular))
|
|| (info->shared
|
|| (info->shared
|
Line 1450... |
Line 1457... |
|
|
|| ((input_section->flags & SEC_DEBUGGING) != 0
|
|| ((input_section->flags & SEC_DEBUGGING) != 0
|
&& h->def_dynamic))
|
&& h->def_dynamic))
|
&& (r_type == R_VAX_8
|
&& (r_type == R_VAX_8
|
|| r_type == R_VAX_16
|
|| r_type == R_VAX_16
|
|| r_type == R_VAX_32
|
|| r_type == R_VAX_32))))
|
|| r_type == R_VAX_PC8
|
|
|| r_type == R_VAX_PC16
|
|
|| r_type == R_VAX_PC32))))
|
|
/* In these cases, we don't need the relocation
|
/* In these cases, we don't need the relocation
|
value. We check specially because in some
|
value. We check specially because in some
|
obscure cases sec->output_section will be NULL. */
|
obscure cases sec->output_section will be NULL. */
|
relocation = 0;
|
relocation = 0;
|
}
|
}
|
Line 1479... |
Line 1483... |
switch (r_type)
|
switch (r_type)
|
{
|
{
|
case R_VAX_GOT32:
|
case R_VAX_GOT32:
|
/* Relocation is to the address of the entry for this symbol
|
/* Relocation is to the address of the entry for this symbol
|
in the global offset table. */
|
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;
|
break;
|
|
|
/* Relocation is the offset of the entry for this symbol in
|
/* Relocation is the offset of the entry for this symbol in
|
the global offset table. */
|
the global offset table. */
|
|
|
{
|
{
|
|
bfd_boolean dyn;
|
bfd_vma off;
|
bfd_vma off;
|
|
|
if (sgot == NULL)
|
if (sgot == NULL)
|
{
|
{
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
sgot = bfd_get_section_by_name (dynobj, ".got");
|
Line 1499... |
Line 1507... |
BFD_ASSERT (h != NULL);
|
BFD_ASSERT (h != NULL);
|
off = h->got.offset;
|
off = h->got.offset;
|
BFD_ASSERT (off != (bfd_vma) -1);
|
BFD_ASSERT (off != (bfd_vma) -1);
|
BFD_ASSERT (off < sgot->size);
|
BFD_ASSERT (off < sgot->size);
|
|
|
if (info->shared
|
dyn = elf_hash_table (info)->dynamic_sections_created;
|
&& h->dynindx == -1
|
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|
&& h->def_regular)
|
|| (info->shared
|
|
&& SYMBOL_REFERENCES_LOCAL (info, h)))
|
{
|
{
|
/* The symbol was forced to be local
|
/* The symbol was forced to be local
|
because of a version file.. We must initialize
|
because of a version file.. We must initialize
|
this entry in the global offset table. Since
|
this entry in the global offset table. Since
|
the offset must always be a multiple of 4, we
|
the offset must always be a multiple of 4, we
|
Line 1535... |
Line 1544... |
contents[rel->r_offset - 1] |= 0x10;
|
contents[rel->r_offset - 1] |= 0x10;
|
relocation += sgot->output_section->vma;
|
relocation += sgot->output_section->vma;
|
}
|
}
|
break;
|
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:
|
case R_VAX_PLT32:
|
/* Relocation is to the entry for this symbol in the
|
/* Relocation is to the entry for this symbol in the
|
procedure linkage table. */
|
procedure linkage table. */
|
|
|
/* Resolve a PLTxx reloc against a local symbol directly,
|
/* Resolve a PLTxx reloc against a local symbol directly,
|
without using the procedure linkage table. */
|
without using the procedure linkage table. */
|
if (h == NULL)
|
if (h == NULL
|
|
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
|
|
|| h->forced_local)
|
break;
|
break;
|
|
|
if (h->plt.offset == (bfd_vma) -1
|
if (h->plt.offset == (bfd_vma) -1
|
|| !elf_hash_table (info)->dynamic_sections_created)
|
|| !elf_hash_table (info)->dynamic_sections_created)
|
{
|
{
|
Line 1594... |
Line 1613... |
|
|
break;
|
break;
|
|
|
case R_VAX_PC8:
|
case R_VAX_PC8:
|
case R_VAX_PC16:
|
case R_VAX_PC16:
|
case R_VAX_PC32:
|
r_vax_pc32_shared:
|
if (h == NULL)
|
if (h == NULL
|
|
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
|
|
|| h->forced_local)
|
break;
|
break;
|
/* Fall through. */
|
/* Fall through. */
|
case R_VAX_8:
|
case R_VAX_8:
|
case R_VAX_16:
|
case R_VAX_16:
|
case R_VAX_32:
|
case R_VAX_32:
|
Line 1620... |
Line 1641... |
/* When generating a shared object, these relocations
|
/* When generating a shared object, these relocations
|
are copied into the output file to be resolved at run
|
are copied into the output file to be resolved at run
|
time. */
|
time. */
|
if (sreloc == NULL)
|
if (sreloc == NULL)
|
{
|
{
|
const char *name;
|
sreloc = _bfd_elf_get_dynamic_reloc_section
|
|
(input_bfd, input_section, /*rela?*/ TRUE);
|
name = (bfd_elf_string_from_elf_section
|
if (sreloc == NULL)
|
(input_bfd,
|
|
elf_elfheader (input_bfd)->e_shstrndx,
|
|
elf_section_data (input_section)->rel_hdr.sh_name));
|
|
if (name == NULL)
|
|
return FALSE;
|
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;
|
skip = FALSE;
|
relocate = FALSE;
|
relocate = FALSE;
|
|
|
Line 2066... |
Line 2075... |
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
|
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
|
|
|
return TRUE;
|
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_SYM bfd_elf32_vax_vec
|
#define TARGET_LITTLE_NAME "elf32-vax"
|
#define TARGET_LITTLE_NAME "elf32-vax"
|
#define ELF_MACHINE_CODE EM_VAX
|
#define ELF_MACHINE_CODE EM_VAX
|
#define ELF_MAXPAGESIZE 0x1000
|
#define ELF_MAXPAGESIZE 0x1000
|
|
|
Line 2088... |
Line 2120... |
#define elf_backend_relocate_section elf_vax_relocate_section
|
#define elf_backend_relocate_section elf_vax_relocate_section
|
#define elf_backend_finish_dynamic_symbol \
|
#define elf_backend_finish_dynamic_symbol \
|
elf_vax_finish_dynamic_symbol
|
elf_vax_finish_dynamic_symbol
|
#define elf_backend_finish_dynamic_sections \
|
#define elf_backend_finish_dynamic_sections \
|
elf_vax_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_mark_hook elf_vax_gc_mark_hook
|
#define elf_backend_gc_sweep_hook elf_vax_gc_sweep_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 \
|
#define bfd_elf32_bfd_merge_private_bfd_data \
|
elf32_vax_merge_private_bfd_data
|
elf32_vax_merge_private_bfd_data
|
#define bfd_elf32_bfd_set_private_flags \
|
#define bfd_elf32_bfd_set_private_flags \
|
elf32_vax_set_private_flags
|
elf32_vax_set_private_flags
|
#define bfd_elf32_bfd_print_private_bfd_data \
|
#define bfd_elf32_bfd_print_private_bfd_data \
|