summaryrefslogtreecommitdiffstats
path: root/contrib/binutils/bfd/elf64-alpha.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/bfd/elf64-alpha.c')
-rw-r--r--contrib/binutils/bfd/elf64-alpha.c193
1 files changed, 132 insertions, 61 deletions
diff --git a/contrib/binutils/bfd/elf64-alpha.c b/contrib/binutils/bfd/elf64-alpha.c
index 76d0661..3d4350d 100644
--- a/contrib/binutils/bfd/elf64-alpha.c
+++ b/contrib/binutils/bfd/elf64-alpha.c
@@ -1,6 +1,6 @@
/* Alpha specific support for 64-bit ELF
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- 2006 Free Software Foundation, Inc.
+ 2006, 2007 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@tamu.edu>.
This file is part of BFD, the Binary File Descriptor library.
@@ -22,8 +22,8 @@
/* 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"
@@ -184,6 +184,10 @@ struct alpha_elf_link_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. */
@@ -321,11 +325,14 @@ struct alpha_elf_obj_tdata
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;
+ {
+ 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 bfd_elf_mkobject (abfd);
}
static bfd_boolean
@@ -1052,6 +1059,23 @@ elf64_alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
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
@@ -1898,7 +1922,7 @@ elf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (rel_sec_name == NULL)
return FALSE;
- BFD_ASSERT (strncmp (rel_sec_name, ".rela", 5) == 0
+ BFD_ASSERT (CONST_STRNEQ (rel_sec_name, ".rela")
&& strcmp (bfd_get_section_name (abfd, sec),
rel_sec_name+5) == 0);
}
@@ -2032,6 +2056,19 @@ elf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
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. */
@@ -2342,7 +2379,6 @@ static bfd_boolean
elf64_alpha_size_got_sections (struct bfd_link_info *info)
{
bfd *i, *got_list, *cur_got_obj = NULL;
- int something_changed = 0;
got_list = alpha_elf_hash_table (info)->got_list;
@@ -2380,9 +2416,6 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
return TRUE;
alpha_elf_hash_table (info)->got_list = got_list;
-
- /* Force got offsets to be recalculated. */
- something_changed = 1;
}
cur_got_obj = got_list;
@@ -2396,8 +2429,6 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
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
{
@@ -2408,8 +2439,7 @@ elf64_alpha_size_got_sections (struct bfd_link_info *info)
/* 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;
}
@@ -2444,10 +2474,10 @@ elf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, PTR data)
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;
@@ -2457,7 +2487,7 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
dynobj = elf_hash_table(info)->dynobj;
splt = bfd_get_section_by_name (dynobj, ".plt");
if (splt == NULL)
- return TRUE;
+ return;
splt->size = 0;
@@ -2466,6 +2496,7 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
/* Every plt entry requires a JMP_SLOT relocation. */
spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ entries = 0;
if (splt->size)
{
if (elf64_alpha_use_secureplt)
@@ -2473,8 +2504,6 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
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
@@ -2485,8 +2514,6 @@ elf64_alpha_size_plt_section (struct bfd_link_info *info)
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
sgotplt->size = entries ? 16 : 0;
}
-
- return TRUE;
}
static bfd_boolean
@@ -2657,7 +2684,7 @@ elf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
/* 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;
@@ -2696,15 +2723,13 @@ elf64_alpha_size_rela_got_section (struct bfd_link_info *info)
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),
elf64_alpha_size_rela_got_1, info);
-
- return TRUE;
}
/* Set the sizes of the dynamic sections. */
@@ -2758,7 +2783,7 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
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)
{
@@ -2770,7 +2795,7 @@ elf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
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)
{
@@ -3576,7 +3601,7 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
struct alpha_elf_got_entry **local_got_entries;
struct alpha_relax_info info;
- /* We are not currently changing any sizes, so only one pass. */
+ /* There's nothing to change, yet. */
*again = FALSE;
if (link_info->relocatable
@@ -3585,6 +3610,22 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
|| sec->reloc_count == 0)
return TRUE;
+ /* Make sure our GOT and PLT tables are up-to-date. */
+ if (alpha_elf_hash_table(link_info)->relax_trip != link_info->relax_trip)
+ {
+ alpha_elf_hash_table(link_info)->relax_trip = link_info->relax_trip;
+
+ /* This should never fail after the initial round, since the only
+ error is GOT overflow, and relaxation only shrinks the table. */
+ if (!elf64_alpha_size_got_sections (link_info))
+ abort ();
+ if (elf_hash_table (link_info)->dynamic_sections_created)
+ {
+ elf64_alpha_size_plt_section (link_info);
+ elf64_alpha_size_rela_got_section (link_info);
+ }
+ }
+
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
@@ -3794,13 +3835,6 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
}
}
- 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)
{
@@ -3896,9 +3930,11 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
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;
+ sym_hashes = elf_sym_hashes (input_bfd);
relend = relocs + input_section->reloc_count;
for (rel = relocs; rel < relend; rel++)
@@ -3908,7 +3944,7 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
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)
@@ -3919,22 +3955,49 @@ elf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
continue;
}
- r_symndx = ELF64_R_SYM(rel->r_info);
-
/* The symbol associated with GPDISP and LITUSE is
immaterial. Only the addend is significant. */
if (r_type == R_ALPHA_GPDISP || r_type == R_ALPHA_LITUSE)
continue;
+ r_symndx = ELF64_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr_sh_info)
{
sym = local_syms + r_symndx;
- if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
- {
- sec = local_sections[r_symndx];
- rel->r_addend += sec->output_offset + sym->st_value;
- }
+ sec = local_sections[r_symndx];
}
+ else
+ {
+ struct elf_link_hash_entry *h;
+
+ h = sym_hashes[r_symndx - symtab_hdr_sh_info];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ continue;
+
+ sym = NULL;
+ sec = h->root.u.def.section;
+ }
+
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. */
+ _bfd_clear_contents (elf64_alpha_howto_table + r_type,
+ input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
+ if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ rel->r_addend += sec->output_offset;
}
return ret_val;
@@ -4134,6 +4197,17 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
gotent = h->got_entries;
}
+ if (sec != NULL && elf_discarded_section (sec))
+ {
+ /* For relocs against symbols from removed linkonce sections,
+ or sections discarded by a linker script, we just want the
+ section contents zeroed. Avoid any special processing. */
+ _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+ rel->r_info = 0;
+ rel->r_addend = 0;
+ continue;
+ }
+
addend = rel->r_addend;
value += addend;
@@ -4193,18 +4267,6 @@ elf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
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)
@@ -5145,9 +5207,9 @@ elf64_alpha_reloc_type_class (const Elf_Internal_Rela *rela)
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
@@ -5231,12 +5293,15 @@ static const struct elf_size_info alpha_elf_size_info =
#define ELF_ARCH bfd_arch_alpha
#define ELF_MACHINE_CODE EM_ALPHA
#define ELF_MAXPAGESIZE 0x10000
+#define ELF_COMMONPAGESIZE 0x2000
#define bfd_elf64_bfd_link_hash_table_create \
elf64_alpha_bfd_link_hash_table_create
#define bfd_elf64_bfd_reloc_type_lookup \
elf64_alpha_bfd_reloc_type_lookup
+#define bfd_elf64_bfd_reloc_name_lookup \
+ elf64_alpha_bfd_reloc_name_lookup
#define elf_info_to_howto \
elf64_alpha_info_to_howto
@@ -5267,10 +5332,14 @@ static const struct elf_size_info alpha_elf_size_info =
elf64_alpha_create_dynamic_sections
#define elf_backend_adjust_dynamic_symbol \
elf64_alpha_adjust_dynamic_symbol
+#define elf_backend_merge_symbol_attribute \
+ elf64_alpha_merge_symbol_attribute
#define elf_backend_always_size_sections \
elf64_alpha_always_size_sections
#define elf_backend_size_dynamic_sections \
elf64_alpha_size_dynamic_sections
+#define elf_backend_omit_section_dynsym \
+ ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
#define elf_backend_relocate_section \
elf64_alpha_relocate_section
#define elf_backend_finish_dynamic_symbol \
@@ -5305,6 +5374,8 @@ static const struct elf_size_info alpha_elf_size_info =
#define TARGET_LITTLE_SYM bfd_elf64_alpha_freebsd_vec
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf64-alpha-freebsd"
+#undef ELF_OSABI
+#define ELF_OSABI ELFOSABI_FREEBSD
/* The kernel recognizes executables as valid only if they carry a
"FreeBSD" label in the ELF header. So we put this label on all
@@ -5319,7 +5390,7 @@ elf64_alpha_fbsd_post_process_headers (bfd * abfd,
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);
OpenPOWER on IntegriCloud