/* Alpha specific support for 64-bit ELF
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@tamu.edu>.
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. */
+
/* We need a published ABI spec for this. Until one comes out, don't
assume this'll remain unchanged forever. */
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
\f
+
+/* Used to implement multiple .got subsections. */
+struct alpha_elf_got_entry
+{
+ struct alpha_elf_got_entry *next;
+
+ /* Which .got subsection? */
+ bfd *gotobj;
+
+ /* The addend in effect for this entry. */
+ bfd_vma addend;
+
+ /* The .got offset for this entry. */
+ int got_offset;
+
+ /* The .plt offset for this entry. */
+ int plt_offset;
+
+ /* How many references to this entry? */
+ int use_count;
+
+ /* The relocation type of this entry. */
+ unsigned char reloc_type;
+
+ /* How a LITERAL is used. */
+ unsigned char flags;
+
+ /* Have we initialized the dynamic relocation for this entry? */
+ unsigned char reloc_done;
+
+ /* Have we adjusted this entry for SEC_MERGE? */
+ unsigned char reloc_xlated;
+};
+
+struct alpha_elf_reloc_entry
+{
+ struct alpha_elf_reloc_entry *next;
+
+ /* Which .reloc section? */
+ asection *srel;
+
+ /* What kind of relocation? */
+ unsigned int rtype;
+
+ /* Is this against read-only section? */
+ unsigned int reltext : 1;
+
+ /* How many did we find? */
+ unsigned long count;
+};
+
struct alpha_elf_link_hash_entry
{
struct elf_link_hash_entry root;
#define ALPHA_ELF_LINK_HASH_TLS_IE 0x80
/* Used to implement multiple .got subsections. */
- struct alpha_elf_got_entry
- {
- struct alpha_elf_got_entry *next;
-
- /* Which .got subsection? */
- bfd *gotobj;
-
- /* The addend in effect for this entry. */
- bfd_vma addend;
-
- /* The .got offset for this entry. */
- int got_offset;
-
- /* The .plt offset for this entry. */
- int plt_offset;
-
- /* How many references to this entry? */
- int use_count;
-
- /* The relocation type of this entry. */
- unsigned char reloc_type;
-
- /* How a LITERAL is used. */
- unsigned char flags;
-
- /* Have we initialized the dynamic relocation for this entry? */
- unsigned char reloc_done;
-
- /* Have we adjusted this entry for SEC_MERGE? */
- unsigned char reloc_xlated;
- } *got_entries;
+ struct alpha_elf_got_entry *got_entries;
/* Used to count non-got, non-plt relocations for delayed sizing
of relocation sections. */
- struct alpha_elf_reloc_entry
- {
- struct alpha_elf_reloc_entry *next;
-
- /* Which .reloc section? */
- asection *srel;
-
- /* What kind of relocation? */
- unsigned int rtype;
-
- /* Is this against read-only section? */
- unsigned int reltext : 1;
-
- /* How many did we find? */
- unsigned long count;
- } *reloc_entries;
+ struct alpha_elf_reloc_entry *reloc_entries;
};
/* Alpha ELF linker hash table. */
/* The head of a list of .got subsections linked through
alpha_elf_tdata(abfd)->got_link_next. */
bfd *got_list;
+
+ /* The most recent relax pass that we've seen. The GOTs
+ should be regenerated if this doesn't match. */
+ int relax_trip;
};
/* Look up an entry in a Alpha ELF linker hash table. */
/* Get the Alpha ELF linker hash table from a link_info structure. */
#define alpha_elf_hash_table(p) \
- ((struct alpha_elf_link_hash_table *) ((p)->hash))
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == ALPHA_ELF_DATA ? ((struct alpha_elf_link_hash_table *) ((p)->hash)) : NULL)
/* Get the object's symbols as our own entry type. */
if (ret == (struct alpha_elf_link_hash_table *) NULL)
return NULL;
- if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
- elf64_alpha_link_hash_newfunc))
+ if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
+ elf64_alpha_link_hash_newfunc,
+ sizeof (struct alpha_elf_link_hash_entry),
+ ALPHA_ELF_DATA))
{
free (ret);
return NULL;
#define alpha_elf_tdata(abfd) \
((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
+#define is_alpha_elf(bfd) \
+ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+ && elf_tdata (bfd) != NULL \
+ && elf_object_id (bfd) == ALPHA_ELF_DATA)
+
static bfd_boolean
elf64_alpha_mkobject (bfd *abfd)
{
- bfd_size_type amt = sizeof (struct alpha_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 alpha_elf_obj_tdata),
+ ALPHA_ELF_DATA);
}
static bfd_boolean
from smaller values. Start with zero, widen, *then* decrement. */
#define MINUS_ONE (((bfd_vma)0) - 1)
+
#define SKIP_HOWTO(N) \
- HOWTO(N, 0, 0, 0, 0, 0, 0, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0)
+ HOWTO(N, 0, 0, 0, 0, 0, complain_overflow_dont, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0)
static reloc_howto_type elf64_alpha_howto_table[] =
{
return 0;
}
+static reloc_howto_type *
+elf64_alpha_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+
+ for (i = 0;
+ i < (sizeof (elf64_alpha_howto_table)
+ / sizeof (elf64_alpha_howto_table[0]));
+ i++)
+ if (elf64_alpha_howto_table[i].name != NULL
+ && strcasecmp (elf64_alpha_howto_table[i].name, r_name) == 0)
+ return &elf64_alpha_howto_table[i];
+
+ return NULL;
+}
+
/* Given an Alpha ELF reloc type, fill in an arelent structure. */
static void
flagword flags;
asection *s;
+ if (! is_alpha_elf (abfd))
+ return FALSE;
+
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
asection *s;
flagword flags;
struct elf_link_hash_entry *h;
- struct bfd_link_hash_entry *bh;
+
+ if (! is_alpha_elf (abfd))
+ return FALSE;
/* We need to create .plt, .rela.plt, .got, and .rela.got sections. */
/* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
.plt section. */
- bh = NULL;
- if (! (_bfd_generic_link_add_one_symbol
- (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s,
- (bfd_vma) 0, (const char *) NULL, FALSE,
- get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
- h = (struct elf_link_hash_entry *) bh;
- h->def_regular = 1;
- h->type = STT_OBJECT;
-
- if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ h = _bfd_elf_define_linkage_sym (abfd, info, s,
+ "_PROCEDURE_LINKAGE_TABLE_");
+ elf_hash_table (info)->hplt = h;
+ if (h == NULL)
return FALSE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
dynobj's .got section. We don't do this in the linker script
because we don't want to define the symbol if we are not creating
a global offset table. */
- bh = NULL;
- if (!(_bfd_generic_link_add_one_symbol
- (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL,
- alpha_elf_tdata(abfd)->got, (bfd_vma) 0, (const char *) NULL,
- FALSE, get_elf_backend_data (abfd)->collect, &bh)))
- return FALSE;
- h = (struct elf_link_hash_entry *) bh;
- h->def_regular = 1;
- h->type = STT_OBJECT;
-
- if (info->shared
- && ! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
-
+ h = _bfd_elf_define_linkage_sym (abfd, info, alpha_elf_tdata(abfd)->got,
+ "_GLOBAL_OFFSET_TABLE_");
elf_hash_table (info)->hgot = h;
+ if (h == NULL)
+ return FALSE;
return TRUE;
}
{
bfd *dynobj;
asection *sreloc;
- const char *rel_sec_name;
Elf_Internal_Shdr *symtab_hdr;
struct alpha_elf_link_hash_entry **sym_hashes;
const Elf_Internal_Rela *rel, *relend;
if ((sec->flags & SEC_ALLOC) == 0)
return TRUE;
- dynobj = elf_hash_table(info)->dynobj;
+ BFD_ASSERT (is_alpha_elf (abfd));
+
+ dynobj = elf_hash_table (info)->dynobj;
if (dynobj == NULL)
- elf_hash_table(info)->dynobj = dynobj = abfd;
+ elf_hash_table (info)->dynobj = dynobj = abfd;
sreloc = NULL;
- rel_sec_name = NULL;
- symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
- sym_hashes = alpha_elf_sym_hashes(abfd);
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = alpha_elf_sym_hashes (abfd);
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; ++rel)
if (need & NEED_DYNREL)
{
- if (rel_sec_name == NULL)
- {
- rel_sec_name = (bfd_elf_string_from_elf_section
- (abfd, elf_elfheader(abfd)->e_shstrndx,
- elf_section_data(sec)->rel_hdr.sh_name));
- if (rel_sec_name == NULL)
- return FALSE;
-
- BFD_ASSERT (strncmp (rel_sec_name, ".rela", 5) == 0
- && strcmp (bfd_get_section_name (abfd, sec),
- rel_sec_name+5) == 0);
- }
-
/* We need to create the section here now whether we eventually
use it or not so that it gets mapped to an output section by
- the linker. If not used, we'll kill it in
- size_dynamic_sections. */
+ the linker. If not used, we'll kill it in size_dynamic_sections. */
if (sreloc == NULL)
{
- sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 3, abfd, /*rela?*/ TRUE);
+
if (sreloc == NULL)
- {
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED | SEC_READONLY);
- if (sec->flags & SEC_ALLOC)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_with_flags (dynobj,
- rel_sec_name,
- flags);
- if (sreloc == NULL
- || !bfd_set_section_alignment (dynobj, sreloc, 3))
- return FALSE;
- }
+ return FALSE;
}
if (h)
return TRUE;
}
+/* Record STO_ALPHA_NOPV and STO_ALPHA_STD_GPLOAD. */
+
+static void
+elf64_alpha_merge_symbol_attribute (struct elf_link_hash_entry *h,
+ const Elf_Internal_Sym *isym,
+ bfd_boolean definition,
+ bfd_boolean dynamic)
+{
+ if (!dynamic && definition)
+ h->other = ((h->other & ELF_ST_VISIBILITY (-1))
+ | (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
+}
+
/* Symbol versioning can create new symbols, and make our old symbols
indirect to the new ones. Consolidate the got and reloc information
in these situations. */
static void
elf64_alpha_calc_got_offsets (struct bfd_link_info *info)
{
- bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
+ bfd *i, *got_list;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return;
+ got_list = htab->got_list;
/* First, zero out the .got sizes, as we may be recalculating the
.got after optimizing it. */
alpha_elf_tdata(i)->got->size = 0;
/* Next, fill in the offsets for all the global entries. */
- alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ alpha_elf_link_hash_traverse (htab,
elf64_alpha_calc_got_offsets_for_symbol,
NULL);
elf64_alpha_size_got_sections (struct bfd_link_info *info)
{
bfd *i, *got_list, *cur_got_obj = NULL;
- int something_changed = 0;
+ struct alpha_elf_link_hash_table * htab;
- got_list = alpha_elf_hash_table (info)->got_list;
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+ got_list = htab->got_list;
/* On the first time through, pretend we have an existing got list
consisting of all of the input files. */
{
for (i = info->input_bfds; i ; i = i->link_next)
{
- bfd *this_got = alpha_elf_tdata (i)->gotobj;
+ bfd *this_got;
+
+ if (! is_alpha_elf (i))
+ continue;
+
+ this_got = alpha_elf_tdata (i)->gotobj;
if (this_got == NULL)
continue;
if (got_list == NULL)
return TRUE;
- alpha_elf_hash_table (info)->got_list = got_list;
-
- /* Force got offsets to be recalculated. */
- something_changed = 1;
+ htab->got_list = got_list;
}
cur_got_obj = got_list;
+ if (cur_got_obj == NULL)
+ return FALSE;
+
i = alpha_elf_tdata(cur_got_obj)->got_link_next;
while (i != NULL)
{
alpha_elf_tdata(i)->got->size = 0;
i = alpha_elf_tdata(i)->got_link_next;
alpha_elf_tdata(cur_got_obj)->got_link_next = i;
-
- something_changed = 1;
}
else
{
/* Once the gots have been merged, fill in the got offsets for
everything therein. */
- if (1 || something_changed)
- elf64_alpha_calc_got_offsets (info);
+ elf64_alpha_calc_got_offsets (info);
return TRUE;
}
return TRUE;
}
-/* Called from relax_section to rebuild the PLT in light of
- potential changes in the function's status. */
+/* Called from relax_section to rebuild the PLT in light of potential changes
+ in the function's status. */
-static bfd_boolean
+static void
elf64_alpha_size_plt_section (struct bfd_link_info *info)
{
asection *splt, *spltrel, *sgotplt;
unsigned long entries;
bfd *dynobj;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return;
dynobj = elf_hash_table(info)->dynobj;
splt = bfd_get_section_by_name (dynobj, ".plt");
if (splt == NULL)
- return TRUE;
+ return;
splt->size = 0;
- alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ alpha_elf_link_hash_traverse (htab,
elf64_alpha_size_plt_section_1, splt);
/* Every plt entry requires a JMP_SLOT relocation. */
spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ entries = 0;
if (splt->size)
{
if (elf64_alpha_use_secureplt)
else
entries = (splt->size - OLD_PLT_HEADER_SIZE) / OLD_PLT_ENTRY_SIZE;
}
- else
- entries = 0;
spltrel->size = entries * sizeof (Elf64_External_Rela);
/* When using the secureplt, we need two words somewhere in the data
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
sgotplt->size = entries ? 16 : 0;
}
-
- return TRUE;
}
static bfd_boolean
struct bfd_link_info *info)
{
bfd *i;
+ struct alpha_elf_link_hash_table * htab;
if (info->relocatable)
return TRUE;
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
/* First, take care of the indirect symbols created by versioning. */
- alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
- elf64_alpha_merge_ind_symbols,
+ alpha_elf_link_hash_traverse (htab, elf64_alpha_merge_ind_symbols,
NULL);
if (!elf64_alpha_size_got_sections (info))
return FALSE;
/* Allocate space for all of the .got subsections. */
- i = alpha_elf_hash_table (info)->got_list;
+ i = htab->got_list;
for ( ; i ; i = alpha_elf_tdata(i)->got_link_next)
{
asection *s = alpha_elf_tdata(i)->got;
/* Set the sizes of the dynamic relocation sections. */
-static bfd_boolean
+static void
elf64_alpha_size_rela_got_section (struct bfd_link_info *info)
{
unsigned long entries;
bfd *i, *dynobj;
asection *srel;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return;
/* Shared libraries often require RELATIVE relocs, and some relocs
require attention for the main application as well. */
entries = 0;
- for (i = alpha_elf_hash_table(info)->got_list;
+ for (i = htab->got_list;
i ; i = alpha_elf_tdata(i)->got_link_next)
{
bfd *j;
if (!srel)
{
BFD_ASSERT (entries == 0);
- return TRUE;
+ return;
}
srel->size = sizeof (Elf64_External_Rela) * entries;
/* Now do the non-local symbols. */
- alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ alpha_elf_link_hash_traverse (htab,
elf64_alpha_size_rela_got_1, info);
-
- return TRUE;
}
/* Set the sizes of the dynamic sections. */
bfd *dynobj;
asection *s;
bfd_boolean relplt;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
dynobj = elf_hash_table(info)->dynobj;
BFD_ASSERT(dynobj != NULL);
symbols need dynamic relocation entries and which don't. We've
collected information in check_relocs that we can now apply to
size the dynamic relocation sections. */
- alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ alpha_elf_link_hash_traverse (htab,
elf64_alpha_calc_dynrel_sizes, info);
elf64_alpha_size_rela_got_section (info);
for (s = dynobj->sections; s != NULL; s = s->next)
{
const char *name;
- bfd_boolean strip;
if (!(s->flags & SEC_LINKER_CREATED))
continue;
of the dynobj section names depend upon the input files. */
name = bfd_get_section_name (dynobj, s);
- /* If we don't need this section, strip it from the output file.
- This is to handle .rela.bss and .rela.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 = FALSE;
-
- if (strncmp (name, ".rela", 5) == 0)
+ if (CONST_STRNEQ (name, ".rela"))
{
- strip = (s->size == 0);
-
- if (!strip)
+ if (s->size != 0)
{
- if (strcmp(name, ".rela.plt") == 0)
+ if (strcmp (name, ".rela.plt") == 0)
relplt = TRUE;
/* We use the reloc_count field as a counter if we need
s->reloc_count = 0;
}
}
- else if (strcmp (name, ".plt") != 0)
+ else if (! CONST_STRNEQ (name, ".got")
+ && strcmp (name, ".plt") != 0
+ && strcmp (name, ".dynbss") != 0)
{
/* It's not one of our dynamic sections, so don't allocate space. */
continue;
}
- if (strip)
- s->flags |= SEC_EXCLUDE;
- else
+ if (s->size == 0)
+ {
+ /* If we don't need this section, strip it from the output file.
+ This is to handle .rela.bss and .rela.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. */
+ s->flags |= SEC_EXCLUDE;
+ }
+ else if ((s->flags & SEC_HAS_CONTENTS) != 0)
{
/* Allocate memory for the section contents. */
s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
- if (s->contents == NULL && s->size != 0)
+ if (s->contents == NULL)
return FALSE;
}
}
/* We've now determined that we can skip an initial gp load. Verify
that the call and the target use the same gp. */
- if (info->link_info->hash->creator != info->tsec->owner->xvec
+ if (info->link_info->output_bfd->xvec != info->tsec->owner->xvec
|| info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)
return 0;
Elf_Internal_Sym *isymbuf = NULL;
struct alpha_elf_got_entry **local_got_entries;
struct alpha_relax_info info;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (link_info);
+ if (htab == NULL)
+ return FALSE;
- /* We are not currently changing any sizes, so only one pass. */
+ /* There's nothing to change, yet. */
*again = FALSE;
if (link_info->relocatable
|| sec->reloc_count == 0)
return TRUE;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ BFD_ASSERT (is_alpha_elf (abfd));
+
+ /* Make sure our GOT and PLT tables are up-to-date. */
+ if (htab->relax_trip != link_info->relax_trip)
+ {
+ htab->relax_trip = link_info->relax_trip;
+
+ /* This should never fail after the initial round, since the only
+ error is GOT overflow, and relaxation only shrinks the table. */
+ if (!elf64_alpha_size_got_sections (link_info))
+ abort ();
+ if (elf_hash_table (link_info)->dynamic_sections_created)
+ {
+ elf64_alpha_size_plt_section (link_info);
+ elf64_alpha_size_rela_got_section (link_info);
+ }
+ }
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
/* Load the relocations for this section. */
}
}
- if (!elf64_alpha_size_plt_section (link_info))
- return FALSE;
- if (!elf64_alpha_size_got_sections (link_info))
- return FALSE;
- if (!elf64_alpha_size_rela_got_section (link_info))
- return FALSE;
-
if (isymbuf != NULL
&& symtab_hdr->contents != (unsigned char *) isymbuf)
{
unsigned long symtab_hdr_sh_info;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ struct elf_link_hash_entry **sym_hashes;
bfd_boolean ret_val = TRUE;
- symtab_hdr_sh_info = elf_tdata (input_bfd)->symtab_hdr.sh_info;
+ symtab_hdr_sh_info = elf_symtab_hdr (input_bfd).sh_info;
+ sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
for (rel = relocs; rel < relend; rel++)
asection *sec;
unsigned long r_type;
- r_type = ELF64_R_TYPE(rel->r_info);
+ r_type = ELF64_R_TYPE (rel->r_info);
if (r_type >= R_ALPHA_max)
{
(*_bfd_error_handler)
continue;
}
- r_symndx = ELF64_R_SYM(rel->r_info);
-
/* The symbol associated with GPDISP and LITUSE is
immaterial. Only the addend is significant. */
if (r_type == R_ALPHA_GPDISP || r_type == R_ALPHA_LITUSE)
continue;
+ r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr_sh_info)
{
sym = local_syms + r_symndx;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
- {
- sec = local_sections[r_symndx];
- rel->r_addend += sec->output_offset + sym->st_value;
- }
+ sec = local_sections[r_symndx];
+ }
+ else
+ {
+ struct elf_link_hash_entry *h;
+
+ 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;
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ continue;
+
+ sym = NULL;
+ sec = h->root.u.def.section;
}
+
+ 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. */
+ _bfd_clear_contents (elf64_alpha_howto_table + r_type,
+ input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += sec->output_offset;
}
return ret_val;
struct alpha_elf_got_entry **local_got_entries;
bfd_boolean ret_val;
+ BFD_ASSERT (is_alpha_elf (input_bfd));
+
/* Handle relocatable links with a smaller loop. */
if (info->relocatable)
return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
ret_val = TRUE;
- symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ symtab_hdr = &elf_symtab_hdr (input_bfd);
dynobj = elf_hash_table (info)->dynobj;
if (dynobj)
gotent = h->got_entries;
}
+ 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;
+ }
+
addend = rel->r_addend;
value += addend;
goto default_reloc;
case R_ALPHA_GPREL32:
- /* If the target section was a removed linkonce section,
- r_symndx will be zero. In this case, assume that the
- switch will not be used, so don't fill it in. If we
- do nothing here, we'll get relocation truncated messages,
- due to the placement of the application above 4GB. */
- if (r_symndx == 0)
- {
- r = bfd_reloc_ok;
- break;
- }
- /* FALLTHRU */
-
case R_ALPHA_GPREL16:
case R_ALPHA_GPRELLOW:
if (dynamic_symbol_p)
/* Mark some specially defined symbols as absolute. */
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)
+ || h == elf_hash_table (info)->hgot
+ || h == elf_hash_table (info)->hplt)
sym->st_shndx = SHN_ABS;
return TRUE;
const struct ecoff_debug_swap *swap
= get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
HDRR *symhdr = &debug.symbolic_header;
- PTR mdebug_handle = NULL;
+ void * mdebug_handle = NULL;
+ struct alpha_elf_link_hash_table * htab;
+
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
/* Go through the sections and collect the mdebug information. */
mdebug_sec = NULL;
input_section = p->u.indirect.section;
input_bfd = input_section->owner;
- if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
- || (get_elf_backend_data (input_bfd)
- ->elf_backend_ecoff_debug_swap) == NULL)
- {
- /* I don't know what a non ALPHA ELF bfd would be
- doing with a .mdebug section, but I don't really
- want to deal with it. */
- continue;
- }
+ if (! is_alpha_elf (input_bfd))
+ /* I don't know what a non ALPHA ELF bfd would be
+ doing with a .mdebug section, but I don't really
+ want to deal with it. */
+ continue;
input_swap = (get_elf_backend_data (input_bfd)
->elf_backend_ecoff_debug_swap);
interesting information, try to find the symbol in
the linker global hash table and save the information
for the output external symbols. */
- eraw_src = input_debug.external_ext;
+ eraw_src = (char *) input_debug.external_ext;
eraw_end = (eraw_src
+ (input_debug.symbolic_header.iextMax
* input_swap->external_ext_size));
continue;
name = input_debug.ssext + ext.asym.iss;
- h = alpha_elf_link_hash_lookup (alpha_elf_hash_table (info),
- name, FALSE, FALSE, TRUE);
+ h = alpha_elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE);
if (h == NULL || h->esym.ifd != -2)
continue;
/* The .got subsections... */
{
bfd *i, *dynobj = elf_hash_table(info)->dynobj;
- for (i = alpha_elf_hash_table(info)->got_list;
+ for (i = htab->got_list;
i != NULL;
i = alpha_elf_tdata(i)->got_link_next)
{
}
}
\f
-static struct bfd_elf_special_section const elf64_alpha_special_sections[] =
+static const struct bfd_elf_special_section elf64_alpha_special_sections[] =
{
- { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
- { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
+ { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
+ { NULL, 0, 0, 0, 0 }
};
-static const struct bfd_elf_special_section *
-elf64_alpha_get_sec_type_attr (bfd *abfd, asection *sec)
-{
- const struct bfd_elf_special_section const *ssect;
-
- /* See if this is one of the special sections. */
- if (sec->name == NULL)
- return NULL;
-
- ssect = _bfd_elf_get_special_section (sec->name,
- elf64_alpha_special_sections,
- sec->use_rela_p);
- if (ssect != NULL)
- return ssect;
-
- return _bfd_elf_get_sec_type_attr (abfd, sec);
-}
-
/* ECOFF swapping routines. These are used when dealing with the
.mdebug section, which is in the ECOFF debugging format. Copied
from elf32-mips.c. */
ELFCLASS64, EV_CURRENT,
bfd_elf64_write_out_phdrs,
bfd_elf64_write_shdrs_and_ehdr,
+ bfd_elf64_checksum_contents,
bfd_elf64_write_relocs,
bfd_elf64_swap_symbol_in,
bfd_elf64_swap_symbol_out,
#define ELF_ARCH bfd_arch_alpha
#define ELF_MACHINE_CODE EM_ALPHA
#define ELF_MAXPAGESIZE 0x10000
+#define ELF_COMMONPAGESIZE 0x2000
#define bfd_elf64_bfd_link_hash_table_create \
elf64_alpha_bfd_link_hash_table_create
#define bfd_elf64_bfd_reloc_type_lookup \
elf64_alpha_bfd_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+ elf64_alpha_bfd_reloc_name_lookup
#define elf_info_to_howto \
elf64_alpha_info_to_howto
#define elf_backend_add_symbol_hook \
elf64_alpha_add_symbol_hook
+#define elf_backend_relocs_compatible \
+ _bfd_elf_relocs_compatible
#define elf_backend_check_relocs \
elf64_alpha_check_relocs
#define elf_backend_create_dynamic_sections \
elf64_alpha_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
elf64_alpha_adjust_dynamic_symbol
+#define elf_backend_merge_symbol_attribute \
+ elf64_alpha_merge_symbol_attribute
#define elf_backend_always_size_sections \
elf64_alpha_always_size_sections
#define elf_backend_size_dynamic_sections \
elf64_alpha_size_dynamic_sections
+#define elf_backend_omit_section_dynsym \
+ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_relocate_section \
elf64_alpha_relocate_section
#define elf_backend_finish_dynamic_symbol \
#define elf_backend_size_info \
alpha_elf_size_info
-#define elf_backend_get_sec_type_attr \
- elf64_alpha_get_sec_type_attr
+#define elf_backend_special_sections \
+ elf64_alpha_special_sections
/* A few constants that determine how the .plt section is set up. */
#define elf_backend_want_got_plt 0
#define TARGET_LITTLE_SYM bfd_elf64_alpha_freebsd_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf64-alpha-freebsd"
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_FREEBSD
/* The kernel recognizes executables as valid only if they carry a
"FreeBSD" label in the ELF header. So we put this label on all
i_ehdrp = elf_elfheader (abfd);
/* Put an ABI label supported by FreeBSD >= 4.1. */
- i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
+ i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
#ifdef OLD_FREEBSD_ABI_LABEL
/* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);