/* SPARC-specific support for ELF
- Copyright (C) 2005-2015 Free Software Foundation, Inc.
+ Copyright (C) 2005-2017 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
default:
if (r_type >= (unsigned int) R_SPARC_max_std)
{
- (*_bfd_error_handler) (_("invalid relocation type %d"),
- (int) r_type);
+ _bfd_error_handler (_("invalid relocation type %d"), (int) r_type);
r_type = R_SPARC_NONE;
}
return &_bfd_sparc_elf_howto_table[r_type];
bfd_size_type pc_count;
};
+/* Is an undefined weak symbol resolved to 0 ?
+ Reference to an undefined weak symbol is resolved to 0 when
+ building an executable if it isn't dynamic and
+ 1. Has non-GOT/non-PLT relocations in text section.
+ Or
+ 2. Has no GOT/PLT relocation. */
+#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, EH) \
+ ((EH)->elf.root.type == bfd_link_hash_undefweak \
+ && bfd_link_executable (INFO) \
+ && (_bfd_sparc_elf_hash_table (INFO)->interp == NULL \
+ || !(EH)->has_got_reloc \
+ || (EH)->has_non_got_reloc \
+ || !(INFO)->dynamic_undefined_weak))
+
/* SPARC ELF linker hash entry. */
struct _bfd_sparc_elf_link_hash_entry
#define GOT_TLS_GD 2
#define GOT_TLS_IE 3
unsigned char tls_type;
+
+ /* Symbol has GOT or PLT relocations. */
+ unsigned int has_got_reloc : 1;
+
+ /* Symbol has non-GOT/non-PLT relocations in text sections. */
+ unsigned int has_non_got_reloc : 1;
+
};
#define _bfd_sparc_elf_hash_entry(ent) ((struct _bfd_sparc_elf_link_hash_entry *)(ent))
eh = (struct _bfd_sparc_elf_link_hash_entry *) entry;
eh->dyn_relocs = NULL;
eh->tls_type = GOT_UNKNOWN;
+ eh->has_got_reloc = 0;
+ eh->has_non_got_reloc = 0;
}
return entry;
if (!_bfd_elf_create_dynamic_sections (dynobj, info))
return FALSE;
- htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
- if (!info->shared)
- htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
-
if (htab->is_vxworks)
{
if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
return FALSE;
- if (info->shared)
+ if (bfd_link_pic (info))
{
htab->plt_header_size
= 4 * ARRAY_SIZE (sparc_vxworks_shared_plt0_entry);
}
}
- if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss
- || (!info->shared && !htab->srelbss))
+ if (!htab->elf.splt || !htab->elf.srelplt || !htab->elf.sdynbss
+ || (!bfd_link_pic (info) && !htab->elf.srelbss))
abort ();
return TRUE;
edir->tls_type = eind->tls_type;
eind->tls_type = GOT_UNKNOWN;
}
+
+ /* Copy has_got_reloc and has_non_got_reloc. */
+ edir->has_got_reloc |= eind->has_got_reloc;
+ edir->has_non_got_reloc |= eind->has_non_got_reloc;
+
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
&& ! _bfd_sparc_elf_tdata (abfd)->has_tlsgd)
r_type = R_SPARC_REV32;
- if (info->shared)
+ if (bfd_link_pic (info))
return r_type;
switch (r_type)
int num_relocs;
bfd_boolean checked_tlsgd = FALSE;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
htab = _bfd_sparc_elf_hash_table (info);
unsigned int r_type;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ struct _bfd_sparc_elf_link_hash_entry *eh;
Elf_Internal_Sym *isym;
r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info);
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
{
- (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
- abfd, r_symndx);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: bad symbol index: %d"), abfd, r_symndx);
return FALSE;
}
/* PR15323, ref flags aren't set for references in the same
object. */
- h->root.non_ir_ref = 1;
+ h->root.non_ir_ref_regular = 1;
}
if (h && h->type == STT_GNU_IFUNC)
}
r_type = sparc_elf_tls_transition (info, abfd, r_type, h == NULL);
+ eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
+
switch (r_type)
{
case R_SPARC_TLS_LDM_HI22:
case R_SPARC_TLS_LDM_LO10:
htab->tls_ldm_got.refcount += 1;
+ if (eh != NULL)
+ eh->has_got_reloc = 1;
break;
case R_SPARC_TLS_LE_HIX22:
case R_SPARC_TLS_LE_LOX10:
- if (info->shared)
+ if (bfd_link_pic (info))
goto r_sparc_plt32;
break;
case R_SPARC_TLS_IE_HI22:
case R_SPARC_TLS_IE_LO10:
- if (info->shared)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
/* Fall through */
tls_type = old_tls_type;
else
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: `%s' accessed both as normal and thread local symbol"),
abfd, h ? h->root.root.string : "<local>");
return FALSE;
if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
return FALSE;
}
+
+ if (eh != NULL)
+ eh->has_got_reloc = 1;
break;
case R_SPARC_TLS_GD_CALL:
case R_SPARC_TLS_LDM_CALL:
- if (info->shared)
+ if (bfd_link_pic (info))
{
/* These are basically R_SPARC_TLS_WPLT30 relocs against
__tls_get_addr. */
goto r_sparc_plt32;
}
h->plt.refcount += 1;
+
+ eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
+ eh->has_got_reloc = 1;
break;
case R_SPARC_PC10:
if (h != NULL)
h->non_got_ref = 1;
+ if (eh != NULL && (sec->flags & SEC_CODE) != 0)
+ eh->has_non_got_reloc = 1;
+
r_sparc_plt32:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
{
/* We may need a .plt entry if the function this reloc
refers to is in a shared lib. */
may need to keep relocations for symbols satisfied by a
dynamic library if we manage to avoid copy relocs for the
symbol. */
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0
&& (! _bfd_sparc_elf_howto_table[r_type].pc_relative
|| (h != NULL
&& (! SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
- || (!info->shared
+ || (!bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular))
- || (!info->shared
+ || (!bfd_link_pic (info)
&& h != NULL
&& h->type == STT_GNU_IFUNC))
{
}
/* FIXME: The test here, in check_relocs and in relocate_section
- dealing with TLS optimization, ought to be !info->executable. */
- if (info->shared)
+ dealing with TLS optimization, ought to be !bfd_link_executable (info). */
+ if (bfd_link_pic (info))
{
switch (SPARC_ELF_R_TYPE (rel->r_info))
{
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
BFD_ASSERT (is_sparc_elf (abfd) || sec->reloc_count == 0);
case R_SPARC_L44:
case R_SPARC_H34:
case R_SPARC_UA64:
- if (info->shared)
+ if (bfd_link_pic (info))
break;
/* Fall through. */
return TRUE;
}
+/* Remove undefined weak symbol from the dynamic symbol table if it
+ is resolved to 0. */
+
+bfd_boolean
+_bfd_sparc_elf_fixup_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
+{
+ if (h->dynindx != -1
+ && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
+ _bfd_sparc_elf_hash_entry (h)))
+ {
+ h->dynindx = -1;
+ _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+ h->dynstr_index);
+ }
+ return TRUE;
+}
+
/* 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
struct _bfd_sparc_elf_link_hash_table *htab;
struct _bfd_sparc_elf_link_hash_entry * eh;
struct _bfd_sparc_elf_dyn_relocs *p;
- asection *s;
+ asection *s, *srel;
htab = _bfd_sparc_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (info->shared)
+ if (bfd_link_pic (info))
return TRUE;
/* If there are no references to this symbol that do not use the
to copy the initial value out of the dynamic object and into the
runtime process image. We need to remember the offset into the
.rel.bss section we are going to use. */
+ if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
+ {
+ s = htab->elf.sdynrelro;
+ srel = htab->elf.sreldynrelro;
+ }
+ else
+ {
+ s = htab->elf.sdynbss;
+ srel = htab->elf.srelbss;
+ }
if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0)
{
- htab->srelbss->size += SPARC_ELF_RELA_BYTES (htab);
+ srel->size += SPARC_ELF_RELA_BYTES (htab);
h->needs_copy = 1;
}
- s = htab->sdynbss;
-
return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
struct _bfd_sparc_elf_link_hash_table *htab;
struct _bfd_sparc_elf_link_hash_entry *eh;
struct _bfd_sparc_elf_dyn_relocs *p;
+ bfd_boolean resolved_to_zero;
if (h->root.type == bfd_link_hash_indirect)
return TRUE;
htab = _bfd_sparc_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
+ eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
+ resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
if ((htab->elf.dynamic_sections_created
&& h->plt.refcount > 0)
|| (h->type == STT_GNU_IFUNC
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && !h->forced_local)
+ && !h->forced_local
+ && !resolved_to_zero)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h)
|| (h->type == STT_GNU_IFUNC
&& h->def_regular))
{
s->size = htab->plt_header_size;
/* Allocate space for the .rela.plt.unloaded relocations. */
- if (htab->is_vxworks && !info->shared)
+ if (htab->is_vxworks && !bfd_link_pic (info))
htab->srelplt2->size = sizeof (Elf32_External_Rela) * 2;
}
location in the .plt. This is required to make function
pointers compare as equal between the normal executable and
the shared library. */
- if (! info->shared
+ if (! bfd_link_pic (info)
&& !h->def_regular)
{
h->root.u.def.section = s;
/* Make room for this entry. */
s->size += htab->plt_entry_size;
- /* We also need to make an entry in the .rela.plt section. */
- if (s == htab->elf.splt)
- htab->elf.srelplt->size += SPARC_ELF_RELA_BYTES (htab);
- else
- htab->elf.irelplt->size += SPARC_ELF_RELA_BYTES (htab);
+ /* There should be no PLT relocations against resolved undefined
+ weak symbols in the executable. */
+ if (!resolved_to_zero)
+ {
+ /* We also need to make an entry in the .rela.plt section. */
+ if (s == htab->elf.splt)
+ htab->elf.srelplt->size += SPARC_ELF_RELA_BYTES (htab);
+ else
+ htab->elf.irelplt->size += SPARC_ELF_RELA_BYTES (htab);
+ }
if (htab->is_vxworks)
{
htab->elf.sgotplt->size += 4;
/* ...and for the .rela.plt.unloaded relocations. */
- if (!info->shared)
+ if (!bfd_link_pic (info))
htab->srelplt2->size += sizeof (Elf32_External_Rela) * 3;
}
}
/* If R_SPARC_TLS_IE_{HI22,LO10} symbol is now local to the binary,
make it a R_SPARC_TLS_LE_{HI22,LO10} requiring no TLS entry. */
if (h->got.refcount > 0
- && !info->shared
+ && !bfd_link_pic (info)
&& h->dynindx == -1
&& _bfd_sparc_elf_hash_entry(h)->tls_type == GOT_TLS_IE)
h->got.offset = (bfd_vma) -1;
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && !h->forced_local)
+ && !h->forced_local
+ && !resolved_to_zero)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
dyn = htab->elf.dynamic_sections_created;
/* R_SPARC_TLS_IE_{HI22,LO10} needs one dynamic relocation,
R_SPARC_TLS_GD_{HI22,LO10} needs one if local symbol and two if
- global. */
+ global. No dynamic relocations are needed against resolved
+ undefined weak symbols in an executable. */
if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
|| tls_type == GOT_TLS_IE
|| h->type == STT_GNU_IFUNC)
htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab);
else if (tls_type == GOT_TLS_GD)
htab->elf.srelgot->size += 2 * SPARC_ELF_RELA_BYTES (htab);
- else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h))
+ else if (((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
+ || h->root.type != bfd_link_hash_undefweak)
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
+ bfd_link_pic (info),
+ h))
htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab);
}
else
h->got.offset = (bfd_vma) -1;
- eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return TRUE;
space for pc-relative relocs that have become local due to symbol
visibility changes. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
if (SYMBOL_CALLS_LOCAL (info, h))
{
}
/* Also discard relocs on undefined weak syms with non-default
- visibility. */
+ visibility or in PIE. */
if (eh->dyn_relocs != NULL
&& h->root.type == bfd_link_hash_undefweak)
{
- if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- eh->dyn_relocs = NULL;
+ /* An undefined weak symbol is never
+ bound locally in a shared library. */
+
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || resolved_to_zero)
+ {
+ if (h->non_got_ref)
+ {
+ /* Keep dynamic non-GOT/non-PLT relocation so that we
+ can branch to 0 without PLT. */
+ struct _bfd_sparc_elf_dyn_relocs **pp;
+
+ for (pp = &eh->dyn_relocs; (p = *pp) != NULL;)
+ if (p->pc_count == 0)
+ *pp = p->next;
+ else
+ {
+ /* Remove other relocations. */
+ p->count = p->pc_count;
+ pp = &p->next;
+ }
+
+ if (eh->dyn_relocs != NULL)
+ {
+ /* Make sure undefined weak symbols are output
+ as dynamic symbols in PIEs for dynamic non-GOT
+ non-PLT reloations. */
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+ }
+ else
+ eh->dyn_relocs = NULL;
+ }
/* Make sure undefined weak symbols are output as a dynamic
symbol in PIEs. */
symbols which turn out to need copy relocs or are not
dynamic. */
- if (!h->non_got_ref
+ if ((!h->non_got_ref
+ || (h->root.type == bfd_link_hash_undefweak
+ && !resolved_to_zero))
&& ((h->def_dynamic
&& !h->def_regular)
|| (htab->elf.dynamic_sections_created
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
if (h->dynindx == -1
- && !h->forced_local)
+ && !h->forced_local
+ && !resolved_to_zero)
{
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (info->executable)
- {
- s = bfd_get_linker_section (dynobj, ".interp");
- BFD_ASSERT (s != NULL);
- s->size = htab->dynamic_interpreter_size;
- s->contents = (unsigned char *) htab->dynamic_interpreter;
- }
+ if (bfd_link_executable (info) && !info->nointerp)
+ {
+ s = bfd_get_linker_section (dynobj, ".interp");
+ BFD_ASSERT (s != NULL);
+ s->size = htab->dynamic_interpreter_size;
+ s->contents = (unsigned char *) htab->dynamic_interpreter;
+ htab->interp = s;
+ }
}
/* Set up .got offsets for local syms, and space for local dynamic
s->size += SPARC_ELF_WORD_BYTES (htab);
if (*local_tls_type == GOT_TLS_GD)
s->size += SPARC_ELF_WORD_BYTES (htab);
- if (info->shared
+ if (bfd_link_pic (info)
|| *local_tls_type == GOT_TLS_GD
|| *local_tls_type == GOT_TLS_IE)
srel->size += SPARC_ELF_RELA_BYTES (htab);
if (s == htab->elf.splt
|| s == htab->elf.sgot
- || s == htab->sdynbss
+ || s == htab->elf.sdynbss
+ || s == htab->elf.sdynrelro
|| s == htab->elf.iplt
|| s == htab->elf.sgotplt)
{
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (info->executable)
+ if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
bfd_boolean *again)
{
- if (link_info->relocatable)
+ if (bfd_link_relocatable (link_info))
(*link_info->callbacks->einfo)
(_("%P%F: --relax and -r may not be used together\n"));
return address - got_base;
}
+/* Return whether H is local and its ADDRESS is within 4G of
+ _GLOBAL_OFFSET_TABLE_ and thus the offset may be calculated by a
+ sethi, xor sequence. */
+
+static bfd_boolean
+gdop_relative_offset_ok (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_vma address ATTRIBUTE_UNUSED)
+{
+ if (!SYMBOL_REFERENCES_LOCAL (info, h))
+ return FALSE;
+ /* If H is undefined, ADDRESS will be zero. We can't allow a
+ relative offset to "zero" when producing PIEs or shared libs.
+ Note that to get here with an undefined symbol it must also be
+ hidden or internal visibility. */
+ if (bfd_link_pic (info)
+ && h != NULL
+ && (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_undefined))
+ return FALSE;
+#ifdef BFD64
+ return gdopoff (info, address) + ((bfd_vma) 1 << 32) < (bfd_vma) 2 << 32;
+#else
+ return TRUE;
+#endif
+}
+
/* Relocate a SPARC ELF section. */
bfd_boolean
sreloc = elf_section_data (input_section)->sreloc;
/* We have to handle relocations in vxworks .tls_vars sections
specially, because the dynamic loader is 'weird'. */
- is_vxworks_tls = (htab->is_vxworks && info->shared
+ is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info)
&& !strcmp (input_section->output_section->name,
".tls_vars"));
reloc_howto_type *howto;
unsigned long r_symndx;
struct elf_link_hash_entry *h;
+ struct _bfd_sparc_elf_link_hash_entry *eh;
Elf_Internal_Sym *sym;
asection *sec;
bfd_vma relocation, off;
bfd_reloc_status_type r;
bfd_boolean is_plt = FALSE;
bfd_boolean unresolved_reloc;
+ bfd_boolean resolved_to_zero;
r_type = SPARC_ELF_R_TYPE (rel->r_info);
if (r_type == R_SPARC_GNU_VTINHERIT
sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
{
/* Relocate against local STT_GNU_IFUNC symbol. */
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
rel, 1, relend, howto, 0, contents);
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
continue;
if (h != NULL
case R_SPARC_32:
case R_SPARC_64:
- if (info->shared && h->non_got_ref)
+ if (bfd_link_pic (info) && h->non_got_ref)
{
Elf_Internal_Rela outrel;
bfd_vma offset;
if (h->dynindx == -1
|| h->forced_local
- || info->executable)
+ || bfd_link_executable (info))
{
outrel.r_info = SPARC_ELF_R_INFO (htab, NULL,
0, R_SPARC_IRELATIVE);
case R_SPARC_HI22:
case R_SPARC_LO10:
/* We should only see such relocs in static links. */
- if (info->shared)
+ if (bfd_link_pic (info))
abort();
relocation = (plt_sec->output_section->vma
+ plt_sec->output_offset + h->plt.offset);
else
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
NULL);
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't handled by %s"), input_bfd,
_bfd_sparc_elf_howto_table[r_type].name,
}
}
+ eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
+ resolved_to_zero = (eh != NULL
+ && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
+
switch (r_type)
{
case R_SPARC_GOTDATA_OP_HIX22:
case R_SPARC_GOTDATA_OP_LOX10:
- if (SYMBOL_REFERENCES_LOCAL (info, h))
- r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
- ? R_SPARC_GOTDATA_HIX22
- : R_SPARC_GOTDATA_LOX10);
- else
- r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
- ? R_SPARC_GOT22
- : R_SPARC_GOT10);
- howto = _bfd_sparc_elf_howto_table + r_type;
+ if (gdop_relative_offset_ok (info, h, relocation))
+ {
+ r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22
+ ? R_SPARC_GOTDATA_HIX22
+ : R_SPARC_GOTDATA_LOX10);
+ howto = _bfd_sparc_elf_howto_table + r_type;
+ }
break;
case R_SPARC_GOTDATA_OP:
- if (SYMBOL_REFERENCES_LOCAL (info, h))
+ if (gdop_relative_offset_ok (info, h, relocation))
{
bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
relocation = gdopoff (info, relocation);
break;
+ case R_SPARC_GOTDATA_OP_HIX22:
+ case R_SPARC_GOTDATA_OP_LOX10:
case R_SPARC_GOT10:
case R_SPARC_GOT13:
case R_SPARC_GOT22:
BFD_ASSERT (off != (bfd_vma) -1);
dyn = elf_hash_table (info)->dynamic_sections_created;
- if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
- || (info->shared
+ if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
+ bfd_link_pic (info),
+ h)
+ || (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
{
/* This is actually a static link, or it is a
else
{
- if (info->shared)
+ if (bfd_link_pic (info))
{
asection *s;
Elf_Internal_Rela outrel;
|| is_vxworks_tls)
break;
- if ((info->shared
+ /* Copy dynamic function pointer relocations. Don't generate
+ dynamic relocations against resolved undefined weak symbols
+ in PIE. */
+ if ((bfd_link_pic (info)
&& (h == NULL
- || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- || h->root.type != bfd_link_hash_undefweak)
+ || ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !resolved_to_zero)
+ || h->root.type != bfd_link_hash_undefweak))
&& (! howto->pc_relative
|| !SYMBOL_CALLS_LOCAL (info, h)))
- || (!info->shared
+ || (!bfd_link_pic (info)
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
&& ((h->def_dynamic
&& !h->def_regular)
- || h->root.type == bfd_link_hash_undefweak
+ || (h->root.type == bfd_link_hash_undefweak
+ && !resolved_to_zero)
|| h->root.type == bfd_link_hash_undefined)))
{
Elf_Internal_Rela outrel;
memset (&outrel, 0, sizeof outrel);
/* h->dynindx may be -1 if the symbol was marked to
become local. */
- else if (h != NULL &&
- h->dynindx != -1
- && (! is_plt
- || !info->shared
+ else if (h != NULL
+ && h->dynindx != -1
+ && (_bfd_sparc_elf_howto_table[r_type].pc_relative
+ || !bfd_link_pic (info)
|| !SYMBOLIC_BIND (info, h)
|| !h->def_regular))
{
}
else
{
- if (r_type == R_SPARC_32 || r_type == R_SPARC_64)
+ if ( (!ABI_64_P (output_bfd) && r_type == R_SPARC_32)
+ || (ABI_64_P (output_bfd) && r_type == R_SPARC_64))
{
outrel.r_info = SPARC_ELF_R_INFO (htab, NULL,
0, R_SPARC_RELATIVE);
if (indx == 0)
{
BFD_FAIL ();
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: probably compiled without -fPIC?"),
input_bfd);
bfd_set_error (bfd_error_bad_value);
else if (h != NULL)
{
tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type;
- if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
+ if (!bfd_link_pic (info)
+ && h->dynindx == -1
+ && tls_type == GOT_TLS_IE)
switch (SPARC_ELF_R_TYPE (rel->r_info))
{
case R_SPARC_TLS_GD_HI22:
case R_SPARC_TLS_LDM_HI22:
case R_SPARC_TLS_LDM_LO10:
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
continue;
case R_SPARC_TLS_LDO_HIX22:
case R_SPARC_TLS_LDO_LOX10:
- if (info->shared)
+ if (bfd_link_pic (info))
{
relocation -= dtpoff_base (info);
break;
case R_SPARC_TLS_LE_HIX22:
case R_SPARC_TLS_LE_LOX10:
- if (info->shared)
+ if (bfd_link_pic (info))
{
Elf_Internal_Rela outrel;
bfd_boolean skip;
break;
case R_SPARC_TLS_LDM_CALL:
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
/* mov %g0, %o0 */
bfd_put_32 (output_bfd, 0x90100000, contents + rel->r_offset);
tls_type = _bfd_sparc_elf_local_got_tls_type (input_bfd) [r_symndx];
else if (h != NULL)
tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type;
- if (! info->shared
+ if (! bfd_link_pic (info)
|| (r_type == R_SPARC_TLS_GD_CALL && tls_type == GOT_TLS_IE))
{
Elf_Internal_Rela *rel2;
bfd_vma insn;
- if (!info->shared && (h == NULL || h->dynindx == -1))
+ if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1))
{
/* GD -> LE */
bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
tls_type = _bfd_sparc_elf_local_got_tls_type (input_bfd) [r_symndx];
else if (h != NULL)
tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type;
- if (! info->shared || tls_type == GOT_TLS_IE)
+ if (! bfd_link_pic (info) || tls_type == GOT_TLS_IE)
{
/* add %reg1, %reg2, %reg3, %tgd_add(foo)
changed into IE:
or LE:
add %g7, %reg2, %reg3. */
bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if ((h != NULL && h->dynindx != -1) || info->shared)
+ if ((h != NULL && h->dynindx != -1) || bfd_link_pic (info))
relocation = insn | (ABI_64_P (output_bfd) ? 0xc0580000 : 0xc0000000);
else
relocation = (insn & ~0x7c000) | 0x1c000;
continue;
case R_SPARC_TLS_LDM_ADD:
- if (! info->shared)
+ if (! bfd_link_pic (info))
bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset);
continue;
case R_SPARC_TLS_LDO_ADD:
- if (! info->shared)
+ if (! bfd_link_pic (info))
{
/* Change rs1 into %g7. */
bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
case R_SPARC_TLS_IE_LD:
case R_SPARC_TLS_IE_LDX:
- if (! info->shared && (h == NULL || h->dynindx == -1))
+ if (! bfd_link_pic (info) && (h == NULL || h->dynindx == -1))
{
bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
int rs2 = insn & 0x1f;
&& h->def_dynamic)
&& _bfd_elf_section_offset (output_bfd, info, input_section,
rel->r_offset) != (bfd_vma) -1)
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
r = bfd_reloc_ok;
}
else if (r_type == R_SPARC_HIX22
- || r_type == R_SPARC_GOTDATA_HIX22)
+ || r_type == R_SPARC_GOTDATA_HIX22
+ || r_type == R_SPARC_GOTDATA_OP_HIX22)
{
bfd_vma x;
relocation);
}
else if (r_type == R_SPARC_LOX10
- || r_type == R_SPARC_GOTDATA_LOX10)
+ || r_type == R_SPARC_GOTDATA_LOX10
+ || r_type == R_SPARC_GOTDATA_OP_LOX10)
{
bfd_vma x;
contents + rel->r_offset - 4);
if ((z & (0xffffffff ^ RD(~0)))
!= (INSN_OR | RS1(O7) | RS2(G0)))
- break;
+ continue;
/* The sequence was
or %o7, %g0, %rN
reg = (y & RS1(~0)) >> 14;
if (reg != ((z & RD(~0)) >> 25)
|| reg == G0 || reg == O7)
- break;
+ continue;
bfd_put_32 (input_bfd, (bfd_vma) INSN_NOP,
contents + rel->r_offset + 4);
if (*name == '\0')
name = bfd_section_name (input_bfd, sec);
}
- if (! ((*info->callbacks->reloc_overflow)
- (info, (h ? &h->root : NULL), name, howto->name,
- (bfd_vma) 0, input_bfd, input_section,
- rel->r_offset)))
- return FALSE;
+ (*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
}
break;
}
htab = _bfd_sparc_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
- if (info->shared)
+ if (bfd_link_pic (info))
{
plt_entry = sparc_vxworks_shared_plt_entry;
got_base = 0;
htab->elf.sgotplt->contents + got_offset);
/* Add relocations to .rela.plt.unloaded. */
- if (!info->shared)
+ if (!bfd_link_pic (info))
{
loc = (htab->srelplt2->contents
+ (2 + 3 * plt_index) * sizeof (Elf32_External_Rela));
{
struct _bfd_sparc_elf_link_hash_table *htab;
const struct elf_backend_data *bed;
+ struct _bfd_sparc_elf_link_hash_entry *eh;
+ bfd_boolean local_undefweak;
htab = _bfd_sparc_elf_hash_table (info);
BFD_ASSERT (htab != NULL);
bed = get_elf_backend_data (output_bfd);
+ eh = (struct _bfd_sparc_elf_link_hash_entry *) h;
+
+ /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for
+ resolved undefined weak symbols in executable so that their
+ references have value 0 at run-time. */
+ local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh);
+
if (h->plt.offset != (bfd_vma) -1)
{
asection *splt;
if (h == NULL
|| h->dynindx == -1
- || ((info->executable
+ || ((bfd_link_executable (info)
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
&& h->def_regular
&& h->type == STT_GNU_IFUNC))
loc += rela_index * bed->s->sizeof_rela;
bed->s->swap_reloca_out (output_bfd, &rela, loc);
- if (!h->def_regular)
+ if (!local_undefweak
+ && !h->def_regular)
{
/* Mark the symbol as undefined, rather than as defined in
the .plt section. Leave the value alone. */
}
}
+ /* Don't generate dynamic GOT relocation against undefined weak
+ symbol in executable. */
if (h->got.offset != (bfd_vma) -1
&& _bfd_sparc_elf_hash_entry(h)->tls_type != GOT_TLS_GD
- && _bfd_sparc_elf_hash_entry(h)->tls_type != GOT_TLS_IE)
+ && _bfd_sparc_elf_hash_entry(h)->tls_type != GOT_TLS_IE
+ && !local_undefweak)
{
asection *sgot;
asection *srela;
the symbol was forced to be local because of a version file.
The entry in the global offset table will already have been
initialized in the relocate_section function. */
- if (! info->shared
+ if (! bfd_link_pic (info)
&& h->type == STT_GNU_IFUNC
&& h->def_regular)
{
+ (h->got.offset & ~(bfd_vma) 1));
return TRUE;
}
- else if (info->shared
+ else if (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
asection *sec = h->root.u.def.section;
/* This symbols needs a copy reloc. Set it up. */
BFD_ASSERT (h->dynindx != -1);
- s = bfd_get_linker_section (h->root.u.def.section->owner,
- ".rela.bss");
- BFD_ASSERT (s != NULL);
-
rela.r_offset = (h->root.u.def.value
+ h->root.u.def.section->output_section->vma
+ h->root.u.def.section->output_offset);
rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_COPY);
rela.r_addend = 0;
+ if (h->root.u.def.section == htab->elf.sdynrelro)
+ s = htab->elf.sreldynrelro;
+ else
+ s = htab->elf.srelbss;
sparc_elf_append_rela (output_bfd, s, &rela);
}
for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize)
{
Elf_Internal_Dyn dyn;
- const char *name;
bfd_boolean size;
bed->s->swap_dyn_in (dynobj, dyncon, &dyn);
- if (htab->is_vxworks && dyn.d_tag == DT_RELASZ)
- {
- /* On VxWorks, DT_RELASZ should not include the relocations
- in .rela.plt. */
- if (htab->elf.srelplt)
- {
- dyn.d_un.d_val -= htab->elf.srelplt->size;
- bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
- }
- }
- else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT)
+ if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT)
{
/* On VxWorks, DT_PLTGOT should point to the start of the GOT,
not to the start of the PLT. */
}
else
{
+ asection *s;
+
switch (dyn.d_tag)
{
- case DT_PLTGOT: name = ".plt"; size = FALSE; break;
- case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break;
- case DT_JMPREL: name = ".rela.plt"; size = FALSE; break;
- default: name = NULL; size = FALSE; break;
+ case DT_PLTGOT:
+ s = htab->elf.splt;
+ size = FALSE;
+ break;
+ case DT_PLTRELSZ:
+ s = htab->elf.srelplt;
+ size = TRUE;
+ break;
+ case DT_JMPREL:
+ s = htab->elf.srelplt;
+ size = FALSE;
+ break;
+ default:
+ continue;
}
- if (name != NULL)
+ if (s == NULL)
+ dyn.d_un.d_val = 0;
+ else
{
- asection *s;
-
- s = bfd_get_section_by_name (output_bfd, name);
- if (s == NULL)
- dyn.d_un.d_val = 0;
+ if (!size)
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
else
- {
- if (! size)
- dyn.d_un.d_ptr = s->vma;
- else
- dyn.d_un.d_val = s->size;
- }
- bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
+ dyn.d_un.d_val = s->size;
}
+ bed->s->swap_dyn_out (output_bfd, &dyn, dyncon);
}
}
return TRUE;
h, NULL);
}
+/* Finish up undefined weak symbol handling in PIE. Fill its PLT entry
+ here since undefined weak symbol may not be dynamic and may not be
+ called for _bfd_sparc_elf_finish_dynamic_symbol. */
+
+static bfd_boolean
+pie_finish_undefweak_symbol (struct bfd_hash_entry *bh,
+ void *inf)
+{
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) bh;
+ struct bfd_link_info *info = (struct bfd_link_info *) inf;
+
+ if (h->root.type != bfd_link_hash_undefweak
+ || h->dynindx != -1)
+ return TRUE;
+
+ return _bfd_sparc_elf_finish_dynamic_symbol (info->output_bfd, info,
+ h, NULL);
+}
+
bfd_boolean
_bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
{
{
if (htab->is_vxworks)
{
- if (info->shared)
+ if (bfd_link_pic (info))
sparc_vxworks_finish_shared_plt (output_bfd, info);
else
sparc_vxworks_finish_exec_plt (output_bfd, info);
/* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */
htab_traverse (htab->loc_hash_table, finish_local_dynamic_symbol, info);
+ /* Fill PLT entries for undefined weak symbols in PIE. */
+ if (bfd_link_pie (info))
+ bfd_hash_traverse (&info->hash->table,
+ pie_finish_undefweak_symbol,
+ info);
return TRUE;
}
bfd_boolean
_bfd_sparc_elf_object_p (bfd *abfd)
{
+ obj_attribute *attrs = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU];
+ obj_attribute *hwcaps = &attrs[Tag_GNU_Sparc_HWCAPS];
+ obj_attribute *hwcaps2 = &attrs[Tag_GNU_Sparc_HWCAPS2];
+
+ unsigned int v9c_hwcaps_mask = ELF_SPARC_HWCAP_ASI_BLK_INIT;
+ unsigned int v9d_hwcaps_mask = (ELF_SPARC_HWCAP_FMAF
+ | ELF_SPARC_HWCAP_VIS3
+ | ELF_SPARC_HWCAP_HPC);
+ unsigned int v9e_hwcaps_mask = (ELF_SPARC_HWCAP_AES
+ | ELF_SPARC_HWCAP_DES
+ | ELF_SPARC_HWCAP_KASUMI
+ | ELF_SPARC_HWCAP_CAMELLIA
+ | ELF_SPARC_HWCAP_MD5
+ | ELF_SPARC_HWCAP_SHA1
+ | ELF_SPARC_HWCAP_SHA256
+ | ELF_SPARC_HWCAP_SHA512
+ | ELF_SPARC_HWCAP_MPMUL
+ | ELF_SPARC_HWCAP_MONT
+ | ELF_SPARC_HWCAP_CRC32C
+ | ELF_SPARC_HWCAP_CBCOND
+ | ELF_SPARC_HWCAP_PAUSE);
+ unsigned int v9v_hwcaps_mask = (ELF_SPARC_HWCAP_FJFMAU
+ | ELF_SPARC_HWCAP_IMA);
+ unsigned int v9m_hwcaps2_mask = (ELF_SPARC_HWCAP2_SPARC5
+ | ELF_SPARC_HWCAP2_MWAIT
+ | ELF_SPARC_HWCAP2_XMPMUL
+ | ELF_SPARC_HWCAP2_XMONT);
+ unsigned int m8_hwcaps2_mask = (ELF_SPARC_HWCAP2_SPARC6
+ | ELF_SPARC_HWCAP2_ONADDSUB
+ | ELF_SPARC_HWCAP2_ONMUL
+ | ELF_SPARC_HWCAP2_ONDIV
+ | ELF_SPARC_HWCAP2_DICTUNP
+ | ELF_SPARC_HWCAP2_FPCMPSHL
+ | ELF_SPARC_HWCAP2_RLE
+ | ELF_SPARC_HWCAP2_SHA3);
+
if (ABI_64_P (abfd))
{
unsigned long mach = bfd_mach_sparc_v9;
- if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3)
+ if (hwcaps2->i & m8_hwcaps2_mask)
+ mach = bfd_mach_sparc_v9m8;
+ else if (hwcaps2->i & v9m_hwcaps2_mask)
+ mach = bfd_mach_sparc_v9m;
+ else if (hwcaps->i & v9v_hwcaps_mask)
+ mach = bfd_mach_sparc_v9v;
+ else if (hwcaps->i & v9e_hwcaps_mask)
+ mach = bfd_mach_sparc_v9e;
+ else if (hwcaps->i & v9d_hwcaps_mask)
+ mach = bfd_mach_sparc_v9d;
+ else if (hwcaps->i & v9c_hwcaps_mask)
+ mach = bfd_mach_sparc_v9c;
+ else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3)
mach = bfd_mach_sparc_v9b;
else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1)
mach = bfd_mach_sparc_v9a;
{
if (elf_elfheader (abfd)->e_machine == EM_SPARC32PLUS)
{
- if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3)
+ if (hwcaps2->i & m8_hwcaps2_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8plusm8);
+ else if (hwcaps2->i & v9m_hwcaps2_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8plusm);
+ else if (hwcaps->i & v9v_hwcaps_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8plusv);
+ else if (hwcaps->i & v9e_hwcaps_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8pluse);
+ else if (hwcaps->i & v9d_hwcaps_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8plusd);
+ else if (hwcaps->i & v9c_hwcaps_mask)
+ return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
+ bfd_mach_sparc_v8plusc);
+ else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3)
return bfd_default_set_arch_mach (abfd, bfd_arch_sparc,
bfd_mach_sparc_v8plusb);
else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1)
object file when linking. */
bfd_boolean
-_bfd_sparc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+_bfd_sparc_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
{
+ bfd *obfd = info->output_bfd;
obj_attribute *in_attr, *in_attrs;
obj_attribute *out_attr, *out_attrs;
out_attr->i |= in_attr->i;
out_attr->type = 1;
-
/* Merge Tag_compatibility attributes and any common GNU ones. */
- _bfd_elf_merge_object_attributes (ibfd, obfd);
+ _bfd_elf_merge_object_attributes (ibfd, info);
return TRUE;
}