Line 1880... |
Line 1880... |
if (info->shared)
|
if (info->shared)
|
info->flags |= DF_STATIC_TLS;
|
info->flags |= DF_STATIC_TLS;
|
break;
|
break;
|
|
|
case R_ALPHA_TPREL64:
|
case R_ALPHA_TPREL64:
|
if (info->shared || maybe_dynamic)
|
if (info->shared && !info->pie)
|
need = NEED_DYNREL;
|
{
|
if (info->shared)
|
|
info->flags |= DF_STATIC_TLS;
|
info->flags |= DF_STATIC_TLS;
|
|
need = NEED_DYNREL;
|
|
}
|
|
else if (maybe_dynamic)
|
|
need = NEED_DYNREL;
|
break;
|
break;
|
}
|
}
|
|
|
if (need & NEED_GOT)
|
if (need & NEED_GOT)
|
{
|
{
|
Line 2146... |
Line 2149... |
|
|
/* Symbol versioning can create new symbols, and make our old symbols
|
/* Symbol versioning can create new symbols, and make our old symbols
|
indirect to the new ones. Consolidate the got and reloc information
|
indirect to the new ones. Consolidate the got and reloc information
|
in these situations. */
|
in these situations. */
|
|
|
static bfd_boolean
|
static void
|
elf64_alpha_merge_ind_symbols (struct alpha_elf_link_hash_entry *hi,
|
elf64_alpha_copy_indirect_symbol (struct bfd_link_info *info,
|
PTR dummy ATTRIBUTE_UNUSED)
|
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)
|
/* Do the merging in the superclass. */
|
return TRUE;
|
_bfd_elf_link_hash_copy_indirect(info, dir, ind);
|
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);
|
|
|
|
/* Merge the flags. Whee. */
|
/* Merge the flags. Whee. */
|
|
|
hs->flags |= hi->flags;
|
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
|
/* Merge the .got entries. Cannibalize the old symbol's list in
|
doing so, since we don't need it anymore. */
|
doing so, since we don't need it anymore. */
|
|
|
if (hs->got_entries == NULL)
|
if (hs->got_entries == NULL)
|
hs->got_entries = hi->got_entries;
|
hs->got_entries = hi->got_entries;
|
Line 2215... |
Line 2224... |
hs->reloc_entries = ri;
|
hs->reloc_entries = ri;
|
found_reloc:;
|
found_reloc:;
|
}
|
}
|
}
|
}
|
hi->reloc_entries = NULL;
|
hi->reloc_entries = NULL;
|
|
|
return TRUE;
|
|
}
|
}
|
|
|
/* Is it possible to merge two object file's .got tables? */
|
/* Is it possible to merge two object file's .got tables? */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
Line 2623... |
Line 2630... |
|
|
htab = alpha_elf_hash_table (info);
|
htab = alpha_elf_hash_table (info);
|
if (htab == NULL)
|
if (htab == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
/* First, take care of the indirect symbols created by versioning. */
|
|
alpha_elf_link_hash_traverse (htab, elf64_alpha_merge_ind_symbols,
|
|
NULL);
|
|
|
|
if (!elf64_alpha_size_got_sections (info))
|
if (!elf64_alpha_size_got_sections (info))
|
return FALSE;
|
return FALSE;
|
|
|
/* Allocate space for all of the .got subsections. */
|
/* Allocate space for all of the .got subsections. */
|
i = htab->got_list;
|
i = htab->got_list;
|
Line 2649... |
Line 2652... |
}
|
}
|
|
|
/* The number of dynamic relocations required by a static relocation. */
|
/* The number of dynamic relocations required by a static relocation. */
|
|
|
static int
|
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)
|
switch (r_type)
|
{
|
{
|
/* May appear in GOT entries. */
|
/* May appear in GOT entries. */
|
case R_ALPHA_TLSGD:
|
case R_ALPHA_TLSGD:
|
return (dynamic ? 2 : shared ? 1 : 0);
|
return (dynamic ? 2 : shared ? 1 : 0);
|
case R_ALPHA_TLSLDM:
|
case R_ALPHA_TLSLDM:
|
return shared;
|
return shared;
|
case R_ALPHA_LITERAL:
|
case R_ALPHA_LITERAL:
|
case R_ALPHA_GOTTPREL:
|
|
return dynamic || shared;
|
return dynamic || shared;
|
|
case R_ALPHA_GOTTPREL:
|
|
return dynamic || (shared && !pie);
|
case R_ALPHA_GOTDTPREL:
|
case R_ALPHA_GOTDTPREL:
|
return dynamic;
|
return dynamic;
|
|
|
/* May appear in data sections. */
|
/* May appear in data sections. */
|
case R_ALPHA_REFLONG:
|
case R_ALPHA_REFLONG:
|
case R_ALPHA_REFQUAD:
|
case R_ALPHA_REFQUAD:
|
case R_ALPHA_TPREL64:
|
|
return dynamic || shared;
|
return dynamic || shared;
|
|
case R_ALPHA_TPREL64:
|
|
return dynamic || (shared && !pie);
|
|
|
/* Everything else is illegal. We'll issue an error during
|
/* Everything else is illegal. We'll issue an error during
|
relocate_section. */
|
relocate_section. */
|
default:
|
default:
|
return 0;
|
return 0;
|
Line 2716... |
Line 2721... |
return TRUE;
|
return TRUE;
|
|
|
for (relent = h->reloc_entries; relent; relent = relent->next)
|
for (relent = h->reloc_entries; relent; relent = relent->next)
|
{
|
{
|
entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
|
entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
|
info->shared);
|
info->shared, info->pie);
|
if (entries)
|
if (entries)
|
{
|
{
|
relent->srel->size +=
|
relent->srel->size +=
|
entries * sizeof (Elf64_External_Rela) * relent->count;
|
entries * sizeof (Elf64_External_Rela) * relent->count;
|
if (relent->reltext)
|
if (relent->reltext)
|
Line 2759... |
Line 2764... |
return TRUE;
|
return TRUE;
|
|
|
entries = 0;
|
entries = 0;
|
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
|
for (gotent = h->got_entries; gotent ; gotent = gotent->next)
|
if (gotent->use_count > 0)
|
if (gotent->use_count > 0)
|
entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
|
entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type, dynamic,
|
dynamic, info->shared);
|
info->shared, info->pie);
|
|
|
if (entries > 0)
|
if (entries > 0)
|
{
|
{
|
bfd *dynobj = elf_hash_table(info)->dynobj;
|
bfd *dynobj = elf_hash_table(info)->dynobj;
|
asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
|
asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
|
Line 2810... |
Line 2815... |
for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
|
for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
|
for (gotent = local_got_entries[k];
|
for (gotent = local_got_entries[k];
|
gotent ; gotent = gotent->next)
|
gotent ; gotent = gotent->next)
|
if (gotent->use_count > 0)
|
if (gotent->use_count > 0)
|
entries += (alpha_dynamic_entries_for_reloc
|
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;
|
dynobj = elf_hash_table(info)->dynobj;
|
srel = bfd_get_section_by_name (dynobj, ".rela.got");
|
srel = bfd_get_section_by_name (dynobj, ".rela.got");
|
Line 3042... |
Line 3047... |
/* Can't relax dynamic symbols. */
|
/* Can't relax dynamic symbols. */
|
if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
|
if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
|
return TRUE;
|
return TRUE;
|
|
|
/* Can't use local-exec relocations in shared libraries. */
|
/* 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;
|
return TRUE;
|
|
|
if (r_type == R_ALPHA_LITERAL)
|
if (r_type == R_ALPHA_LITERAL)
|
{
|
{
|
/* Look for nice constant addresses. This includes the not-uncommon
|
/* Look for nice constant addresses. This includes the not-uncommon
|
Line 3500... |
Line 3506... |
pos[1] = info->contents + irel[1].r_offset;
|
pos[1] = info->contents + irel[1].r_offset;
|
pos[2] = info->contents + irel[2].r_offset;
|
pos[2] = info->contents + irel[2].r_offset;
|
pos[3] = info->contents + gpdisp->r_offset;
|
pos[3] = info->contents + gpdisp->r_offset;
|
pos[4] = pos[3] + gpdisp->r_addend;
|
pos[4] = pos[3] + gpdisp->r_addend;
|
|
|
|
/* 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
|
/* Generally, the positions are not allowed to be out of order, lest the
|
modified insn sequence have different register lifetimes. We can make
|
modified insn sequence have different register lifetimes. We can make
|
an exception when pos 1 is adjacent to pos 0. */
|
an exception when pos 1 is adjacent to pos 0. */
|
if (pos[1] + 4 == pos[0])
|
if (pos[1] + 4 == pos[0])
|
{
|
{
|
Line 3567... |
Line 3580... |
as appropriate. */
|
as appropriate. */
|
|
|
use_gottprel = FALSE;
|
use_gottprel = FALSE;
|
new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
|
new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : STN_UNDEF;
|
|
|
/* 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;
|
|
|
|
switch (!dynamic && !info->link_info->shared)
|
switch (!dynamic && !info->link_info->shared)
|
{
|
{
|
case 1:
|
case 1:
|
{
|
{
|
bfd_vma tp_base;
|
bfd_vma tp_base;
|
Line 4507... |
Line 4513... |
goto default_reloc;
|
goto default_reloc;
|
}
|
}
|
else if (r_type == R_ALPHA_TPREL64)
|
else if (r_type == R_ALPHA_TPREL64)
|
{
|
{
|
BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
|
BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
|
if (!info->shared)
|
if (!info->shared || info->pie)
|
{
|
{
|
value -= tp_base;
|
value -= tp_base;
|
goto default_reloc;
|
goto default_reloc;
|
}
|
}
|
dynindx = 0;
|
dynindx = 0;
|
Line 4628... |
Line 4634... |
goto default_reloc;
|
goto default_reloc;
|
|
|
case R_ALPHA_TPRELHI:
|
case R_ALPHA_TPRELHI:
|
case R_ALPHA_TPRELLO:
|
case R_ALPHA_TPRELLO:
|
case R_ALPHA_TPREL16:
|
case R_ALPHA_TPREL16:
|
if (info->shared)
|
if (info->shared && !info->pie)
|
{
|
{
|
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
(_("%B: TLS local exec code cannot be linked into shared objects"),
|
(_("%B: TLS local exec code cannot be linked into shared objects"),
|
input_bfd);
|
input_bfd);
|
ret_val = FALSE;
|
ret_val = FALSE;
|
Line 5441... |
Line 5447... |
elf64_alpha_create_dynamic_sections
|
elf64_alpha_create_dynamic_sections
|
#define elf_backend_adjust_dynamic_symbol \
|
#define elf_backend_adjust_dynamic_symbol \
|
elf64_alpha_adjust_dynamic_symbol
|
elf64_alpha_adjust_dynamic_symbol
|
#define elf_backend_merge_symbol_attribute \
|
#define elf_backend_merge_symbol_attribute \
|
elf64_alpha_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 \
|
#define elf_backend_always_size_sections \
|
elf64_alpha_always_size_sections
|
elf64_alpha_always_size_sections
|
#define elf_backend_size_dynamic_sections \
|
#define elf_backend_size_dynamic_sections \
|
elf64_alpha_size_dynamic_sections
|
elf64_alpha_size_dynamic_sections
|
#define elf_backend_omit_section_dynsym \
|
#define elf_backend_omit_section_dynsym \
|