/* Alpha specific support for 64-bit ELF
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@tamu.edu>.
This file is part of BFD, the Binary File Descriptor library.
#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. */
/* 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 (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
elf64_alpha_link_hash_newfunc,
- sizeof (struct alpha_elf_link_hash_entry)))
+ sizeof (struct alpha_elf_link_hash_entry),
+ ALPHA_ELF_DATA))
{
free (ret);
return NULL;
#define is_alpha_elf(bfd) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
&& elf_tdata (bfd) != NULL \
- && elf_object_id (bfd) == ALPHA_ELF_TDATA)
+ && elf_object_id (bfd) == ALPHA_ELF_DATA)
static bfd_boolean
elf64_alpha_mkobject (bfd *abfd)
{
return bfd_elf_allocate_object (abfd, sizeof (struct alpha_elf_obj_tdata),
- ALPHA_ELF_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[] =
{
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"REFLONG", /* name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"REFQUAD", /* name */
FALSE, /* partial_inplace */
MINUS_ONE, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GPREL32", /* name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"ELF_LITERAL", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"BRADDR", /* name */
FALSE, /* partial_inplace */
0x1fffff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"HINT", /* name */
FALSE, /* partial_inplace */
0x3fff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"SREL16", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"SREL32", /* name */
FALSE, /* partial_inplace */
0xffffffff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"SREL64", /* name */
FALSE, /* partial_inplace */
MINUS_ONE, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GPRELHIGH", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GPRELLOW", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GPREL16", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
TRUE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"BRSGP", /* name */
FALSE, /* partial_inplace */
0x1fffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TLSGD", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TLSLDM", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"DTPMOD64", /* name */
FALSE, /* partial_inplace */
MINUS_ONE, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GOTDTPREL", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"DTPREL64", /* name */
FALSE, /* partial_inplace */
MINUS_ONE, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"DTPRELHI", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"DTPRELLO", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"DTPREL16", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"GOTTPREL", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TPREL64", /* name */
FALSE, /* partial_inplace */
MINUS_ONE, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TPRELHI", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TPRELLO", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- 0, /* special_function */
+ bfd_elf_generic_reloc, /* special_function */
"TPREL16", /* name */
FALSE, /* partial_inplace */
0xffff, /* src_mask */
{
asection *msec;
- if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
+ section, symbols, offset,
filename_ptr, functionname_ptr,
line_ptr, 0,
&elf_tdata (abfd)->dwarf2_find_line_info))
bfd_boolean strip;
asection *sec, *output_section;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
if (h->root.indx == -2)
strip = FALSE;
else if ((h->root.def_dynamic
{
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;
elf_hash_table (info)->dynobj = dynobj = abfd;
sreloc = NULL;
- rel_sec_name = NULL;
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = alpha_elf_sym_hashes (abfd);
case R_ALPHA_TLSLDM:
/* The symbol for a TLSLDM reloc is ignored. Collapse the
- reloc to the 0 symbol so that they all match. */
- r_symndx = 0;
+ reloc to the STN_UNDEF (0) symbol so that they all match. */
+ r_symndx = STN_UNDEF;
h = 0;
maybe_dynamic = FALSE;
/* FALLTHRU */
break;
case R_ALPHA_TPREL64:
- if (info->shared || maybe_dynamic)
+ if (info->shared && !info->pie)
+ {
+ info->flags |= DF_STATIC_TLS;
+ need = NEED_DYNREL;
+ }
+ else if (maybe_dynamic)
need = NEED_DYNREL;
- if (info->shared)
- info->flags |= DF_STATIC_TLS;
break;
}
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 (CONST_STRNEQ (rel_sec_name, ".rela")
- && 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;
}
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+elf64_alpha_gc_mark_hook (asection *sec, struct bfd_link_info *info,
+ Elf_Internal_Rela *rel,
+ struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)
+{
+ /* These relocations don't really reference a symbol. Instead we store
+ extra data in their addend slot. Ignore the symbol. */
+ switch (ELF64_R_TYPE (rel->r_info))
+ {
+ case R_ALPHA_LITUSE:
+ case R_ALPHA_GPDISP:
+ case R_ALPHA_HINT:
+ return NULL;
+ }
+
+ return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static bfd_boolean
+elf64_alpha_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
+ asection *sec, const Elf_Internal_Rela *relocs)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct alpha_elf_link_hash_entry **sym_hashes;
+ const Elf_Internal_Rela *rel, *relend;
+
+ if (info->relocatable)
+ return TRUE;
+
+ symtab_hdr = &elf_symtab_hdr (abfd);
+ sym_hashes = alpha_elf_sym_hashes (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ {
+ unsigned long r_symndx, r_type;
+ struct alpha_elf_link_hash_entry *h = NULL;
+ struct alpha_elf_got_entry *gotent;
+
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.root.type == bfd_link_hash_indirect
+ || h->root.root.type == bfd_link_hash_warning)
+ h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
+ }
+
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ case R_ALPHA_LITERAL:
+ /* ??? Ignore re-computation of gotent_flags. We're not
+ carrying a use-count for each bit in that mask. */
+
+ case R_ALPHA_TLSGD:
+ case R_ALPHA_GOTDTPREL:
+ case R_ALPHA_GOTTPREL:
+ /* Fetch the got entry from the tables. */
+ gotent = get_got_entry (abfd, h, r_type, r_symndx, rel->r_addend);
+
+ /* The got entry *must* exist, since we should have created it
+ before during check_relocs. Also note that get_got_entry
+ assumed this was going to be another use, and so incremented
+ the use count again. Thus the use count must be at least the
+ one real use and the "use" we just added. */
+ if (gotent == NULL || gotent->use_count < 2)
+ {
+ abort ();
+ return FALSE;
+ }
+ gotent->use_count -= 2;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
indirect to the new ones. Consolidate the got and reloc information
in these situations. */
-static bfd_boolean
-elf64_alpha_merge_ind_symbols (struct alpha_elf_link_hash_entry *hi,
- PTR dummy ATTRIBUTE_UNUSED)
+static void
+elf64_alpha_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
{
- struct alpha_elf_link_hash_entry *hs;
+ struct alpha_elf_link_hash_entry *hi
+ = (struct alpha_elf_link_hash_entry *) ind;
+ struct alpha_elf_link_hash_entry *hs
+ = (struct alpha_elf_link_hash_entry *) dir;
- if (hi->root.root.type != bfd_link_hash_indirect)
- return TRUE;
- hs = hi;
- do {
- hs = (struct alpha_elf_link_hash_entry *)hs->root.root.u.i.link;
- } while (hs->root.root.type == bfd_link_hash_indirect);
+ /* Do the merging in the superclass. */
+ _bfd_elf_link_hash_copy_indirect(info, dir, ind);
/* Merge the flags. Whee. */
-
hs->flags |= hi->flags;
+ /* ??? It's unclear to me what's really supposed to happen when
+ "merging" defweak and defined symbols, given that we don't
+ actually throw away the defweak. This more-or-less copies
+ the logic related to got and plt entries in the superclass. */
+ if (ind->root.type != bfd_link_hash_indirect)
+ return;
+
/* Merge the .got entries. Cannibalize the old symbol's list in
doing so, since we don't need it anymore. */
}
}
hi->reloc_entries = NULL;
-
- return TRUE;
}
/* Is it possible to merge two object file's .got tables? */
{
struct alpha_elf_got_entry *gotent;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
for (gotent = h->got_entries; gotent; gotent = gotent->next)
if (gotent->use_count > 0)
{
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;
+ 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. */
if (got_list == NULL)
return TRUE;
- alpha_elf_hash_table (info)->got_list = got_list;
+ htab->got_list = got_list;
}
cur_got_obj = got_list;
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");
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. */
struct bfd_link_info *info)
{
bfd *i;
+ struct alpha_elf_link_hash_table * htab;
if (info->relocatable)
return TRUE;
- /* 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,
- NULL);
+ htab = alpha_elf_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
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;
/* The number of dynamic relocations required by a static relocation. */
static int
-alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared)
+alpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared, int pie)
{
switch (r_type)
{
case R_ALPHA_TLSLDM:
return shared;
case R_ALPHA_LITERAL:
- case R_ALPHA_GOTTPREL:
return dynamic || shared;
+ case R_ALPHA_GOTTPREL:
+ return dynamic || (shared && !pie);
case R_ALPHA_GOTDTPREL:
return dynamic;
/* May appear in data sections. */
case R_ALPHA_REFLONG:
case R_ALPHA_REFQUAD:
- case R_ALPHA_TPREL64:
return dynamic || shared;
+ case R_ALPHA_TPREL64:
+ return dynamic || (shared && !pie);
/* Everything else is illegal. We'll issue an error during
relocate_section. */
struct alpha_elf_reloc_entry *relent;
unsigned long entries;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
/* If the symbol was defined as a common symbol in a regular object
file, and there was no definition in any dynamic object, then the
linker will have allocated space for the symbol in a common
for (relent = h->reloc_entries; relent; relent = relent->next)
{
entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
- info->shared);
+ info->shared, info->pie);
if (entries)
{
relent->srel->size +=
struct alpha_elf_got_entry *gotent;
unsigned long entries;
- if (h->root.root.type == bfd_link_hash_warning)
- h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
-
/* If we're using a plt for this symbol, then all of its relocations
for its got entries go into .rela.plt. */
if (h->root.needs_plt)
entries = 0;
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
if (gotent->use_count > 0)
- entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
- dynamic, info->shared);
+ entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type, dynamic,
+ info->shared, info->pie);
if (entries > 0)
{
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;
gotent ; gotent = gotent->next)
if (gotent->use_count > 0)
entries += (alpha_dynamic_entries_for_reloc
- (gotent->reloc_type, 0, info->shared));
+ (gotent->reloc_type, 0, info->shared, info->pie));
}
}
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);
}
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);
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;
+ if (!CONST_STRNEQ (name, ".got"))
+ s->flags |= SEC_EXCLUDE;
}
else if ((s->flags & SEC_HAS_CONTENTS) != 0)
{
return TRUE;
/* Can't use local-exec relocations in shared libraries. */
- if (r_type == R_ALPHA_GOTTPREL && info->link_info->shared)
+ if (r_type == R_ALPHA_GOTTPREL
+ && (info->link_info->shared && !info->link_info->pie))
return TRUE;
if (r_type == R_ALPHA_LITERAL)
/* 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_Rela *irel, bfd_boolean is_gd)
{
bfd_byte *pos[5];
- unsigned int insn;
+ unsigned int insn, tlsgd_reg;
Elf_Internal_Rela *gpdisp, *hint;
- bfd_boolean dynamic, use_gottprel, pos1_unusable;
+ bfd_boolean dynamic, use_gottprel;
unsigned long new_symndx;
dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
pos[2] = info->contents + irel[2].r_offset;
pos[3] = info->contents + gpdisp->r_offset;
pos[4] = pos[3] + gpdisp->r_addend;
- pos1_unusable = FALSE;
+
+ /* Beware of the compiler hoisting part of the sequence out a loop
+ and adjusting the destination register for the TLSGD insn. If this
+ happens, there will be a move into $16 before the JSR insn, so only
+ transformations of the first insn pair should use this register. */
+ tlsgd_reg = bfd_get_32 (info->abfd, pos[0]);
+ tlsgd_reg = (tlsgd_reg >> 21) & 31;
/* Generally, the positions are not allowed to be out of order, lest the
modified insn sequence have different register lifetimes. We can make
pos[0] = pos[1];
pos[1] = tmp;
}
- else if (pos[1] < pos[0])
- pos1_unusable = TRUE;
if (pos[1] >= pos[2] || pos[2] >= pos[3])
return TRUE;
as appropriate. */
use_gottprel = FALSE;
- new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
+ new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
+
switch (!dynamic && !info->link_info->shared)
{
case 1:
if (disp >= -0x8000 && disp < 0x8000)
{
- insn = (OP_LDA << 26) | (16 << 21) | (31 << 16);
+ insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (31 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
}
else if (disp >= -(bfd_signed_vma) 0x80000000
&& disp < (bfd_signed_vma) 0x7fff8000
- && !pos1_unusable)
+ && pos[0] + 4 == pos[1])
{
- insn = (OP_LDAH << 26) | (16 << 21) | (31 << 16);
+ insn = (OP_LDAH << 26) | (tlsgd_reg << 21) | (31 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
- insn = (OP_LDA << 26) | (16 << 21) | (16 << 16);
+ insn = (OP_LDA << 26) | (tlsgd_reg << 21) | (tlsgd_reg << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
irel[0].r_offset = pos[0] - info->contents;
default:
use_gottprel = TRUE;
- insn = (OP_LDQ << 26) | (16 << 21) | (29 << 16);
+ insn = (OP_LDQ << 26) | (tlsgd_reg << 21) | (29 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
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;
/* There's nothing to change, yet. */
*again = FALSE;
BFD_ASSERT (is_alpha_elf (abfd));
/* Make sure our GOT and PLT tables are up-to-date. */
- if (alpha_elf_hash_table(link_info)->relax_trip != link_info->relax_trip)
+ if (htab->relax_trip != link_info->relax_trip)
{
- alpha_elf_hash_table(link_info)->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. */
case R_ALPHA_TLSLDM:
/* The symbol for a TLSLDM reloc is ignored. Collapse the
- reloc to the 0 symbol so that they all match. */
- r_symndx = 0;
+ reloc to the STN_UNDEF (0) symbol so that they all match. */
+ r_symndx = STN_UNDEF;
break;
default:
}
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;
- }
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend,
+ elf64_alpha_howto_table + r_type,
+ contents);
if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
rel->r_addend += sec->output_offset;
const char *section_name;
section_name = (bfd_elf_string_from_elf_section
(input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
- elf_section_data(input_section)->rel_hdr.sh_name));
+ _bfd_elf_single_rel_hdr (input_section)->sh_name));
BFD_ASSERT(section_name != NULL);
srel = bfd_get_section_by_name (dynobj, section_name);
}
r_symndx = ELF64_R_SYM(rel->r_info);
/* The symbol for a TLSLDM reloc is ignored. Collapse the
- reloc to the 0 symbol so that they all match. */
+ reloc to the STN_UNDEF (0) symbol so that they all match. */
if (r_type == R_ALPHA_TLSLDM)
- r_symndx = 0;
+ r_symndx = STN_UNDEF;
if (r_symndx < symtab_hdr->sh_info)
{
msec = sec;
value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
- /* If this is a tp-relative relocation against sym 0,
+ /* If this is a tp-relative relocation against sym STN_UNDEF (0),
this is hackery from relax_section. Force the value to
be the tls module base. */
- if (r_symndx == 0
+ if (r_symndx == STN_UNDEF
&& (r_type == R_ALPHA_TLSLDM
|| r_type == R_ALPHA_GOTTPREL
|| r_type == R_ALPHA_TPREL64
}
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;
- }
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, relend, howto, contents);
addend = rel->r_addend;
value += addend;
else if (r_type == R_ALPHA_TPREL64)
{
BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
- if (!info->shared)
+ if (!info->shared || info->pie)
{
value -= tp_base;
goto default_reloc;
dynaddend = value - dtp_base;
}
else if (info->shared
- && r_symndx != 0
+ && r_symndx != STN_UNDEF
&& (input_section->flags & SEC_ALLOC)
&& !undef_weak_ref)
{
/* ??? .eh_frame references to discarded sections will be smashed
to relocations against SHN_UNDEF. The .eh_frame format allows
NULL to be encoded as 0 in any format, so this works here. */
- if (r_symndx == 0)
+ if (r_symndx == STN_UNDEF)
howto = (elf64_alpha_howto_table
+ (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
goto default_reloc;
case R_ALPHA_TPRELHI:
case R_ALPHA_TPRELLO:
case R_ALPHA_TPREL16:
- if (info->shared)
+ if (info->shared && !info->pie)
{
(*_bfd_error_handler)
(_("%B: TLS local exec code cannot be linked into shared objects"),
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;
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)
{
#define TARGET_LITTLE_SYM bfd_elf64_alpha_vec
#define TARGET_LITTLE_NAME "elf64-alpha"
#define ELF_ARCH bfd_arch_alpha
+#define ELF_TARGET_ID ALPHA_ELF_DATA
#define ELF_MACHINE_CODE EM_ALPHA
#define ELF_MAXPAGESIZE 0x10000
#define ELF_COMMONPAGESIZE 0x2000
elf64_alpha_adjust_dynamic_symbol
#define elf_backend_merge_symbol_attribute \
elf64_alpha_merge_symbol_attribute
+#define elf_backend_copy_indirect_symbol \
+ elf64_alpha_copy_indirect_symbol
#define elf_backend_always_size_sections \
elf64_alpha_always_size_sections
#define elf_backend_size_dynamic_sections \
#define elf_backend_reloc_type_class \
elf64_alpha_reloc_type_class
+#define elf_backend_can_gc_sections 1
+#define elf_backend_gc_mark_hook elf64_alpha_gc_mark_hook
+#define elf_backend_gc_sweep_hook elf64_alpha_gc_sweep_hook
+
#define elf_backend_ecoff_debug_swap \
&elf64_alpha_ecoff_debug_swap