/* Alpha specific support for 64-bit ELF
- Copyright 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright 1996, 97, 98, 1999 Free Software Foundation, Inc.
Contributed by Richard Henderson <rth@tamu.edu>.
This file is part of BFD, the Binary File Descriptor library.
PARAMS((bfd *, Elf64_Internal_Shdr *, char *));
static boolean elf64_alpha_fake_sections
PARAMS((bfd *, Elf64_Internal_Shdr *, asection *));
-static int elf64_alpha_additional_program_headers
- PARAMS((bfd *));
static boolean elf64_alpha_create_got_section
PARAMS((bfd *, struct bfd_link_info *));
static boolean elf64_alpha_create_dynamic_sections
static boolean elf64_alpha_calc_got_offsets_for_symbol
PARAMS ((struct alpha_elf_link_hash_entry *, PTR));
static void elf64_alpha_calc_got_offsets PARAMS ((struct bfd_link_info *));
-static void elf64_alpha_strip_section_from_output PARAMS ((asection *));
static boolean elf64_alpha_size_got_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean elf64_alpha_always_size_sections
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_adjust_dynindx
- PARAMS((struct elf_link_hash_entry *, PTR));
static boolean elf64_alpha_relocate_section
PARAMS((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
PARAMS((bfd *, struct bfd_link_info *));
static boolean elf64_alpha_final_link
PARAMS((bfd *, struct bfd_link_info *));
+static boolean elf64_alpha_merge_ind_symbols
+ PARAMS((struct alpha_elf_link_hash_entry *, PTR));
+static Elf_Internal_Rela * elf64_alpha_find_reloc_at_ofs
+ PARAMS ((Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_vma, int));
\f
struct alpha_elf_link_hash_entry
/* Should we do dynamic things to this symbol? */
#define alpha_elf_dynamic_symbol_p(h, info) \
- (((info)->shared && !(info)->symbolic && (h)->dynindx != -1) \
- || (((h)->elf_link_hash_flags \
- & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)) \
- == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)))
+ ((((info)->shared && !(info)->symbolic) \
+ || (((h)->elf_link_hash_flags \
+ & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)) \
+ == (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR)) \
+ || (h)->root.type == bfd_link_hash_undefweak \
+ || (h)->root.type == bfd_link_hash_defweak) \
+ && (h)->dynindx != -1)
/* Create an entry in a Alpha ELF linker hash table. */
{BFD_RELOC_16_PCREL, R_ALPHA_SREL16},
{BFD_RELOC_32_PCREL, R_ALPHA_SREL32},
{BFD_RELOC_64_PCREL, R_ALPHA_SREL64},
+
+/* The BFD_RELOC_ALPHA_USER_* relocations are used by the assembler to process
+ the explicit !<reloc>!sequence relocations, and are mapped into the normal
+ relocations at the end of processing. */
+ {BFD_RELOC_ALPHA_USER_LITERAL, R_ALPHA_LITERAL},
+ {BFD_RELOC_ALPHA_USER_LITUSE_BASE, R_ALPHA_LITUSE},
+ {BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, R_ALPHA_LITUSE},
+ {BFD_RELOC_ALPHA_USER_LITUSE_JSR, R_ALPHA_LITUSE},
+ {BFD_RELOC_ALPHA_USER_GPDISP, R_ALPHA_GPDISP},
+ {BFD_RELOC_ALPHA_USER_GPRELHIGH, R_ALPHA_GPRELHIGH},
+ {BFD_RELOC_ALPHA_USER_GPRELLOW, R_ALPHA_GPRELLOW},
};
/* Given a BFD reloc type, return a HOWTO structure. */
bfd_vma gp;
bfd *gotobj;
asection *tsec;
- Elf_Internal_Sym *elfsym;
struct alpha_elf_link_hash_entry *h;
struct alpha_elf_got_entry *gotent;
+ unsigned char other;
};
static Elf_Internal_Rela * elf64_alpha_relax_with_lituse
/* If the symbol is marked NOPV, we are being told the function never
needs its procedure value. */
- if (info->elfsym->st_other == STO_ALPHA_NOPV)
+ if (info->other == STO_ALPHA_NOPV)
return symval;
/* If the symbol is marked STD_GP, we are being told the function does
a normal ldgp in the first two words. */
- else if (info->elfsym->st_other == STO_ALPHA_STD_GPLOAD)
+ else if (info->other == STO_ALPHA_STD_GPLOAD)
;
/* Otherwise, we may be able to identify a GP load in the first two
bfd_vma ofs;
/* Load the relocations from the section that the target symbol is in. */
- tsec_relocs = (_bfd_elf64_link_read_relocs
- (info->abfd, info->tsec, (PTR) NULL,
- (Elf_Internal_Rela *) NULL,
- info->link_info->keep_memory));
- if (tsec_relocs == NULL)
- return 0;
- tsec_free = (info->link_info->keep_memory ? NULL : tsec_relocs);
- tsec_relend = tsec_relocs + info->tsec->reloc_count;
+ if (info->sec == info->tsec)
+ {
+ tsec_relocs = info->relocs;
+ tsec_relend = info->relend;
+ tsec_free = NULL;
+ }
+ else
+ {
+ tsec_relocs = (_bfd_elf64_link_read_relocs
+ (info->abfd, info->tsec, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->link_info->keep_memory));
+ if (tsec_relocs == NULL)
+ return 0;
+ tsec_relend = tsec_relocs + info->tsec->reloc_count;
+ tsec_free = (info->link_info->keep_memory ? NULL : tsec_relocs);
+ }
/* Recover the symbol's offset within the section. */
ofs = (symval - info->tsec->output_section->vma
for (irel = internal_relocs; irel < irelend; irel++)
{
bfd_vma symval;
- unsigned int insn;
Elf_Internal_Sym isym;
+ struct alpha_elf_got_entry *gotent;
if (ELF64_R_TYPE (irel->r_info) != (int) R_ALPHA_LITERAL)
continue;
/* Get the value of the symbol referred to by the reloc. */
if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
-
/* A local symbol. */
bfd_elf64_swap_symbol_in (abfd,
extsyms + ELF64_R_SYM (irel->r_info),
continue; /* who knows. */
info.h = NULL;
- info.gotent = local_got_entries[ELF64_R_SYM(irel->r_info)];
- info.elfsym = &isym;
+ info.other = isym.st_other;
+ gotent = local_got_entries[ELF64_R_SYM(irel->r_info)];
symval = isym.st_value;
}
else
{
unsigned long indx;
struct alpha_elf_link_hash_entry *h;
- struct alpha_elf_got_entry *gotent;
indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
h = alpha_elf_sym_hashes (abfd)[indx];
BFD_ASSERT (h != NULL);
+ 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;
+
/* We can't do anthing with undefined or dynamic symbols. */
if (h->root.root.type == bfd_link_hash_undefined
|| h->root.root.type == bfd_link_hash_undefweak
|| alpha_elf_dynamic_symbol_p (&h->root, link_info))
continue;
- /* Search for the got entry to be used by this relocation. */
- for (gotent = h->got_entries; gotent ; gotent = gotent->next)
- if (gotent->gotobj == info.gotobj
- && gotent->addend == irel->r_addend)
- break;
-
info.h = h;
info.gotent = gotent;
info.tsec = h->root.root.u.def.section;
- info.elfsym = &((elf_symbol_type *) h)->internal_elf_sym;
+ info.other = h->root.other;
+ gotent = h->got_entries;
symval = h->root.root.u.def.value;
}
+
+ /* Search for the got entry to be used by this relocation. */
+ while (gotent->gotobj != info.gotobj || gotent->addend != irel->r_addend)
+ gotent = gotent->next;
+ info.gotent = gotent;
+
symval += info.tsec->output_section->vma + info.tsec->output_offset;
symval += irel->r_addend;
}
}
+ *again = info.changed_contents || info.changed_relocs;
+
return true;
error_return:
return true;
}
-/* Return the number of additional phdrs we will need. */
-
-static int
-elf64_alpha_additional_program_headers (abfd)
- bfd *abfd;
-{
- asection *s;
- int ret;
-
- ret = 0;
-
- s = bfd_get_section_by_name (abfd, ".reginfo");
- if (s != NULL && (s->flags & SEC_LOAD) != 0)
- {
- /* We need a PT_ALPHA_REGINFO segment. */
- ++ret;
- }
-
- if (bfd_get_section_by_name (abfd, ".dynamic") != NULL
- && bfd_get_section_by_name (abfd, ".mdebug") != NULL)
- {
- /* We need a PT_ALPHA_RTPROC segment. */
- ++ret;
- }
-
- return ret;
-}
-
/* Create the .got section. */
static boolean
char *ext_hdr = NULL;
swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+ memset (debug, 0, sizeof(*debug));
ext_hdr = (char *) bfd_malloc ((size_t) swap->external_hdr_size);
if (ext_hdr == NULL && swap->external_hdr_size != 0)
{
output_section = sec->output_section;
if (output_section != NULL)
- h->esym.asym.value = (h->root.plt_offset
+ h->esym.asym.value = (h->root.plt.offset
+ sec->output_offset
+ output_section->vma);
else
else
rent->count++;
}
- else if (info->shared)
+ else if (info->shared && (sec->flags & SEC_ALLOC))
{
- /* If this is a shared library, we need a RELATIVE reloc. */
+ /* If this is a shared library, and the section is to be
+ loaded into memory, we need a RELATIVE reloc. */
sreloc->_raw_size += sizeof (Elf64_External_Rela);
}
break;
if (s->_raw_size == 0)
s->_raw_size = PLT_HEADER_SIZE;
- h->plt_offset = s->_raw_size;
+ h->plt.offset = s->_raw_size;
s->_raw_size += PLT_ENTRY_SIZE;
/* If this symbol is not defined in a regular file, and we are not
generating a shared library, then set the symbol to the location
in the .plt. This is required to make function pointers compare
equal between the normal executable and the shared library. */
- if (!info->shared)
+ if (! info->shared
+ && h->root.type != bfd_link_hash_defweak)
{
h->root.u.def.section = s;
- h->root.u.def.value = h->plt_offset;
+ h->root.u.def.value = h->plt.offset;
}
/* We also need a JMP_SLOT entry in the .rela.plt section. */
bfd *a, *b;
{
int total = alpha_elf_tdata (a)->total_got_entries;
+ bfd *bsub;
/* Trivial quick fallout test. */
if (total + alpha_elf_tdata (b)->total_got_entries <= MAX_GOT_ENTRIES)
/* Failing the common trivial comparison, we must effectively
perform the merge. Not actually performing the merge means that
we don't have to store undo information in case we fail. */
- {
- struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
- int i, n;
+ for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
+ {
+ struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes (bsub);
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (bsub)->symtab_hdr;
+ int i, n;
- n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
- for (i = 0; i < n; ++i)
- {
- struct alpha_elf_got_entry *ae, *be;
- struct alpha_elf_link_hash_entry *h;
+ n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *ae, *be;
+ struct alpha_elf_link_hash_entry *h;
- h = hashes[i];
- 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;
+ h = hashes[i];
+ 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;
- for (be = h->got_entries; be ; be = be->next)
- {
- if (be->use_count == 0)
- continue;
- if (be->gotobj != b)
- continue;
+ for (be = h->got_entries; be ; be = be->next)
+ {
+ if (be->use_count == 0)
+ continue;
+ if (be->gotobj != b)
+ continue;
- for (ae = h->got_entries; ae ; ae = ae->next)
- if (ae->gotobj == a && ae->addend == be->addend)
- goto global_found;
+ for (ae = h->got_entries; ae ; ae = ae->next)
+ if (ae->gotobj == a && ae->addend == be->addend)
+ goto global_found;
- if (++total > MAX_GOT_ENTRIES)
- return false;
- global_found:;
- }
- }
- }
+ if (++total > MAX_GOT_ENTRIES)
+ return false;
+ global_found:;
+ }
+ }
+ }
return true;
}
elf64_alpha_merge_gots (a, b)
bfd *a, *b;
{
- int total = alpha_elf_tdata(a)->total_got_entries;
+ int total = alpha_elf_tdata (a)->total_got_entries;
+ bfd *bsub;
/* Remember local expansion. */
{
- int e = alpha_elf_tdata(b)->n_local_got_entries;
+ int e = alpha_elf_tdata (b)->n_local_got_entries;
total += e;
- alpha_elf_tdata(a)->n_local_got_entries += e;
+ alpha_elf_tdata (a)->n_local_got_entries += e;
}
- /* Let the local .got entries know they are part of a new subsegment. */
- {
- struct alpha_elf_got_entry **local_got_entries;
- local_got_entries = alpha_elf_tdata(b)->local_got_entries;
- if (local_got_entries)
- {
- int i, n;
+ for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
+ {
+ struct alpha_elf_got_entry **local_got_entries;
+ struct alpha_elf_link_hash_entry **hashes;
+ Elf_Internal_Shdr *symtab_hdr;
+ int i, n;
+
+ /* Let the local .got entries know they are part of a new subsegment. */
+ local_got_entries = alpha_elf_tdata (bsub)->local_got_entries;
+ if (local_got_entries)
+ {
+ n = elf_tdata (bsub)->symtab_hdr.sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *ent;
+ for (ent = local_got_entries[i]; ent; ent = ent->next)
+ ent->gotobj = a;
+ }
+ }
- n = elf_tdata(b)->symtab_hdr.sh_info;
- for (i = 0; i < n; ++i)
- {
- struct alpha_elf_got_entry *gotent;
- for (gotent = local_got_entries[i]; gotent; gotent = gotent->next)
- gotent->gotobj = a;
- }
- }
- }
+ /* Merge the global .got entries. */
+ hashes = alpha_elf_sym_hashes (bsub);
+ symtab_hdr = &elf_tdata (bsub)->symtab_hdr;
- /* Merge the global .got entries. */
- {
- struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes(b);
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata(b)->symtab_hdr;
- int i, n;
+ n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
+ for (i = 0; i < n; ++i)
+ {
+ struct alpha_elf_got_entry *ae, *be, **pbe, **start;
+ struct alpha_elf_link_hash_entry *h;
- n = symtab_hdr->sh_size / symtab_hdr->sh_entsize - symtab_hdr->sh_info;
- for (i = 0; i < n; ++i)
- {
- struct alpha_elf_got_entry *ae, *be, **pbe, **start;
- struct alpha_elf_link_hash_entry *h;
+ h = hashes[i];
+ 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;
- h = hashes[i];
- 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;
+ start = &h->got_entries;
+ for (pbe = start, be = *start; be ; pbe = &be->next, be = be->next)
+ {
+ if (be->use_count == 0)
+ {
+ *pbe = be->next;
+ continue;
+ }
+ if (be->gotobj != b)
+ continue;
- start = &h->got_entries;
- for (pbe = start, be = *start; be ; pbe = &be->next, be = be->next)
- {
- if (be->use_count == 0)
- {
- *pbe = be->next;
- continue;
- }
- if (be->gotobj != b)
- continue;
+ for (ae = *start; ae ; ae = ae->next)
+ if (ae->gotobj == a && ae->addend == be->addend)
+ {
+ ae->flags |= be->flags;
+ ae->use_count += be->use_count;
+ *pbe = be->next;
+ goto global_found;
+ }
+ be->gotobj = a;
+ total += 1;
- for (ae = *start; ae ; ae = ae->next)
- if (ae->gotobj == a && ae->addend == be->addend)
- {
- ae->flags |= be->flags;
- ae->use_count += be->use_count;
- *pbe = be->next;
- goto global_found;
- }
- be->gotobj = a;
- total += 1;
+ global_found:;
+ }
+ }
- global_found:;
- }
- }
- }
+ alpha_elf_tdata (bsub)->gotobj = a;
+ }
+ alpha_elf_tdata (a)->total_got_entries = total;
+
+ /* Merge the two in_got chains. */
+ {
+ bfd *next;
- alpha_elf_tdata(a)->total_got_entries = total;
- alpha_elf_tdata(b)->gotobj = a;
+ bsub = a;
+ while ((next = alpha_elf_tdata (bsub)->in_got_link_next) != NULL)
+ bsub = next;
+
+ alpha_elf_tdata (bsub)->in_got_link_next = b;
+ }
}
/* Calculate the offsets for the got entries. */
}
}
-/* Remove a section from the output BFD. */
-
-static void
-elf64_alpha_strip_section_from_output (s)
- asection *s;
-{
- asection **spp;
-
- for (spp = &s->output_section->owner->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- continue;
- *spp = s->output_section->next;
- --s->output_section->owner->section_count;
-}
-
/* Constructs the gots. */
static boolean
bfd *output_bfd;
struct bfd_link_info *info;
{
- bfd *i, *got_list, *cur_got_obj, **cur_got_tail;
- int ngots;
-
- ngots = 0;
- got_list = NULL;
- cur_got_obj = NULL;
- cur_got_tail = NULL;
- for (i = info->input_bfds; i ; i = i->link_next)
- {
- bfd *this_got = alpha_elf_tdata (i)->gotobj;
+ bfd *i, *got_list, *cur_got_obj;
+ int something_changed = 0;
- /* Don't play if there is no .got for this input file. */
- if (this_got == NULL)
- continue;
+ got_list = alpha_elf_hash_table (info)->got_list;
- if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES)
+ /* 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)
{
- /* Yikes! A single object file has too many entries. */
- (*_bfd_error_handler)
- (_("%s: .got subsegment exceeds 64K (size %d)"),
- bfd_get_filename(i),
- alpha_elf_tdata(this_got)->total_got_entries * 8);
- return false;
- }
+ bfd *this_got = alpha_elf_tdata (i)->gotobj;
+ if (this_got == NULL)
+ continue;
- if (cur_got_obj)
- {
- if (this_got == cur_got_obj)
- ; /* Some previous pass merged us already. */
- else if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+ /* We are assuming no merging has yet ocurred. */
+ BFD_ASSERT (this_got == i);
+
+ if (alpha_elf_tdata (this_got)->total_got_entries > MAX_GOT_ENTRIES)
{
- elf64_alpha_merge_gots (cur_got_obj, i);
- *cur_got_tail = i;
+ /* Yikes! A single object file has too many entries. */
+ (*_bfd_error_handler)
+ (_("%s: .got subsegment exceeds 64K (size %d)"),
+ bfd_get_filename (i),
+ alpha_elf_tdata (this_got)->total_got_entries * 8);
+ return false;
}
+
+ if (got_list == NULL)
+ got_list = this_got;
else
- {
- if (++ngots == 2)
- {
- (*info->callbacks->warning)
- (info, _("using multiple gp values"), (char *) NULL,
- output_bfd, (asection *) NULL, (bfd_vma) 0);
- }
- *cur_got_tail = NULL;
- alpha_elf_tdata(cur_got_obj)->got_link_next = got_list;
- got_list = cur_got_obj;
- cur_got_obj = i;
- }
+ alpha_elf_tdata(cur_got_obj)->got_link_next = this_got;
+ cur_got_obj = this_got;
+ }
+
+ /* Strange degenerate case of no got references. */
+ if (got_list == NULL)
+ 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;
+ i = alpha_elf_tdata(cur_got_obj)->got_link_next;
+ while (i != NULL)
+ {
+ if (elf64_alpha_can_merge_gots (cur_got_obj, i))
+ {
+ elf64_alpha_merge_gots (cur_got_obj, i);
+ i = alpha_elf_tdata(i)->got_link_next;
+ alpha_elf_tdata(cur_got_obj)->got_link_next = i;
+ something_changed = 1;
}
else
{
- ++ngots;
cur_got_obj = i;
+ i = alpha_elf_tdata(i)->got_link_next;
}
- cur_got_tail = &alpha_elf_tdata(i)->in_got_link_next;
}
- if (cur_got_obj)
- alpha_elf_tdata (cur_got_obj)->got_link_next = got_list;
- alpha_elf_hash_table (info)->got_list = cur_got_obj;
-
- /* Once the gots have been merged, fill in the got offsets for everything
- therein. */
- elf64_alpha_calc_got_offsets (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);
return true;
}
}
/* If the symbol is dynamic, we'll need all the relocations in their
- natural form. If it has been forced local, we'll need the same
- number of RELATIVE relocations. */
- if (alpha_elf_dynamic_symbol_p (&h->root, info)
- || (info->shared && h->root.dynindx == -1))
- {
- struct alpha_elf_reloc_entry *relent;
+ natural form. If this is a shared object, and it has been forced
+ local, we'll need the same number of RELATIVE relocations. */
- for (relent = h->reloc_entries; relent; relent = relent->next)
- {
- relent->srel->_raw_size +=
- sizeof (Elf64_External_Rela) * relent->count;
- }
-
- /* Only add a .rela.got entry if we're not using a .plt entry. */
- if (h->root.plt_offset == MINUS_ONE)
- {
- bfd *dynobj = elf_hash_table(info)->dynobj;
- struct alpha_elf_got_entry *gotent;
- bfd_size_type count = 0;
- asection *srel;
-
- for (gotent = h->got_entries; gotent ; gotent = gotent->next)
- count++;
- if (count > 0)
- {
- srel = bfd_get_section_by_name (dynobj, ".rela.got");
- BFD_ASSERT (srel != NULL);
- srel->_raw_size += sizeof (Elf64_External_Rela) * count;
- }
- }
- }
- /* Otherwise, shared objects require RELATIVE relocs for all REFQUAD
- and REFLONG relocations. */
- else if (info->shared)
+ if (alpha_elf_dynamic_symbol_p (&h->root, info) || info->shared)
{
struct alpha_elf_reloc_entry *relent;
+ bfd *dynobj;
+ struct alpha_elf_got_entry *gotent;
+ bfd_size_type count;
+ asection *srel;
for (relent = h->reloc_entries; relent; relent = relent->next)
if (relent->rtype == R_ALPHA_REFLONG
relent->srel->_raw_size +=
sizeof(Elf64_External_Rela) * relent->count;
}
+
+ dynobj = elf_hash_table(info)->dynobj;
+ count = 0;
+
+ for (gotent = h->got_entries; gotent ; gotent = gotent->next)
+ count++;
+
+ /* If we are using a .plt entry, subtract one, as the first
+ reference uses a .rela.plt entry instead. */
+ if (h->root.plt.offset != MINUS_ONE)
+ count--;
+
+ if (count > 0)
+ {
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srel != NULL);
+ srel->_raw_size += sizeof (Elf64_External_Rela) * count;
+ }
}
return true;
}
if (strip)
- elf64_alpha_strip_section_from_output (s);
+ _bfd_strip_section_from_output (info, s);
else
{
/* Allocate memory for the section contents. */
}
}
- /* If we are generating a shared library, we generate a section
- symbol for each output section. These are local symbols, which
- means that they must come first in the dynamic symbol table.
- That means we must increment the dynamic symbol index of every
- other dynamic symbol. */
- if (info->shared)
- {
- long c[2], i;
- asection *p;
-
- c[0] = 0;
- c[1] = bfd_count_sections (output_bfd);
-
- elf_hash_table (info)->dynsymcount += c[1];
- elf_link_hash_traverse (elf_hash_table(info),
- elf64_alpha_adjust_dynindx,
- (PTR) c);
-
- for (i = 1, p = output_bfd->sections;
- p != NULL;
- p = p->next, i++)
- {
- elf_section_data (p)->dynindx = i;
- /* These symbols will have no names, so we don't need to
- fiddle with dynstr_index. */
- }
- }
-
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Add some entries to the .dynamic section. We fill in the
{
if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
return false;
+ info->flags |= DF_TEXTREL;
}
}
return true;
}
-/* Increment the index of a dynamic symbol by a given amount. Called
- via elf_link_hash_traverse. */
-
-static boolean
-elf64_alpha_adjust_dynindx (h, cparg)
- struct elf_link_hash_entry *h;
- PTR cparg;
-{
- long *cp = (long *)cparg;
-
- if (h->dynindx >= cp[0])
- h->dynindx += cp[1];
-
- return true;
-}
-
/* Relocate an Alpha ELF section. */
static boolean
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;
}
else if (h->root.root.type == bfd_link_hash_undefweak)
relocation = 0;
- else if (info->shared && !info->symbolic)
+ else if (info->shared && !info->symbolic
+ && !info->no_undefined
+ && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
relocation = 0;
else
{
if (!((*info->callbacks->undefined_symbol)
(info, h->root.root.root.string, input_bfd,
- input_section, rel->r_offset)))
+ input_section, rel->r_offset,
+ (!info->shared || info->no_undefined
+ || ELF_ST_VISIBILITY (h->root.other)))))
return false;
relocation = 0;
}
case R_ALPHA_LITERAL:
{
struct alpha_elf_got_entry *gotent;
+ boolean dynamic_symbol;
BFD_ASSERT(sgot != NULL);
BFD_ASSERT(gp != 0);
if (h != NULL)
{
gotent = h->got_entries;
- BFD_ASSERT(gotent != NULL);
-
- while (gotent->gotobj != gotobj || gotent->addend != addend)
- gotent = gotent->next;
-
- /* Initialize the .got entry's value. */
- if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
- {
- bfd_put_64 (output_bfd, relocation+addend,
- sgot->contents + gotent->got_offset);
-
- /* If the symbol has been forced local, output a
- RELATIVE reloc, otherwise it will be handled in
- finish_dynamic_symbol. */
- if (info->shared && h->root.dynindx == -1)
- {
- Elf_Internal_Rela outrel;
-
- BFD_ASSERT(srelgot != NULL);
-
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + gotent->got_offset);
- outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
- outrel.r_addend = 0;
-
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- ((Elf64_External_Rela *)
- srelgot->contents)
- + srelgot->reloc_count++);
- }
-
- gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
- }
+ dynamic_symbol = alpha_elf_dynamic_symbol_p (&h->root, info);
}
else
{
gotent = (alpha_elf_tdata(input_bfd)->
local_got_entries[r_symndx]);
- while (gotent->addend != addend)
- gotent = gotent->next;
+ dynamic_symbol = false;
+ }
+
+ BFD_ASSERT(gotent != NULL);
- if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
+ while (gotent->gotobj != gotobj || gotent->addend != addend)
+ gotent = gotent->next;
+
+ BFD_ASSERT(gotent->use_count >= 1);
+
+ /* Initialize the .got entry's value. */
+ if (!(gotent->flags & ALPHA_ELF_GOT_ENTRY_RELOCS_DONE))
+ {
+ bfd_put_64 (output_bfd, relocation+addend,
+ sgot->contents + gotent->got_offset);
+
+ /* If the symbol has been forced local, output a
+ RELATIVE reloc, otherwise it will be handled in
+ finish_dynamic_symbol. */
+ if (info->shared && !dynamic_symbol)
{
- bfd_put_64 (output_bfd, relocation+addend,
- sgot->contents + gotent->got_offset);
-
- /* Local got entries need RELATIVE relocs in shared
- libraries. */
- if (info->shared)
- {
- Elf_Internal_Rela outrel;
-
- BFD_ASSERT(srelgot != NULL);
-
- outrel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
- + gotent->got_offset);
- outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
- outrel.r_addend = 0;
-
- bfd_elf64_swap_reloca_out (output_bfd, &outrel,
- ((Elf64_External_Rela *)
- srelgot->contents)
- + srelgot->reloc_count++);
- }
-
- gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
+ Elf_Internal_Rela outrel;
+
+ BFD_ASSERT(srelgot != NULL);
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + gotent->got_offset);
+ outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
+ outrel.r_addend = 0;
+
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ ((Elf64_External_Rela *)
+ srelgot->contents)
+ + srelgot->reloc_count++);
+ BFD_ASSERT (sizeof(Elf64_External_Rela)
+ * srelgot->reloc_count
+ <= srelgot->_cooked_size);
}
+
+ gotent->flags |= ALPHA_ELF_GOT_ENTRY_RELOCS_DONE;
}
/* Figure the gprel relocation. */
outrel.r_addend = addend;
addend = 0, relocation = 0;
}
- else if (info->shared)
+ else if (info->shared && (input_section->flags & SEC_ALLOC))
{
outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
outrel.r_addend = 0;
((Elf64_External_Rela *)
srel->contents)
+ srel->reloc_count++);
+ BFD_ASSERT (sizeof(Elf64_External_Rela) * srel->reloc_count
+ <= srel->_cooked_size);
}
goto default_reloc;
{
bfd *dynobj = elf_hash_table(info)->dynobj;
- if (h->plt_offset != MINUS_ONE)
+ if (h->plt.offset != MINUS_ONE)
{
/* Fill in the .plt entry for this symbol. */
asection *splt, *sgot, *srel;
+ gotent->got_offset);
plt_addr = (splt->output_section->vma
+ splt->output_offset
- + h->plt_offset);
+ + h->plt.offset);
- plt_index = (h->plt_offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
+ plt_index = (h->plt.offset - PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
/* Fill in the entry in the procedure linkage table. */
{
unsigned insn1, insn2, insn3;
- insn1 = PLT_ENTRY_WORD1 | ((-(h->plt_offset + 4) >> 2) & 0x1fffff);
+ insn1 = PLT_ENTRY_WORD1 | ((-(h->plt.offset + 4) >> 2) & 0x1fffff);
insn2 = PLT_ENTRY_WORD2;
insn3 = PLT_ENTRY_WORD3;
- bfd_put_32 (output_bfd, insn1, splt->contents + h->plt_offset);
- bfd_put_32 (output_bfd, insn2, splt->contents + h->plt_offset + 4);
- bfd_put_32 (output_bfd, insn3, splt->contents + h->plt_offset + 8);
+ bfd_put_32 (output_bfd, insn1, splt->contents + h->plt.offset);
+ bfd_put_32 (output_bfd, insn2, splt->contents + h->plt.offset + 4);
+ bfd_put_32 (output_bfd, insn3, splt->contents + h->plt.offset + 8);
}
/* Fill in the entry in the .rela.plt section. */
bfd_put_64 (output_bfd, plt_addr, sgot->contents + gotent->got_offset);
/* Subsequent .got entries will continue to bounce through the .plt. */
- while ((gotent = gotent->next) != NULL)
+ if (gotent->next)
{
- sgot = alpha_elf_tdata(gotent->gotobj)->got;
- BFD_ASSERT(sgot != NULL);
- BFD_ASSERT(gotent->addend == 0);
+ srel = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (! info->shared || srel != NULL);
- bfd_put_64 (output_bfd, plt_addr,
- sgot->contents + gotent->got_offset);
+ gotent = gotent->next;
+ do
+ {
+ sgot = alpha_elf_tdata(gotent->gotobj)->got;
+ BFD_ASSERT(sgot != NULL);
+ BFD_ASSERT(gotent->addend == 0);
+
+ bfd_put_64 (output_bfd, plt_addr,
+ sgot->contents + gotent->got_offset);
+
+ if (info->shared)
+ {
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + gotent->got_offset);
+ outrel.r_info = ELF64_R_INFO(0, R_ALPHA_RELATIVE);
+ outrel.r_addend = 0;
+
+ bfd_elf64_swap_reloca_out (output_bfd, &outrel,
+ ((Elf64_External_Rela *)
+ srel->contents)
+ + srel->reloc_count++);
+ BFD_ASSERT (sizeof(Elf64_External_Rela) * srel->reloc_count
+ <= srel->_cooked_size);
+ }
+
+ gotent = gotent->next;
+ }
+ while (gotent != NULL);
}
}
else if (alpha_elf_dynamic_symbol_p (h, info))
bfd_elf64_swap_reloca_out (output_bfd, &outrel,
((Elf64_External_Rela *)srel->contents
+ srel->reloc_count++));
+ BFD_ASSERT (sizeof(Elf64_External_Rela) * srel->reloc_count
+ <= srel->_cooked_size);
}
}
}
}
- if (info->shared)
- {
- asection *sdynsym;
- asection *s;
- Elf_Internal_Sym sym;
-
- /* Set up the section symbols for the output sections. */
-
- sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
- BFD_ASSERT (sdynsym != NULL);
-
- sym.st_size = 0;
- sym.st_name = 0;
- sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
- sym.st_other = 0;
-
- for (s = output_bfd->sections; s != NULL; s = s->next)
- {
- int indx;
-
- sym.st_value = s->vma;
-
- indx = elf_section_data (s)->this_idx;
- BFD_ASSERT (indx > 0);
- sym.st_shndx = indx;
-
- bfd_elf64_swap_symbol_out (output_bfd, &sym,
- (PTR) (((Elf64_External_Sym *)
- sdynsym->contents)
- + elf_section_data (s)->dynindx));
- }
-
- /* Set the sh_info field of the output .dynsym section to the
- index of the first global symbol. */
- elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
- bfd_count_sections (output_bfd) + 1;
- }
-
return true;
}
HDRR *symhdr = &debug.symbolic_header;
PTR mdebug_handle = NULL;
+#if 0
+ if (++ngots == 2)
+ {
+ (*info->callbacks->warning)
+ (info, _("using multiple gp values"), (char *) NULL,
+ output_bfd, (asection *) NULL, (bfd_vma) 0);
+ }
+#endif
+
/* Go through the sections and collect the .reginfo and .mdebug
information. */
reginfo_sec = NULL;
elf64_alpha_read_ecoff_info
};
\f
+/* Use a non-standard hash bucket size of 8. */
+
+const struct elf_size_info alpha_elf_size_info =
+{
+ sizeof (Elf64_External_Ehdr),
+ sizeof (Elf64_External_Phdr),
+ sizeof (Elf64_External_Shdr),
+ sizeof (Elf64_External_Rel),
+ sizeof (Elf64_External_Rela),
+ sizeof (Elf64_External_Sym),
+ sizeof (Elf64_External_Dyn),
+ sizeof (Elf_External_Note),
+ 8,
+ 1,
+ 64, 8,
+ ELFCLASS64, EV_CURRENT,
+ bfd_elf64_write_out_phdrs,
+ bfd_elf64_write_shdrs_and_ehdr,
+ bfd_elf64_write_relocs,
+ bfd_elf64_swap_symbol_out,
+ bfd_elf64_slurp_reloc_table,
+ bfd_elf64_slurp_symbol_table,
+ bfd_elf64_swap_dyn_in,
+ bfd_elf64_swap_dyn_out,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
#define TARGET_LITTLE_SYM bfd_elf64_alpha_vec
#define TARGET_LITTLE_NAME "elf64-alpha"
#define ELF_ARCH bfd_arch_alpha
elf64_alpha_section_from_shdr
#define elf_backend_fake_sections \
elf64_alpha_fake_sections
-#define elf_backend_additional_program_headers \
- elf64_alpha_additional_program_headers
#define bfd_elf64_bfd_is_local_label_name \
elf64_alpha_is_local_label_name
#define elf_backend_ecoff_debug_swap \
&elf64_alpha_ecoff_debug_swap
+#define elf_backend_size_info \
+ alpha_elf_size_info
+
/*
* A few constants that determine how the .plt section is set up.
*/
#define elf_backend_want_got_plt 0
#define elf_backend_plt_readonly 0
#define elf_backend_want_plt_sym 1
+#define elf_backend_got_header_size 0
+#define elf_backend_plt_header_size PLT_HEADER_SIZE
#include "elf64-target.h"