#ifndef RELATIVE_DYNRELOCS
#define RELATIVE_DYNRELOCS 0
#define IS_ABSOLUTE_RELOC(r_type) 1
+#define pc_dynrelocs(hh) 0
#endif
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
asection *id_sec;
};
+enum _tls_type
+ {
+ GOT_UNKNOWN = 0,
+ GOT_NORMAL = 1,
+ GOT_TLS_GD = 2,
+ GOT_TLS_LDM = 4,
+ GOT_TLS_IE = 8
+ };
+
struct elf32_hppa_link_hash_entry
{
struct elf_link_hash_entry eh;
#endif
} *dyn_relocs;
- enum
- {
- GOT_UNKNOWN = 0, GOT_NORMAL = 1, GOT_TLS_GD = 2, GOT_TLS_LDM = 4, GOT_TLS_IE = 8
- } tls_type;
+ ENUM_BITFIELD (_tls_type) tls_type : 8;
/* Set if this symbol is used by a plabel reloc. */
unsigned int plabel:1;
hh_dir = hppa_elf_hash_entry (eh_dir);
hh_ind = hppa_elf_hash_entry (eh_ind);
- if (hh_ind->dyn_relocs != NULL)
+ if (hh_ind->dyn_relocs != NULL
+ && eh_ind->root.type == bfd_link_hash_indirect)
{
if (hh_dir->dyn_relocs != NULL)
{
const Elf_Internal_Rela *rela_end;
struct elf32_hppa_link_hash_table *htab;
asection *sreloc;
- int tls_type = GOT_UNKNOWN, old_tls_type = GOT_UNKNOWN;
if (bfd_link_relocatable (info))
return TRUE;
while (hh->eh.root.type == bfd_link_hash_indirect
|| hh->eh.root.type == bfd_link_hash_warning)
hh = hppa_elf_hash_entry (hh->eh.root.u.i.link);
-
- /* PR15323, ref flags aren't set for references in the same
- object. */
- hh->eh.root.non_ir_ref_regular = 1;
}
r_type = ELF32_R_TYPE (rela->r_info);
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
- if (bfd_link_pic (info))
+ if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
need_entry = NEED_GOT;
break;
/* Now carry out our orders. */
if (need_entry & NEED_GOT)
{
+ int tls_type = GOT_NORMAL;
+
switch (r_type)
{
default:
- tls_type = GOT_NORMAL;
break;
case R_PARISC_TLS_GD21L:
case R_PARISC_TLS_GD14R:
- tls_type |= GOT_TLS_GD;
+ tls_type = GOT_TLS_GD;
break;
case R_PARISC_TLS_LDM21L:
case R_PARISC_TLS_LDM14R:
- tls_type |= GOT_TLS_LDM;
+ tls_type = GOT_TLS_LDM;
break;
case R_PARISC_TLS_IE21L:
case R_PARISC_TLS_IE14R:
- tls_type |= GOT_TLS_IE;
+ tls_type = GOT_TLS_IE;
break;
}
return FALSE;
}
- if (r_type == R_PARISC_TLS_LDM21L
- || r_type == R_PARISC_TLS_LDM14R)
- htab->tls_ldm_got.refcount += 1;
- else
+ if (hh != NULL)
{
- if (hh != NULL)
- {
- hh->eh.got.refcount += 1;
- old_tls_type = hh->tls_type;
- }
+ if (tls_type == GOT_TLS_LDM)
+ htab->tls_ldm_got.refcount += 1;
else
- {
- bfd_signed_vma *local_got_refcounts;
-
- /* This is a global offset table entry for a local symbol. */
- local_got_refcounts = hppa32_elf_local_refcounts (abfd);
- if (local_got_refcounts == NULL)
- return FALSE;
- local_got_refcounts[r_symndx] += 1;
-
- old_tls_type = hppa_elf_local_got_tls_type (abfd) [r_symndx];
- }
-
- tls_type |= old_tls_type;
+ hh->eh.got.refcount += 1;
+ hh->tls_type |= tls_type;
+ }
+ else
+ {
+ bfd_signed_vma *local_got_refcounts;
- if (old_tls_type != tls_type)
- {
- if (hh != NULL)
- hh->tls_type = tls_type;
- else
- hppa_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
- }
+ /* This is a global offset table entry for a local symbol. */
+ local_got_refcounts = hppa32_elf_local_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ if (tls_type == GOT_TLS_LDM)
+ htab->tls_ldm_got.refcount += 1;
+ else
+ local_got_refcounts[r_symndx] += 1;
+ hppa_elf_local_got_tls_type (abfd) [r_symndx] |= tls_type;
}
}
return NULL;
}
+/* Return true if we have dynamic relocs against H or any of its weak
+ aliases, that apply to read-only sections. Cannot be used after
+ size_dynamic_sections. */
+
+static bfd_boolean
+alias_readonly_dynrelocs (struct elf_link_hash_entry *eh)
+{
+ struct elf32_hppa_link_hash_entry *hh = hppa_elf_hash_entry (eh);
+ do
+ {
+ if (readonly_dynrelocs (&hh->eh))
+ return TRUE;
+ hh = hppa_elf_hash_entry (hh->eh.u.alias);
+ } while (hh != NULL && &hh->eh != eh);
+
+ return FALSE;
+}
+
/* 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
if (eh->type == STT_FUNC
|| eh->needs_plt)
{
- /* After adjust_dynamic_symbol, non_got_ref set in the non-pic
- case means that dyn_relocs for this symbol should be
- discarded; We either want the symbol to remain undefined, or
- we have a local definition of some sort. The "local
- definition" for non-function symbols may be due to creating a
- local definition in .dynbss.
- Unlike other targets, elf32-hppa.c does not define a function
- symbol in a non-pic executable on PLT stub code, so we don't
- have a local definition in that case. dyn_relocs therefore
- should not be discarded for function symbols, generally.
- However we should discard dyn_relocs if we've decided that an
- undefined function symbol is local, for example due to
- non-default visibility, or UNDEFWEAK_NO_DYNAMIC_RELOC is
- true for an undefined weak symbol. */
bfd_boolean local = (SYMBOL_CALLS_LOCAL (info, eh)
|| UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh));
- /* Prior to adjust_dynamic_symbol, non_got_ref set means that
- check_relocs set up some dyn_relocs for this symbol.
- The !non_got_ref term here is saying that if we didn't have
- any dyn_relocs set up by check_relocs, then we don't want
- relocate_section looking for them.
- FIXME: Get rid of the inversion, so non_got_ref set after
- dyn_relocs means we do have dyn_relocs. */
- eh->non_got_ref = local || !eh->non_got_ref;
+ /* Discard dyn_relocs when non-pic if we've decided that a
+ function symbol is local. */
+ if (!bfd_link_pic (info) && local)
+ hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
/* If the symbol is used by a plabel, we must allocate a PLT slot.
The refcounts are not reliable when it has been hidden since
eh->needs_plt = 0;
}
+ /* Unlike other targets, elf32-hppa.c does not define a function
+ symbol in a non-pic executable on PLT stub code, so we don't
+ have a local definition in that case. ie. dyn_relocs can't
+ be discarded. */
+
/* Function symbols can't have copy relocs. */
return TRUE;
}
/* If this is a weak symbol, and there is a real definition, the
processor independent code will have arranged for us to see the
real definition first, and we can just use the same value. */
- if (eh->u.weakdef != NULL)
+ if (eh->is_weakalias)
{
- if (eh->u.weakdef->root.type != bfd_link_hash_defined
- && eh->u.weakdef->root.type != bfd_link_hash_defweak)
- abort ();
- eh->root.u.def.section = eh->u.weakdef->root.u.def.section;
- eh->root.u.def.value = eh->u.weakdef->root.u.def.value;
+ struct elf_link_hash_entry *def = weakdef (eh);
+ BFD_ASSERT (def->root.type == bfd_link_hash_defined);
+ eh->root.u.def.section = def->root.u.def.section;
+ eh->root.u.def.value = def->root.u.def.value;
if (ELIMINATE_COPY_RELOCS)
- eh->non_got_ref = eh->u.weakdef->non_got_ref;
+ eh->non_got_ref = def->non_got_ref;
return TRUE;
}
/* If there are no references to this symbol that do not use the
GOT, we don't need to generate a copy reloc. */
if (!eh->non_got_ref)
- {
- eh->non_got_ref = 1;
- return TRUE;
- }
+ return TRUE;
/* If -z nocopyreloc was given, we won't generate them either. */
if (info->nocopyreloc)
- {
- eh->non_got_ref = 0;
- return TRUE;
- }
+ return TRUE;
if (ELIMINATE_COPY_RELOCS
- && !readonly_dynrelocs (eh))
+ && !alias_readonly_dynrelocs (eh))
{
/* If we didn't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- eh->non_got_ref = 0;
return TRUE;
}
eh->needs_copy = 1;
}
+ /* We no longer want dyn_relocs. */
+ hppa_elf_hash_entry (eh)->dyn_relocs = NULL;
return _bfd_elf_adjust_dynamic_copy (info, eh, sec);
}
return TRUE;
}
+/* Calculate size of GOT entries for symbol given its TLS_TYPE. */
+
+static inline unsigned int
+got_entries_needed (int tls_type)
+{
+ unsigned int need = 0;
+
+ if ((tls_type & GOT_NORMAL) != 0)
+ need += GOT_ENTRY_SIZE;
+ if ((tls_type & GOT_TLS_GD) != 0)
+ need += GOT_ENTRY_SIZE * 2;
+ if ((tls_type & GOT_TLS_IE) != 0)
+ need += GOT_ENTRY_SIZE;
+ return need;
+}
+
+/* Calculate size of relocs needed for symbol given its TLS_TYPE and
+ NEEDed GOT entries. KNOWN says a TPREL offset can be calculated
+ at link time. */
+
+static inline unsigned int
+got_relocs_needed (int tls_type, unsigned int need, bfd_boolean known)
+{
+ /* All the entries we allocated need relocs.
+ Except IE in executable with a local symbol. We could also omit
+ the DTPOFF reloc on the second word of a GD entry under the same
+ condition as that for IE, but ld.so might want to differentiate
+ LD and GD entries at some stage. */
+ if ((tls_type & GOT_TLS_IE) != 0 && known)
+ need -= GOT_ENTRY_SIZE;
+ return need * sizeof (Elf32_External_Rela) / GOT_ENTRY_SIZE;
+}
+
/* Allocate space in .plt, .got and associated reloc sections for
global syms. */
if (eh->got.refcount > 0)
{
+ unsigned int need;
+
if (!ensure_undef_dynamic (info, eh))
return FALSE;
sec = htab->etab.sgot;
eh->got.offset = sec->size;
- sec->size += GOT_ENTRY_SIZE;
- /* R_PARISC_TLS_GD* needs two GOT entries */
- if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
- sec->size += GOT_ENTRY_SIZE * 2;
- else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
- sec->size += GOT_ENTRY_SIZE;
+ need = got_entries_needed (hh->tls_type);
+ sec->size += need;
if (htab->etab.dynamic_sections_created
&& (bfd_link_pic (info)
|| (eh->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, eh)))
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
{
- htab->etab.srelgot->size += sizeof (Elf32_External_Rela);
- if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
- htab->etab.srelgot->size += 2 * sizeof (Elf32_External_Rela);
- else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
- htab->etab.srelgot->size += sizeof (Elf32_External_Rela);
+ bfd_boolean tprel_known = (bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info, eh));
+ htab->etab.srelgot->size
+ += got_relocs_needed (hh->tls_type, need, tprel_known);
}
}
else
if (!htab->etab.dynamic_sections_created)
hh->dyn_relocs = NULL;
+ /* Discard relocs on undefined syms with non-default visibility. */
+ else if ((eh->root.type == bfd_link_hash_undefined
+ && ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
+ hh->dyn_relocs = NULL;
+
if (hh->dyn_relocs == NULL)
return TRUE;
changes. */
if (bfd_link_pic (info))
{
- /* Discard relocs on undefined syms with non-default visibility. */
- if ((eh->root.type == bfd_link_hash_undefined
- && ELF_ST_VISIBILITY (eh->other) != STV_DEFAULT)
- || UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
- hh->dyn_relocs = NULL;
-
#if RELATIVE_DYNRELOCS
- else if (SYMBOL_CALLS_LOCAL (info, eh))
+ if (SYMBOL_CALLS_LOCAL (info, eh))
{
struct elf32_hppa_dyn_reloc_entry **hdh_pp;
symbols which turn out to need copy relocs or are not
dynamic. */
- if (!eh->non_got_ref
- && !eh->def_regular)
+ if (eh->dynamic_adjusted
+ && !eh->def_regular
+ && !ELF_COMMON_DEF_P (eh))
{
if (!ensure_undef_dynamic (info, eh))
return FALSE;
{
if (*local_got > 0)
{
+ unsigned int need;
+
*local_got = sec->size;
- sec->size += GOT_ENTRY_SIZE;
- if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
- sec->size += 2 * GOT_ENTRY_SIZE;
- else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
- sec->size += GOT_ENTRY_SIZE;
+ need = got_entries_needed (*local_tls_type);
+ sec->size += need;
if (bfd_link_pic (info))
- {
- srel->size += sizeof (Elf32_External_Rela);
- if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
- srel->size += 2 * sizeof (Elf32_External_Rela);
- else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
- srel->size += sizeof (Elf32_External_Rela);
- }
+ {
+ bfd_boolean tprel_known = bfd_link_executable (info);
+ htab->etab.srelgot->size
+ += got_relocs_needed (*local_tls_type, need, tprel_known);
+ }
}
else
*local_got = (bfd_vma) -1;
if ((input_section->flags & SEC_ALLOC) == 0)
break;
- /* The reloc types handled here and this conditional
- expression must match the code in ..check_relocs and
- allocate_dynrelocs. ie. We need exactly the same condition
- as in ..check_relocs, with some extra conditions (dynindx
- test in this case) to cater for relocs removed by
- allocate_dynrelocs. */
- if ((bfd_link_pic (info)
- && !(hh != NULL
- && ((hh->eh.root.type == bfd_link_hash_undefined
- && ELF_ST_VISIBILITY (hh->eh.other) != STV_DEFAULT)
- || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh)))
- && (IS_ABSOLUTE_RELOC (r_type)
- || !SYMBOL_CALLS_LOCAL (info, &hh->eh)))
- || (ELIMINATE_COPY_RELOCS
- && !bfd_link_pic (info)
- && hh != NULL
- && hh->eh.dynindx != -1
- && !hh->eh.non_got_ref
- && !hh->eh.def_regular))
+ if (bfd_link_pic (info)
+ ? ((hh == NULL
+ || hh->dyn_relocs != NULL)
+ && ((hh != NULL && pc_dynrelocs (hh))
+ || IS_ABSOLUTE_RELOC (r_type)))
+ : (hh != NULL
+ && hh->dyn_relocs != NULL))
{
Elf_Internal_Rela outrel;
bfd_boolean skip;
indx = 0;
if (hh != NULL)
{
- bfd_boolean dyn;
- dyn = htab->etab.dynamic_sections_created;
-
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
- bfd_link_pic (info),
- &hh->eh)
- && (!bfd_link_pic (info)
- || !SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))
- {
- indx = hh->eh.dynindx;
- }
+ if (!htab->etab.dynamic_sections_created
+ || hh->eh.dynindx == -1
+ || SYMBOL_REFERENCES_LOCAL (info, &hh->eh)
+ || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally, or the symbol was forced to be local
+ because of a version file. */
+ ;
+ else
+ indx = hh->eh.dynindx;
off = hh->eh.got.offset;
tls_type = hh->tls_type;
}
now, and emit any relocations. If both an IE GOT and a
GD GOT are necessary, we emit the GD first. */
- if ((bfd_link_pic (info) || indx != 0)
- && (hh == NULL
- || ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT
- || hh->eh.root.type != bfd_link_hash_undefweak))
+ if (indx != 0
+ || (bfd_link_pic (info)
+ && (hh == NULL
+ || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))))
{
need_relocs = TRUE;
loc = htab->etab.srelgot->contents;
- /* FIXME (CAO): Should this be reloc_count++ ? */
- loc += htab->etab.srelgot->reloc_count * sizeof (Elf32_External_Rela);
+ loc += (htab->etab.srelgot->reloc_count
+ * sizeof (Elf32_External_Rela));
}
if (tls_type & GOT_TLS_GD)
{
if (need_relocs)
{
- outrel.r_offset = (cur_off
- + htab->etab.sgot->output_section->vma
- + htab->etab.sgot->output_offset);
- outrel.r_info = ELF32_R_INFO (indx,R_PARISC_TLS_DTPMOD32);
+ outrel.r_offset
+ = (cur_off
+ + htab->etab.sgot->output_section->vma
+ + htab->etab.sgot->output_offset);
+ outrel.r_info
+ = ELF32_R_INFO (indx, R_PARISC_TLS_DTPMOD32);
outrel.r_addend = 0;
- bfd_put_32 (output_bfd, 0, htab->etab.sgot->contents + cur_off);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->etab.srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
-
- if (indx == 0)
- bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
- htab->etab.sgot->contents + cur_off + 4);
- else
- {
- bfd_put_32 (output_bfd, 0,
- htab->etab.sgot->contents + cur_off + 4);
- outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
- outrel.r_offset += 4;
- bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc);
- htab->etab.srelgot->reloc_count++;
- loc += sizeof (Elf32_External_Rela);
- }
+ outrel.r_info
+ = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
+ outrel.r_offset += 4;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ htab->etab.srelgot->reloc_count++;
+ loc += sizeof (Elf32_External_Rela);
+ bfd_put_32 (output_bfd, 0,
+ htab->etab.sgot->contents + cur_off);
+ bfd_put_32 (output_bfd, 0,
+ htab->etab.sgot->contents + cur_off + 4);
}
else
{
to module 1, the executable. */
bfd_put_32 (output_bfd, 1,
htab->etab.sgot->contents + cur_off);
- bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+ bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
htab->etab.sgot->contents + cur_off + 4);
}
-
-
cur_off += 8;
}
if (tls_type & GOT_TLS_IE)
{
- if (need_relocs)
+ if (need_relocs
+ && !(bfd_link_executable (info)
+ && SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))
{
- outrel.r_offset = (cur_off
- + htab->etab.sgot->output_section->vma
- + htab->etab.sgot->output_offset);
- outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_TPREL32);
-
+ outrel.r_offset
+ = (cur_off
+ + htab->etab.sgot->output_section->vma
+ + htab->etab.sgot->output_offset);
+ outrel.r_info = ELF32_R_INFO (indx,
+ R_PARISC_TLS_TPREL32);
if (indx == 0)
outrel.r_addend = relocation - dtpoff_base (info);
else
outrel.r_addend = 0;
-
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
htab->etab.srelgot->reloc_count++;
loc += sizeof (Elf32_External_Rela);
else
bfd_put_32 (output_bfd, tpoff (info, relocation),
htab->etab.sgot->contents + cur_off);
-
cur_off += 4;
}
local_got_offsets[r_symndx] |= 1;
}
+ if ((tls_type & GOT_NORMAL) != 0
+ && (tls_type & (GOT_TLS_GD | GOT_TLS_LDM | GOT_TLS_IE)) != 0)
+ {
+ if (hh != NULL)
+ _bfd_error_handler (_("%s has both normal and TLS relocs"),
+ hh_name (hh));
+ else
+ {
+ Elf_Internal_Sym *isym
+ = bfd_sym_from_r_symndx (&htab->sym_cache,
+ input_bfd, r_symndx);
+ if (isym == NULL)
+ return FALSE;
+ sym_name
+ = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ isym->st_name);
+ if (sym_name == NULL)
+ return FALSE;
+ if (*sym_name == '\0')
+ sym_name = bfd_section_name (input_bfd, sym_sec);
+ _bfd_error_handler
+ (_("%B:%s has both normal and TLS relocs"),
+ input_bfd, sym_name);
+ }
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
if ((tls_type & GOT_TLS_GD)
&& r_type != R_PARISC_TLS_GD21L
&& r_type != R_PARISC_TLS_GD14R)
}
if (eh->got.offset != (bfd_vma) -1
- && (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_GD) == 0
- && (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_IE) == 0
+ && (hppa_elf_hash_entry (eh)->tls_type & GOT_NORMAL) != 0
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
{
bfd_boolean is_dyn = (eh->dynindx != -1