static boolean elf64_alpha_object_p
PARAMS((bfd *));
static boolean elf64_alpha_section_from_shdr
- PARAMS((bfd *, Elf64_Internal_Shdr *, char *));
+ PARAMS((bfd *, Elf64_Internal_Shdr *, const char *));
static boolean elf64_alpha_section_flags
PARAMS((flagword *, Elf64_Internal_Shdr *));
static boolean elf64_alpha_fake_sections
PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static void elf64_alpha_calc_got_offsets PARAMS ((struct bfd_link_info *));
static boolean elf64_alpha_size_got_sections
- PARAMS ((bfd *, struct bfd_link_info *));
+ PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_plt_section
+ PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_plt_section_1
+ PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static boolean elf64_alpha_always_size_sections
PARAMS ((bfd *, struct bfd_link_info *));
static int alpha_dynamic_entries_for_reloc
PARAMS ((int, int, int));
static boolean elf64_alpha_calc_dynrel_sizes
PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
+static boolean elf64_alpha_size_rela_got_section
+ PARAMS ((struct bfd_link_info *));
+static boolean elf64_alpha_size_rela_got_1
+ PARAMS ((struct alpha_elf_link_hash_entry *, struct bfd_link_info *));
static boolean elf64_alpha_add_symbol_hook
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *,
const char **, flagword *, asection **, bfd_vma *));
PARAMS((struct bfd_link_info *, struct elf_link_hash_entry *));
static boolean elf64_alpha_size_dynamic_sections
PARAMS((bfd *, struct bfd_link_info *));
+static boolean elf64_alpha_relocate_section_r
+ PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
static boolean elf64_alpha_relocate_section
PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
case LITUSE_ALPHA_TLSGD:
case LITUSE_ALPHA_TLSLDM:
{
- /* If not zero, place to jump without needing pv. */
- bfd_vma optdest = elf64_alpha_relax_opt_call (info, symval);
- bfd_vma org = (info->sec->output_section->vma
- + info->sec->output_offset
- + urel->r_offset + 4);
+ bfd_vma optdest, org;
bfd_signed_vma odisp;
+ /* 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);
odisp = (optdest ? optdest : symval) - org;
+
if (odisp >= -0x400000 && odisp < 0x400000)
{
Elf_Internal_Rela *xrel;
R_ALPHA_GPDISP));
if (gpdisp)
{
- bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
+ bfd_byte *p_ldah = info->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);
insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
info->changed_contents = true;
-
+
switch (r_type)
{
case R_ALPHA_LITERAL:
struct elf_link_tls_segment *seg;
{
bfd *output_bfd = info->sec->output_section->owner;
- asection *first_tls_sec = NULL, *o;
+ asection *o;
unsigned int align;
bfd_vma base, end;
for (o = output_bfd->sections; o ; o = o->next)
if ((o->flags & SEC_THREAD_LOCAL) != 0
&& (o->flags & SEC_LOAD) != 0)
- {
- first_tls_sec = o;
- break;
- }
- if (!first_tls_sec)
+ break;
+ if (!o)
return NULL;
- base = first_tls_sec->vma;
+ base = o->vma;
align = 0;
- for (o = first_tls_sec; o && (o->flags & SEC_THREAD_LOCAL); o = o->next)
+ do
{
bfd_vma size;
size = lo->offset + lo->size;
}
end = o->vma + size;
+ o = o->next;
}
+ while (o && (o->flags & SEC_THREAD_LOCAL));
seg->start = base;
seg->size = end - base;
boolean *again;
{
Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Shdr *shndx_hdr;
Elf_Internal_Rela *internal_relocs;
- Elf_Internal_Rela *free_relocs = NULL;
Elf_Internal_Rela *irel, *irelend;
- bfd_byte *free_contents = NULL;
- Elf64_External_Sym *extsyms;
- Elf64_External_Sym *free_extsyms = NULL;
- Elf_External_Sym_Shndx *shndx_buf = NULL;
+ Elf_Internal_Sym *isymbuf = NULL;
struct alpha_elf_got_entry **local_got_entries;
struct alpha_relax_info info;
struct elf_link_tls_segment tls_segment;
(abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
link_info->keep_memory));
if (internal_relocs == NULL)
- goto error_return;
- if (! link_info->keep_memory)
- free_relocs = internal_relocs;
+ return false;
memset(&info, 0, sizeof (info));
info.abfd = abfd;
info.relocs = internal_relocs;
info.relend = irelend = internal_relocs + sec->reloc_count;
- /* Find the GP for this object. Do not store the result back via
+ /* Find the GP for this object. Do not store the result back via
_bfd_set_gp_value, since this could change again before final. */
info.gotobj = alpha_elf_tdata (abfd)->gotobj;
if (info.gotobj)
info.contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
if (info.contents == NULL)
goto error_return;
- free_contents = info.contents;
if (! bfd_get_section_contents (abfd, sec, info.contents,
(file_ptr) 0, sec->_raw_size))
goto error_return;
}
- /* Read this BFD's symbols. */
- if (symtab_hdr->contents != NULL)
- extsyms = (Elf64_External_Sym *) symtab_hdr->contents;
- else
- {
- bfd_size_type amt = symtab_hdr->sh_info * sizeof (Elf64_External_Sym);
- extsyms = (Elf64_External_Sym *) bfd_malloc (amt);
- if (extsyms == NULL)
- goto error_return;
- free_extsyms = extsyms;
- if (bfd_seek (abfd, symtab_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) extsyms, amt, abfd) != amt)
- goto error_return;
- }
-
- shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- if (shndx_hdr->sh_size != 0)
- {
- bfd_size_type amt;
- amt = symtab_hdr->sh_info * sizeof (Elf_External_Sym_Shndx);
- shndx_buf = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
- if (shndx_buf == NULL)
- goto error_return;
- if (bfd_seek (abfd, shndx_hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread ((PTR) shndx_buf, amt, abfd) != amt)
- goto error_return;
- }
-
/* Compute the TLS segment information. The version normally found in
elf_hash_table (link_info)->tls_segment isn't built until final_link.
??? Probably should look into extracting this into a common function. */
for (irel = internal_relocs; irel < irelend; irel++)
{
bfd_vma symval;
- Elf_Internal_Sym isym;
struct alpha_elf_got_entry *gotent;
unsigned long r_type = ELF64_R_TYPE (irel->r_info);
if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
/* A local symbol. */
- Elf64_External_Sym *esym;
- Elf_External_Sym_Shndx *shndx;
-
- esym = extsyms + ELF64_R_SYM (irel->r_info);
- shndx = shndx_buf + (shndx_buf ? ELF64_R_SYM (irel->r_info) : 0);
- bfd_elf64_swap_symbol_in (abfd, esym, shndx, &isym);
- if (isym.st_shndx == SHN_UNDEF)
- info.tsec = bfd_und_section_ptr;
- else if (isym.st_shndx == SHN_ABS)
+ Elf_Internal_Sym *isym;
+
+ /* Read this BFD's local symbols. */
+ if (isymbuf == NULL)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ goto error_return;
+ }
+
+ isym = isymbuf + ELF64_R_SYM (irel->r_info);
+ if (isym->st_shndx == SHN_UNDEF)
+ continue;
+ else if (isym->st_shndx == SHN_ABS)
info.tsec = bfd_abs_section_ptr;
- else if (isym.st_shndx == SHN_COMMON)
+ else if (isym->st_shndx == SHN_COMMON)
info.tsec = bfd_com_section_ptr;
else
- info.tsec = bfd_section_from_elf_index (abfd, isym.st_shndx);
+ info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
info.h = NULL;
- info.other = isym.st_other;
+ info.other = isym->st_other;
info.first_gotent = &local_got_entries[ELF64_R_SYM(irel->r_info)];
- symval = isym.st_value;
+ symval = isym->st_value;
}
else
{
|| h->root.root.type == bfd_link_hash_warning)
h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
+ /* If the symbol is undefined, we can't do anything with it. */
+ if (h->root.root.type == bfd_link_hash_undefweak
+ || h->root.root.type == bfd_link_hash_undefined)
+ continue;
+
+ /* If the symbol isn't defined in the current module, again
+ we can't do anything. */
+ if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+ continue;
+
info.h = h;
info.tsec = h->root.root.u.def.section;
info.other = h->root.other;
}
}
- if (!elf64_alpha_size_got_sections (abfd, link_info))
+ 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 (info.changed_relocs)
- elf_section_data (sec)->relocs = internal_relocs;
- else if (free_relocs != NULL)
- free (free_relocs);
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ {
+ if (!link_info->keep_memory)
+ free (isymbuf);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+ }
+ }
- if (info.changed_contents)
- elf_section_data (sec)->this_hdr.contents = info.contents;
- else if (free_contents != NULL)
+ if (info.contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != info.contents)
{
- if (! link_info->keep_memory)
- free (free_contents);
+ if (!info.changed_contents && !link_info->keep_memory)
+ free (info.contents);
else
{
/* Cache the section contents for elf_link_input_bfd. */
}
}
- if (shndx_buf != NULL)
- free (shndx_buf);
-
- if (free_extsyms != NULL)
+ if (elf_section_data (sec)->relocs != internal_relocs)
{
- if (! link_info->keep_memory)
- free (free_extsyms);
+ if (!info.changed_relocs)
+ free (internal_relocs);
else
- {
- /* Cache the symbols for elf_link_input_bfd. */
- symtab_hdr->contents = (unsigned char *) extsyms;
- }
+ elf_section_data (sec)->relocs = internal_relocs;
}
*again = info.changed_contents || info.changed_relocs;
return true;
error_return:
- if (free_relocs != NULL)
- free (free_relocs);
- if (free_contents != NULL)
- free (free_contents);
- if (shndx_buf != NULL)
- free (shndx_buf);
- if (free_extsyms != NULL)
- free (free_extsyms);
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
+ free (isymbuf);
+ if (info.contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != info.contents)
+ free (info.contents);
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
return false;
}
\f
elf64_alpha_section_from_shdr (abfd, hdr, name)
bfd *abfd;
Elf64_Internal_Shdr *hdr;
- char *name;
+ const char *name;
{
asection *newsect;
if (ext_hdr == NULL && swap->external_hdr_size != 0)
goto error_return;
- if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
- swap->external_hdr_size)
- == false)
+ if (! bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
+ swap->external_hdr_size))
goto error_return;
symhdr = &debug->symbolic_header;
size *= sizeof (struct alpha_elf_got_entry *);
local_got_entries
- = (struct alpha_elf_got_entry **) bfd_alloc (abfd, size);
+ = (struct alpha_elf_got_entry **) bfd_zalloc (abfd, size);
if (!local_got_entries)
return NULL;
- memset (local_got_entries, 0, (size_t) size);
alpha_elf_tdata (abfd)->local_got_entries = local_got_entries;
}
/* Constructs the gots. */
static boolean
-elf64_alpha_size_got_sections (output_bfd, info)
- bfd *output_bfd ATTRIBUTE_UNUSED;
+elf64_alpha_size_got_sections (info)
struct bfd_link_info *info;
{
bfd *i, *got_list, *cur_got_obj = NULL;
return true;
}
+/* Called from relax_section to rebuild the PLT in light of
+ potential changes in the function's status. */
+
+static boolean
+elf64_alpha_size_plt_section (info)
+ struct bfd_link_info *info;
+{
+ asection *splt, *spltrel;
+ unsigned long entries;
+ bfd *dynobj;
+
+ dynobj = elf_hash_table(info)->dynobj;
+ splt = bfd_get_section_by_name(dynobj, ".plt");
+ if (splt == NULL)
+ return true;
+
+ splt->_raw_size = 0;
+
+ alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
+ elf64_alpha_size_plt_section_1, splt);
+
+ splt->_cooked_size = splt->_raw_size;
+
+ /* Every plt entry requires a JMP_SLOT relocation. */
+ spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
+ if (splt->_raw_size)
+ entries = (splt->_raw_size - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+ else
+ entries = 0;
+ spltrel->_raw_size = entries * sizeof (Elf64_External_Rela);
+ spltrel->_cooked_size = spltrel->_raw_size;
+
+ return true;
+}
+
+static boolean
+elf64_alpha_size_plt_section_1 (h, data)
+ struct alpha_elf_link_hash_entry *h;
+ PTR data;
+{
+ asection *splt = (asection *) data;
+ struct alpha_elf_got_entry *gotent;
+
+ /* If we didn't need an entry before, we still don't. */
+ if (!(h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT))
+ return true;
+
+ /* There must still be a LITERAL got entry for the function. */
+ for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+ if (gotent->reloc_type == R_ALPHA_LITERAL
+ && gotent->use_count > 0)
+ break;
+
+ /* If there is, reset the PLT offset. If not, there's no longer
+ a need for the PLT entry. */
+ if (gotent)
+ {
+ if (splt->_raw_size == 0)
+ splt->_raw_size = PLT_HEADER_SIZE;
+ h->root.plt.offset = splt->_raw_size;
+ splt->_raw_size += PLT_ENTRY_SIZE;
+ }
+ else
+ {
+ h->root.elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+ h->root.plt.offset = -1;
+ }
+
+ return true;
+}
+
static boolean
elf64_alpha_always_size_sections (output_bfd, info)
- bfd *output_bfd;
+ bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
{
bfd *i;
elf64_alpha_merge_ind_symbols,
NULL);
- if (!elf64_alpha_size_got_sections (output_bfd, info))
+ if (!elf64_alpha_size_got_sections (info))
return false;
/* Allocate space for all of the .got subsections. */
{
boolean dynamic;
struct alpha_elf_reloc_entry *relent;
- struct alpha_elf_got_entry *gotent;
- int entries;
+ 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;
&& (h->root.root.type == bfd_link_hash_defined
|| h->root.root.type == bfd_link_hash_defweak)
&& !(h->root.root.u.def.section->owner->flags & DYNAMIC))
- {
- h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
- }
+ h->root.elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
/* If the symbol is dynamic, we'll need all the relocations in their
natural form. If this is a shared object, and it has been forced
}
}
+ return true;
+}
+
+/* Set the sizes of the dynamic relocation sections. */
+
+static boolean
+elf64_alpha_size_rela_got_section (info)
+ struct bfd_link_info *info;
+{
+ unsigned long entries;
+ bfd *i, *dynobj;
+ asection *srel;
+
+ /* 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;
+ i ; i = alpha_elf_tdata(i)->got_link_next)
+ {
+ bfd *j;
+
+ for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
+ {
+ struct alpha_elf_got_entry **local_got_entries, *gotent;
+ int k, n;
+
+ local_got_entries = alpha_elf_tdata(j)->local_got_entries;
+ if (!local_got_entries)
+ continue;
+
+ for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
+ for (gotent = local_got_entries[k];
+ gotent ; gotent = gotent->next)
+ if (gotent->use_count > 0)
+ entries += (alpha_dynamic_entries_for_reloc
+ (gotent->reloc_type, 0, info->shared));
+ }
+ }
+
+ dynobj = elf_hash_table(info)->dynobj;
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (!srel)
+ {
+ BFD_ASSERT (entries == 0);
+ return true;
+ }
+ srel->_raw_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);
+
+ srel->_cooked_size = srel->_raw_size;
+
+ return true;
+}
+
+/* Subroutine of elf64_alpha_size_rela_got_section for doing the
+ global symbols. */
+
+static boolean
+elf64_alpha_size_rela_got_1 (h, info)
+ struct alpha_elf_link_hash_entry *h;
+ struct bfd_link_info *info;
+{
+ boolean dynamic;
+ 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 the symbol is dynamic, we'll need all the relocations in their
+ natural form. If this is a shared object, and it has been forced
+ local, we'll need the same number of RELATIVE relocations. */
+
+ dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
+
entries = 0;
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
- entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
- dynamic, info->shared);
+ if (gotent->use_count > 0)
+ entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
+ dynamic, info->shared);
/* If we are using a .plt entry, subtract one, as the first
reference uses a .rela.plt entry instead. */
if (elf_hash_table (info)->dynamic_sections_created)
{
- int entries;
- bfd *i;
-
/* Set the contents of the .interp section to the interpreter. */
if (!info->shared)
{
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),
- elf64_alpha_calc_dynrel_sizes,
- info);
-
- /* 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;
- i ; i = alpha_elf_tdata(i)->got_link_next)
- {
- bfd *j;
-
- for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
- {
- struct alpha_elf_got_entry **local_got_entries, *gotent;
- int k, n;
-
- local_got_entries = alpha_elf_tdata(j)->local_got_entries;
- if (!local_got_entries)
- continue;
-
- for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
- for (gotent = local_got_entries[k];
- gotent ; gotent = gotent->next)
- if (gotent->use_count > 0)
- entries += (alpha_dynamic_entries_for_reloc
- (gotent->reloc_type, 0, info->shared));
- }
- }
+ elf64_alpha_calc_dynrel_sizes, info);
- if (entries > 0)
- {
- s = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (s != NULL);
- s->_raw_size += sizeof (Elf64_External_Rela) * entries;
- }
+ elf64_alpha_size_rela_got_section (info);
}
/* else we're not dynamic and by definition we don't need such things. */
return true;
}
+/* Relocate an Alpha ELF section for a relocatable link.
+
+ We don't have to change anything unless the reloc is against a section
+ symbol, in which case we have to adjust according to where the section
+ symbol winds up in the output section. */
+
+static boolean
+elf64_alpha_relocate_section_r (output_bfd, info, input_bfd, input_section,
+ contents, relocs, local_syms, local_sections)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents ATTRIBUTE_UNUSED;
+ Elf_Internal_Rela *relocs;
+ Elf_Internal_Sym *local_syms;
+ asection **local_sections;
+{
+ unsigned long symtab_hdr_sh_info;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ boolean ret_val = true;
+
+ symtab_hdr_sh_info = elf_tdata (input_bfd)->symtab_hdr.sh_info;
+
+ relend = relocs + input_section->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ {
+ unsigned long r_symndx;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ unsigned long r_type;
+
+ r_type = ELF64_R_TYPE(rel->r_info);
+ if (r_type >= R_ALPHA_max)
+ {
+ (*_bfd_error_handler)
+ (_("%s: unknown relocation type %d"),
+ bfd_archive_filename (input_bfd), (int)r_type);
+ bfd_set_error (bfd_error_bad_value);
+ ret_val = false;
+ 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;
+
+ 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;
+ }
+ }
+ }
+
+ return ret_val;
+}
+
/* Relocate an Alpha ELF section. */
static boolean
Elf_Internal_Sym *local_syms;
asection **local_sections;
{
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
- struct elf_link_tls_segment *tls_segment = NULL;
- asection *sgot = NULL, *srel = NULL, *srelgot = NULL;
- bfd *dynobj = NULL, *gotobj = NULL;
- bfd_vma gp = 0, tp_base = 0, dtp_base = 0;
- boolean ret_val = true;
+ struct elf_link_tls_segment *tls_segment;
+ asection *sgot, *srel, *srelgot;
+ bfd *dynobj, *gotobj;
+ bfd_vma gp, tp_base, dtp_base;
+ struct alpha_elf_got_entry **local_got_entries;
+ boolean ret_val;
+ const char *section_name;
- if (!info->relocateable)
- {
- const char *name;
+ /* Handle relocatable links with a smaller loop. */
+ if (info->relocateable)
+ return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
+ input_section, contents, relocs,
+ local_syms, local_sections);
+
+ /* This is a final link. */
+
+ ret_val = true;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- dynobj = elf_hash_table (info)->dynobj;
- if (dynobj)
- srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj)
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ else
+ srelgot = NULL;
- 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_ASSERT(name != NULL);
- srel = bfd_get_section_by_name (dynobj, 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_ASSERT(section_name != NULL);
+ srel = bfd_get_section_by_name (dynobj, section_name);
- /* Find the gp value for this input bfd. */
- gotobj = alpha_elf_tdata (input_bfd)->gotobj;
- if (gotobj)
+ /* Find the gp value for this input bfd. */
+ gotobj = alpha_elf_tdata (input_bfd)->gotobj;
+ if (gotobj)
+ {
+ sgot = alpha_elf_tdata (gotobj)->got;
+ gp = _bfd_get_gp_value (gotobj);
+ if (gp == 0)
{
- sgot = alpha_elf_tdata (gotobj)->got;
- gp = _bfd_get_gp_value (gotobj);
- if (gp == 0)
- {
- gp = (sgot->output_section->vma
- + sgot->output_offset
- + 0x8000);
- _bfd_set_gp_value (gotobj, gp);
- }
- }
+ gp = (sgot->output_section->vma
+ + sgot->output_offset
+ + 0x8000);
+ _bfd_set_gp_value (gotobj, gp);
+ }
+ }
+ else
+ {
+ sgot = NULL;
+ gp = 0;
+ }
- tls_segment = elf_hash_table (info)->tls_segment;
- if (tls_segment)
- {
- dtp_base = alpha_get_dtprel_base (tls_segment);
- tp_base = alpha_get_tprel_base (tls_segment);
- }
+ local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries;
+
+ tls_segment = elf_hash_table (info)->tls_segment;
+ if (tls_segment)
+ {
+ dtp_base = alpha_get_dtprel_base (tls_segment);
+ tp_base = alpha_get_tprel_base (tls_segment);
}
+ else
+ dtp_base = tp_base = 0;
- rel = relocs;
relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
+ for (rel = relocs; rel < relend; rel++)
{
- struct alpha_elf_link_hash_entry *h;
+ struct alpha_elf_link_hash_entry *h = NULL;
struct alpha_elf_got_entry *gotent;
bfd_reloc_status_type r;
reloc_howto_type *howto;
unsigned long r_symndx;
- Elf_Internal_Sym *sym;
- asection *sec;
+ Elf_Internal_Sym *sym = NULL;
+ asection *sec = NULL;
bfd_vma value;
bfd_vma addend;
boolean dynamic_symbol_p;
- boolean undef_weak_ref;
+ boolean undef_weak_ref = false;
unsigned long r_type;
r_type = ELF64_R_TYPE(rel->r_info);
howto = elf64_alpha_howto_table + r_type;
r_symndx = ELF64_R_SYM(rel->r_info);
- if (info->relocateable)
- {
- /* This is a relocateable link. We don't have to change
- anything, unless the reloc is against a section symbol,
- in which case we have to adjust according to where the
- section symbol winds up in the output section. */
-
- /* 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;
-
- 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;
- }
- }
-
- continue;
- }
-
- /* This is a final link. */
-
- h = NULL;
- sym = NULL;
- sec = NULL;
- undef_weak_ref = false;
-
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
value = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
- gotent = alpha_elf_tdata(input_bfd)->local_got_entries[r_symndx];
+ if (local_got_entries)
+ gotent = local_got_entries[r_symndx];
+ else
+ gotent = NULL;
/* Need to adjust local GOT entries' addends for SEC_MERGE
unless it has been done already. */
if ((sec->flags & SEC_MERGE)
- && ELF_ST_TYPE (sym->st_info) == STT_SECTION
- && (elf_section_data (sec)->sec_info_type
- == ELF_INFO_TYPE_MERGE)
- && !gotent->reloc_xlated)
+ && ELF_ST_TYPE (sym->st_info) == STT_SECTION
+ && (elf_section_data (sec)->sec_info_type
+ == ELF_INFO_TYPE_MERGE)
+ && gotent
+ && !gotent->reloc_xlated)
{
struct alpha_elf_got_entry *ent;
asection *msec;
/* The source and destination gp must be the same. Note that
the source will always have an assigned gp, since we forced
one in check_relocs, but that the destination may not, as
- it might not have had any relocations at all. Also take
+ it might not have had any relocations at all. Also take
care not to crash if H is an undefined symbol. */
if (h != NULL && sec != NULL
&& alpha_elf_tdata (sec->owner)->gotobj
gotent != NULL;
gotent = gotent->next)
{
- asection *sgot = alpha_elf_tdata (gotent->gotobj)->got;
+ asection *sgot;
int r_type;
+ if (gotent->use_count == 0)
+ continue;
+
+ sgot = alpha_elf_tdata (gotent->gotobj)->got;
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ gotent->got_offset);
bfd_elf64_write_out_phdrs,
bfd_elf64_write_shdrs_and_ehdr,
bfd_elf64_write_relocs,
+ bfd_elf64_swap_symbol_in,
bfd_elf64_swap_symbol_out,
bfd_elf64_slurp_reloc_table,
bfd_elf64_slurp_symbol_table,