/* Alpha specific support for 64-bit ELF
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1996-2014 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. */
#define alpha_elf_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
- (bfd_boolean (*) (struct elf_link_hash_entry *, PTR)) (func), \
+ (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
/* 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. */
#define alpha_elf_sym_hashes(abfd) \
((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
-/* Should we do dynamic things to this symbol? This differs from the
+/* Should we do dynamic things to this symbol? This differs from the
generic version in that we never need to consider function pointer
equality wrt PLT entries -- we don't create a PLT entry if a symbol's
address is ever taken. */
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;
return &ret->root.root;
}
\f
+/* Alpha ELF follows MIPS ELF in using a special find_nearest_line
+ routine in order to handle the ECOFF debugging information. */
+
+struct alpha_elf_find_line
+{
+ struct ecoff_debug_info d;
+ struct ecoff_find_line i;
+};
+
/* We have some private fields hanging off of the elf_tdata structure. */
struct alpha_elf_obj_tdata
/* For every got, this is the sum of the number of words required
to hold all of the member object's local got. */
int local_got_size;
+
+ /* Used by elf64_alpha_find_nearest_line entry point. */
+ struct alpha_elf_find_line *find_line_info;
+
};
#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
static bfd_reloc_status_type
elf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
asymbol *sym ATTRIBUTE_UNUSED,
- PTR data ATTRIBUTE_UNUSED, asection *sec,
+ void * data ATTRIBUTE_UNUSED, asection *sec,
bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
{
if (output_bfd)
static bfd_reloc_status_type
elf64_alpha_reloc_bad (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
asymbol *sym ATTRIBUTE_UNUSED,
- PTR data ATTRIBUTE_UNUSED, asection *sec,
+ void * data ATTRIBUTE_UNUSED, asection *sec,
bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
{
if (output_bfd)
static bfd_reloc_status_type
elf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry,
- asymbol *sym ATTRIBUTE_UNUSED, PTR data,
+ asymbol *sym ATTRIBUTE_UNUSED, void * data,
asection *input_section, bfd *output_bfd,
char **err_msg)
{
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 */
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);
flagword flags;
struct elf_link_hash_entry *h;
+ if (! is_alpha_elf (abfd))
+ return FALSE;
+
/* We need to create .plt, .rela.plt, .got, and .rela.got sections. */
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
}
READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
- READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
- READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
- READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
- READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
+ READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *);
+ READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *);
+ READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *);
+ READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *);
READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
union aux_ext *);
READ (ss, cbSsOffset, issMax, sizeof (char), char *);
READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
- READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
- READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
- READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR);
+ READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *);
+ READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *);
+ READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *);
#undef READ
debug->fdr = NULL;
return name[0] == '$';
}
-/* Alpha ELF follows MIPS ELF in using a special find_nearest_line
- routine in order to handle the ECOFF debugging information. We
- still call this mips_elf_find_line because of the slot
- find_line_info in elf_obj_tdata is declared that way. */
-
-struct mips_elf_find_line
-{
- struct ecoff_debug_info d;
- struct ecoff_find_line i;
-};
-
static bfd_boolean
-elf64_alpha_find_nearest_line (bfd *abfd, asection *section, asymbol **symbols,
- bfd_vma offset, const char **filename_ptr,
+elf64_alpha_find_nearest_line (bfd *abfd, asymbol **symbols,
+ asection *section, bfd_vma offset,
+ const char **filename_ptr,
const char **functionname_ptr,
- unsigned int *line_ptr)
+ unsigned int *line_ptr,
+ unsigned int *discriminator_ptr)
{
asection *msec;
- if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset,
filename_ptr, functionname_ptr,
- line_ptr, 0,
+ line_ptr, discriminator_ptr,
+ dwarf_debug_sections, 0,
&elf_tdata (abfd)->dwarf2_find_line_info))
return TRUE;
if (msec != NULL)
{
flagword origflags;
- struct mips_elf_find_line *fi;
+ struct alpha_elf_find_line *fi;
const struct ecoff_debug_swap * const swap =
get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS)
msec->flags |= SEC_HAS_CONTENTS;
- fi = elf_tdata (abfd)->find_line_info;
+ fi = alpha_elf_tdata (abfd)->find_line_info;
if (fi == NULL)
{
bfd_size_type external_fdr_size;
char *fraw_src;
char *fraw_end;
struct fdr *fdr_ptr;
- bfd_size_type amt = sizeof (struct mips_elf_find_line);
+ bfd_size_type amt = sizeof (struct alpha_elf_find_line);
- fi = (struct mips_elf_find_line *) bfd_zalloc (abfd, amt);
+ fi = (struct alpha_elf_find_line *) bfd_zalloc (abfd, amt);
if (fi == NULL)
{
msec->flags = origflags;
fraw_end = (fraw_src
+ fi->d.symbolic_header.ifdMax * external_fdr_size);
for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
- (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+ (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr);
- elf_tdata (abfd)->find_line_info = fi;
+ alpha_elf_tdata (abfd)->find_line_info = fi;
/* Note that we don't bother to ever free this information.
find_nearest_line is either called all the time, as in
/* Fall back on the generic ELF find_nearest_line routine. */
- return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
+ return _bfd_elf_find_nearest_line (abfd, symbols, section, offset,
filename_ptr, functionname_ptr,
- line_ptr);
+ line_ptr, discriminator_ptr);
}
\f
/* Structure used to pass information to alpha_elf_output_extsym. */
};
static bfd_boolean
-elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, PTR data)
+elf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, void * data)
{
struct extsym_info *einfo = (struct extsym_info *) data;
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;
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)
|| h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
+ /* PR15323, ref flags aren't set for references in the same
+ object. */
+ h->root.root.non_ir_ref = 1;
h->root.ref_regular = 1;
}
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 (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;
}
+/* 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
{
h->needs_plt = TRUE;
- s = bfd_get_section_by_name(dynobj, ".plt");
+ s = bfd_get_linker_section (dynobj, ".plt");
if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
return FALSE;
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 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? */
static bfd_boolean
elf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
- PTR arg ATTRIBUTE_UNUSED)
+ void * arg ATTRIBUTE_UNUSED)
{
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);
/* Constructs the gots. */
static bfd_boolean
-elf64_alpha_size_got_sections (struct bfd_link_info *info)
+elf64_alpha_size_got_sections (struct bfd_link_info *info,
+ bfd_boolean may_merge)
{
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. */
if (got_list == NULL)
{
- for (i = info->input_bfds; i ; i = i->link_next)
+ 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;
- i = alpha_elf_tdata(cur_got_obj)->got_link_next;
- while (i != NULL)
+ if (cur_got_obj == NULL)
+ return FALSE;
+
+ if (may_merge)
{
- if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+ i = alpha_elf_tdata(cur_got_obj)->got_link_next;
+ while (i != NULL)
{
- elf64_alpha_merge_gots (cur_got_obj, i);
+ if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+ {
+ elf64_alpha_merge_gots (cur_got_obj, i);
- 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
- {
- cur_got_obj = i;
- i = alpha_elf_tdata(i)->got_link_next;
+ 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;
+ }
+ else
+ {
+ cur_got_obj = i;
+ i = alpha_elf_tdata(i)->got_link_next;
+ }
}
}
/* 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;
}
static bfd_boolean
-elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, PTR data)
+elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h,
+ void * data)
{
asection *splt = (asection *) data;
struct alpha_elf_got_entry *gotent;
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");
+ splt = bfd_get_linker_section (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");
+ spltrel = bfd_get_linker_section (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
entire contents of the .got.plt section. */
if (elf64_alpha_use_secureplt)
{
- sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+ sgotplt = bfd_get_linker_section (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;
- /* 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))
+ if (!elf64_alpha_size_got_sections (info, TRUE))
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)
{
bfd *dynobj = elf_hash_table(info)->dynobj;
- asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ asection *srel = bfd_get_linker_section (dynobj, ".rela.got");
BFD_ASSERT (srel != NULL);
srel->size += sizeof (Elf64_External_Rela) * entries;
}
/* 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;
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));
}
}
dynobj = elf_hash_table(info)->dynobj;
- srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ srel = bfd_get_linker_section (dynobj, ".rela.got");
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);
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
{
- s = bfd_get_section_by_name (dynobj, ".interp");
+ s = bfd_get_linker_section (dynobj, ".interp");
BFD_ASSERT (s != NULL);
s->size = sizeof ELF_DYNAMIC_INTERPRETER;
s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
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);
of the dynobj section names depend upon the input files. */
name = bfd_get_section_name (dynobj, s);
- if (strncmp (name, ".rela", 5) == 0)
+ if (CONST_STRNEQ (name, ".rela"))
{
if (s->size != 0)
{
s->reloc_count = 0;
}
}
- else if (strncmp (name, ".got", 4) != 0
+ else if (! CONST_STRNEQ (name, ".got")
&& strcmp (name, ".plt") != 0
&& strcmp (name, ".dynbss") != 0)
{
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)
}
else
{
+ /* We may only create GPREL relocs during the second pass. */
+ if (info->link_info->relax_pass == 0)
+ return TRUE;
+
disp = symval - info->gp;
insn = (OP_LDA << 26) | (insn & 0x03ff0000);
r_type = R_ALPHA_GPREL16;
else
{
tsec_relocs = (_bfd_elf_link_read_relocs
- (info->abfd, info->tsec, (PTR) NULL,
+ (info->abfd, info->tsec, NULL,
(Elf_Internal_Rela *) NULL,
info->link_info->keep_memory));
if (tsec_relocs == NULL)
/* 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;
elf64_alpha_relax_with_lituse (struct alpha_relax_info *info,
bfd_vma symval, Elf_Internal_Rela *irel)
{
- Elf_Internal_Rela *urel, *irelend = info->relend;
- int flags, count, i;
+ Elf_Internal_Rela *urel, *erel, *irelend = info->relend;
+ int flags;
bfd_signed_vma disp;
bfd_boolean fits16;
bfd_boolean fits32;
bfd_boolean lit_reused = FALSE;
bfd_boolean all_optimized = TRUE;
+ bfd_boolean changed_contents;
+ bfd_boolean changed_relocs;
+ bfd_byte *contents = info->contents;
+ bfd *abfd = info->abfd;
+ bfd_vma sec_output_vma;
unsigned int lit_insn;
+ int relax_pass;
- lit_insn = bfd_get_32 (info->abfd, info->contents + irel->r_offset);
+ lit_insn = bfd_get_32 (abfd, contents + irel->r_offset);
if (lit_insn >> 26 != OP_LDQ)
{
((*_bfd_error_handler)
("%B: %A+0x%lx: warning: LITERAL relocation against unexpected insn",
- info->abfd, info->sec,
+ abfd, info->sec,
(unsigned long) irel->r_offset));
return TRUE;
}
if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
return TRUE;
+ changed_contents = info->changed_contents;
+ changed_relocs = info->changed_relocs;
+ sec_output_vma = info->sec->output_section->vma + info->sec->output_offset;
+ relax_pass = info->link_info->relax_pass;
+
/* Summarize how this particular LITERAL is used. */
- for (urel = irel+1, flags = count = 0; urel < irelend; ++urel, ++count)
+ for (erel = irel+1, flags = 0; erel < irelend; ++erel)
{
- if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
+ if (ELF64_R_TYPE (erel->r_info) != R_ALPHA_LITUSE)
break;
- if (urel->r_addend <= 6)
- flags |= 1 << urel->r_addend;
+ if (erel->r_addend <= 6)
+ flags |= 1 << erel->r_addend;
}
/* A little preparation for the loop... */
disp = symval - info->gp;
- for (urel = irel+1, i = 0; i < count; ++i, ++urel)
+ for (urel = irel+1; urel < erel; ++urel)
{
+ bfd_vma urel_r_offset = urel->r_offset;
unsigned int insn;
int insn_disp;
bfd_signed_vma xdisp;
+ Elf_Internal_Rela nrel;
- insn = bfd_get_32 (info->abfd, info->contents + urel->r_offset);
+ insn = bfd_get_32 (abfd, contents + urel_r_offset);
switch (urel->r_addend)
{
break;
case LITUSE_ALPHA_BASE:
+ /* We may only create GPREL relocs during the second pass. */
+ if (relax_pass == 0)
+ {
+ all_optimized = FALSE;
+ break;
+ }
+
/* We can always optimize 16-bit displacements. */
/* Extract the displacement from the instruction, sign-extending
/* Take the op code and dest from this insn, take the base
register from the literal insn. Leave the offset alone. */
insn = (insn & 0xffe0ffff) | (lit_insn & 0x001f0000);
- urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
- R_ALPHA_GPREL16);
- urel->r_addend = irel->r_addend;
- info->changed_relocs = TRUE;
-
- bfd_put_32 (info->abfd, (bfd_vma) insn,
- info->contents + urel->r_offset);
- info->changed_contents = TRUE;
+ bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset);
+ changed_contents = TRUE;
+
+ nrel = *urel;
+ nrel.r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_GPREL16);
+ nrel.r_addend = irel->r_addend;
+
+ /* As we adjust, move the reloc to the end so that we don't
+ break the LITERAL+LITUSE chain. */
+ if (urel < --erel)
+ *urel-- = *erel;
+ *erel = nrel;
+ changed_relocs = TRUE;
}
/* If all mem+byte, we can optimize 32-bit mem displacements. */
irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
R_ALPHA_GPRELHIGH);
lit_insn = (OP_LDAH << 26) | (lit_insn & 0x03ff0000);
- bfd_put_32 (info->abfd, (bfd_vma) lit_insn,
- info->contents + irel->r_offset);
+ bfd_put_32 (abfd, (bfd_vma) lit_insn, contents + irel->r_offset);
lit_reused = TRUE;
- info->changed_contents = TRUE;
+ changed_contents = TRUE;
+ /* Since all relocs must be optimized, don't bother swapping
+ this relocation to the end. */
urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
R_ALPHA_GPRELLOW);
urel->r_addend = irel->r_addend;
- info->changed_relocs = TRUE;
+ changed_relocs = TRUE;
}
else
all_optimized = FALSE;
insn &= ~ (unsigned) 0x001ff000;
insn |= ((symval & 7) << 13) | 0x1000;
-
- urel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
- urel->r_addend = 0;
- info->changed_relocs = TRUE;
-
- bfd_put_32 (info->abfd, (bfd_vma) insn,
- info->contents + urel->r_offset);
- info->changed_contents = TRUE;
+ bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset);
+ changed_contents = TRUE;
+
+ nrel = *urel;
+ nrel.r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
+ nrel.r_addend = 0;
+
+ /* As we adjust, move the reloc to the end so that we don't
+ break the LITERAL+LITUSE chain. */
+ if (urel < --erel)
+ *urel-- = *erel;
+ *erel = nrel;
+ changed_relocs = TRUE;
break;
case LITUSE_ALPHA_JSR:
if (info->h && info->h->root.root.type == bfd_link_hash_undefweak)
{
insn |= 31 << 16;
- bfd_put_32 (info->abfd, (bfd_vma) insn,
- info->contents + urel->r_offset);
+ bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset);
- info->changed_contents = TRUE;
+ changed_contents = TRUE;
break;
}
/* If not zero, place to jump without needing pv. */
optdest = elf64_alpha_relax_opt_call (info, symval);
- org = (info->sec->output_section->vma
- + info->sec->output_offset
- + urel->r_offset + 4);
+ org = sec_output_vma + urel_r_offset + 4;
odisp = (optdest ? optdest : symval) - org;
if (odisp >= -0x400000 && odisp < 0x400000)
insn = (OP_BSR << 26) | (insn & 0x03e00000);
else
insn = (OP_BR << 26) | (insn & 0x03e00000);
+ bfd_put_32 (abfd, (bfd_vma) insn, contents + urel_r_offset);
+ changed_contents = TRUE;
- urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
- R_ALPHA_BRADDR);
- urel->r_addend = irel->r_addend;
+ nrel = *urel;
+ nrel.r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
+ R_ALPHA_BRADDR);
+ nrel.r_addend = irel->r_addend;
if (optdest)
- urel->r_addend += optdest - symval;
+ nrel.r_addend += optdest - symval;
else
all_optimized = FALSE;
- bfd_put_32 (info->abfd, (bfd_vma) insn,
- info->contents + urel->r_offset);
-
/* Kill any HINT reloc that might exist for this insn. */
xrel = (elf64_alpha_find_reloc_at_ofs
- (info->relocs, info->relend, urel->r_offset,
+ (info->relocs, info->relend, urel_r_offset,
R_ALPHA_HINT));
if (xrel)
xrel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
- info->changed_contents = TRUE;
+ /* As we adjust, move the reloc to the end so that we don't
+ break the LITERAL+LITUSE chain. */
+ if (urel < --erel)
+ *urel-- = *erel;
+ *erel = nrel;
+
info->changed_relocs = TRUE;
}
else
{
Elf_Internal_Rela *gpdisp
= (elf64_alpha_find_reloc_at_ofs
- (info->relocs, irelend, urel->r_offset + 4,
+ (info->relocs, irelend, urel_r_offset + 4,
R_ALPHA_GPDISP));
if (gpdisp)
{
- bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
+ bfd_byte *p_ldah = contents + gpdisp->r_offset;
bfd_byte *p_lda = p_ldah + gpdisp->r_addend;
- unsigned int ldah = bfd_get_32 (info->abfd, p_ldah);
- unsigned int lda = bfd_get_32 (info->abfd, p_lda);
+ unsigned int ldah = bfd_get_32 (abfd, p_ldah);
+ unsigned int lda = bfd_get_32 (abfd, p_lda);
/* Verify that the instruction is "ldah $29,0($26)".
Consider a function that ends in a noreturn call,
In that case the insn would use $27 as the base. */
if (ldah == 0x27ba0000 && lda == 0x23bd0000)
{
- bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_ldah);
- bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_lda);
+ bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, p_ldah);
+ bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, p_lda);
gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
- info->changed_contents = TRUE;
- info->changed_relocs = TRUE;
+ changed_contents = TRUE;
+ changed_relocs = TRUE;
}
}
}
}
}
+ /* If we reused the literal instruction, we must have optimized all. */
+ BFD_ASSERT(!lit_reused || all_optimized);
+
/* If all cases were optimized, we can reduce the use count on this
got entry by one, possibly eliminating it. */
if (all_optimized)
if (!lit_reused)
{
irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
- info->changed_relocs = TRUE;
+ changed_relocs = TRUE;
- bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP,
- info->contents + irel->r_offset);
- info->changed_contents = TRUE;
+ bfd_put_32 (abfd, (bfd_vma) INSN_UNOP, contents + irel->r_offset);
+ changed_contents = TRUE;
}
-
- return TRUE;
}
- else
- return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL);
+
+ info->changed_contents = changed_contents;
+ info->changed_relocs = changed_relocs;
+
+ if (all_optimized || relax_pass == 0)
+ return TRUE;
+ return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL);
}
static bfd_boolean
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;
- switch (!dynamic && !info->link_info->shared)
+ new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
+
+ /* Some compilers warn about a Boolean-looking expression being
+ used in a switch. The explicit cast silences them. */
+ switch ((int) (!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;
+ int relax_pass;
+
+ 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));
+ relax_pass = link_info->relax_pass;
+
+ /* 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. However, we
+ may only merge got sections during the first pass. If we merge
+ sections after we've created GPREL relocs, the GP for the merged
+ section backs up which may put the relocs out of range. */
+ if (!elf64_alpha_size_got_sections (link_info, relax_pass == 0))
+ 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. */
internal_relocs = (_bfd_elf_link_read_relocs
- (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
return FALSE;
unsigned long r_symndx = ELF64_R_SYM (irel->r_info);
/* Early exit for unhandled or unrelaxable relocations. */
- switch (r_type)
- {
- case R_ALPHA_LITERAL:
- case R_ALPHA_GPRELHIGH:
- case R_ALPHA_GPRELLOW:
- case R_ALPHA_GOTDTPREL:
- case R_ALPHA_GOTTPREL:
- case R_ALPHA_TLSGD:
- break;
-
- 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;
- break;
-
- default:
- continue;
+ if (r_type != R_ALPHA_LITERAL)
+ {
+ /* We complete everything except LITERAL in the first pass. */
+ if (relax_pass != 0)
+ continue;
+ if (r_type == R_ALPHA_TLSLDM)
+ {
+ /* The symbol for a TLSLDM reloc is ignored. Collapse the
+ reloc to the STN_UNDEF (0) symbol so that they all match. */
+ r_symndx = STN_UNDEF;
+ }
+ else if (r_type != R_ALPHA_GOTDTPREL
+ && r_type != R_ALPHA_GOTTPREL
+ && r_type != R_ALPHA_TLSGD)
+ continue;
}
/* Get the value of the symbol referred to by the reloc. */
}
}
- 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 && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend,
+ elf64_alpha_howto_table + r_type, 0,
+ contents);
+
+ 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)
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ srelgot = bfd_get_linker_section (dynobj, ".rela.got");
else
srelgot = NULL;
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);
+ srel = bfd_get_linker_section (dynobj, section_name);
}
else
srel = NULL;
bfd_vma value;
bfd_vma addend;
bfd_boolean dynamic_symbol_p;
+ bfd_boolean unresolved_reloc = FALSE;
bfd_boolean undef_weak_ref = FALSE;
unsigned long r_type;
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
unless it has been done already. */
if ((sec->flags & SEC_MERGE)
&& ELF_ST_TYPE (sym->st_info) == STT_SECTION
- && sec->sec_info_type == ELF_INFO_TYPE_MERGE
+ && sec->sec_info_type == SEC_INFO_TYPE_MERGE
&& gotent
&& !gotent->reloc_xlated)
{
}
else
{
- bfd_boolean warned;
- bfd_boolean unresolved_reloc;
+ bfd_boolean warned, ignored;
struct elf_link_hash_entry *hh;
struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
r_symndx, symtab_hdr, sym_hashes,
hh, sec, value,
- unresolved_reloc, warned);
+ unresolved_reloc, warned, ignored);
if (warned)
continue;
gotent = h->got_entries;
}
+ if (sec != NULL && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, howto, 0, contents);
+
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)
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)
+ && !undef_weak_ref
+ && !(unresolved_reloc
+ && (_bfd_elf_section_offset (output_bfd, info,
+ input_section,
+ rel->r_offset)
+ == (bfd_vma) -1)))
{
if (r_type == R_ALPHA_REFLONG)
{
/* ??? .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
+ || (unresolved_reloc
+ && _bfd_elf_section_offset (output_bfd, info,
+ input_section,
+ rel->r_offset) == (bfd_vma) -1))
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"),
if (r_symndx < symtab_hdr->sh_info
&& sec != NULL && howto->pc_relative
- && elf_discarded_section (sec))
+ && discarded_section (sec))
break;
if (h != NULL)
BFD_ASSERT (h->dynindx != -1);
- splt = bfd_get_section_by_name (dynobj, ".plt");
+ splt = bfd_get_linker_section (dynobj, ".plt");
BFD_ASSERT (splt != NULL);
- srel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ srel = bfd_get_linker_section (dynobj, ".rela.plt");
BFD_ASSERT (srel != NULL);
for (gotent = ah->got_entries; gotent ; gotent = gotent->next)
asection *srel;
struct alpha_elf_got_entry *gotent;
- srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ srel = bfd_get_linker_section (dynobj, ".rela.got");
BFD_ASSERT (srel != NULL);
for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
abort ();
}
- elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
+ elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
gotent->got_offset, h->dynindx,
r_type, gotent->addend);
if (gotent->reloc_type == R_ALPHA_TLSGD)
- elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
+ elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
gotent->got_offset + 8, h->dynindx,
R_ALPHA_DTPREL64, gotent->addend);
}
}
/* Mark some specially defined symbols as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ if (h == elf_hash_table (info)->hdynamic
|| h == elf_hash_table (info)->hgot
|| h == elf_hash_table (info)->hplt)
sym->st_shndx = SHN_ABS;
asection *sdyn;
dynobj = elf_hash_table (info)->dynobj;
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
if (elf_hash_table (info)->dynamic_sections_created)
{
Elf64_External_Dyn *dyncon, *dynconend;
bfd_vma plt_vma, gotplt_vma;
- splt = bfd_get_section_by_name (dynobj, ".plt");
- srelaplt = bfd_get_section_by_name (output_bfd, ".rela.plt");
+ splt = bfd_get_linker_section (dynobj, ".plt");
+ srelaplt = bfd_get_linker_section (output_bfd, ".rela.plt");
BFD_ASSERT (splt != NULL && sdyn != NULL);
plt_vma = splt->output_section->vma + splt->output_offset;
gotplt_vma = 0;
if (elf64_alpha_use_secureplt)
{
- sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+ sgotplt = bfd_get_linker_section (dynobj, ".got.plt");
BFD_ASSERT (sgotplt != NULL);
if (sgotplt->size > 0)
gotplt_vma = sgotplt->output_section->vma + sgotplt->output_offset;
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;
debug.external_ext = debug.external_ext_end = NULL;
mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info);
- if (mdebug_handle == (PTR) NULL)
+ if (mdebug_handle == NULL)
return FALSE;
if (1)
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));
const char *name;
struct alpha_elf_link_hash_entry *h;
- (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext);
+ (*input_swap->swap_ext_in) (input_bfd, eraw_src, &ext);
if (ext.asym.sc == scNil
|| ext.asym.sc == scUndefined
|| ext.asym.sc == scSUndefined)
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;
einfo.failed = FALSE;
elf_link_hash_traverse (elf_hash_table (info),
elf64_alpha_output_extsym,
- (PTR) &einfo);
+ &einfo);
if (einfo.failed)
return FALSE;
/* 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)
{
}
static enum elf_reloc_type_class
-elf64_alpha_reloc_type_class (const Elf_Internal_Rela *rela)
+elf64_alpha_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ const asection *rel_sec ATTRIBUTE_UNUSED,
+ const Elf_Internal_Rela *rela)
{
switch ((int) ELF64_R_TYPE (rela->r_info))
{
\f
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 }
};
/* ECOFF swapping routines. These are used when dealing with the
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,
bfd_elf64_swap_reloca_out
};
-#define TARGET_LITTLE_SYM bfd_elf64_alpha_vec
+#define TARGET_LITTLE_SYM alpha_elf64_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
#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_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 \
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_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
/* FreeBSD support. */
#undef TARGET_LITTLE_SYM
-#define TARGET_LITTLE_SYM bfd_elf64_alpha_freebsd_vec
+#define TARGET_LITTLE_SYM alpha_elf64_fbsd_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);