/* CRIS-specific support for 32-bit ELF.
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Axis Communications AB.
Written by Hans-Peter Nilsson, based on elf32-fr30.c
{
/* Next section. */
struct elf_cris_pcrel_relocs_copied *next;
+
/* A section in dynobj. */
asection *section;
+
/* Number of relocs copied in this section. */
bfd_size_type count;
+
+ /* Example of reloc being copied, for message. */
+ enum elf_cris_reloc_type r_type;
};
/* CRIS ELF linker hash entry. */
case R_CRIS_16_PCREL:
case R_CRIS_32_PCREL:
/* If the symbol was local, we need no shlib-specific handling. */
- if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ || h->dynindx == -1)
break;
/* Fall through. */
&& r_type != R_CRIS_16_PCREL
&& r_type != R_CRIS_32_PCREL)
|| (!info->symbolic
- || !h->def_regular)))
+ || (h != NULL && !h->def_regular))))
{
Elf_Internal_Rela outrel;
bfd_byte *loc;
if (sreloc == NULL)
{
- const char *name;
-
- name = (bfd_elf_string_from_elf_section
- (input_bfd,
- elf_elfheader (input_bfd)->e_shstrndx,
- elf_section_data (input_section)->rel_hdr.sh_name));
- if (name == NULL)
- return FALSE;
-
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && strcmp (bfd_get_section_name (input_bfd,
- input_section),
- name + 5) == 0);
-
- sreloc = bfd_get_section_by_name (dynobj, name);
-
- /* That section should have been created in
- cris_elf_check_relocs, but that function will not be
- called for objects which fail in
+ sreloc = _bfd_elf_get_dynamic_reloc_section
+ (input_bfd, input_section, /*rela?*/ TRUE);
+ /* The section should have been created in cris_elf_check_relocs,
+ but that function will not be called for objects which fail in
cris_elf_merge_private_bfd_data. */
if (sreloc == NULL)
{
- (*_bfd_error_handler)
- (_("%B: Internal inconsistency; no relocation section %s"),
- input_bfd,
- name);
-
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
return _bfd_elf_adjust_dynamic_copy (h, s);
}
+/* Adjust our "subclass" elements for an indirect symbol. */
+
+static void
+elf_cris_copy_indirect_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *dir,
+ struct elf_link_hash_entry *ind)
+{
+ struct elf_cris_link_hash_entry *edir, *eind;
+
+ edir = (struct elf_cris_link_hash_entry *) dir;
+ eind = (struct elf_cris_link_hash_entry *) ind;
+
+ /* Only indirect symbols are replaced; we're not interested in
+ updating any of EIND's fields for other symbols. */
+ if (eind->root.root.type != bfd_link_hash_indirect)
+ return;
+
+ BFD_ASSERT (edir->pcrel_relocs_copied == NULL);
+ BFD_ASSERT (edir->gotplt_offset == 0 || eind->gotplt_offset == 0);
+
+#define XMOVOPZ(F, OP, Z) edir->F OP eind->F; eind->F = Z
+#define XMOVE(F) XMOVOPZ (F, +=, 0)
+ XMOVOPZ (pcrel_relocs_copied, =, NULL);
+ XMOVE (gotplt_refcount);
+ XMOVE (gotplt_offset);
+ XMOVE (reg_got_refcount);
+ XMOVE (tprel_refcount);
+ XMOVE (dtp_refcount);
+#undef XMOVE
+#undef XMOVOPZ
+
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
/* Look through the relocs for a section during the first phase. */
static bfd_boolean
case R_CRIS_16:
case R_CRIS_32:
/* Let's help debug shared library creation. Any of these
- relocs can be used in shared libs, but pages containing them
- cannot be shared. Don't warn for sections we don't care
- about, such as debug sections or non-constant sections. We
- can't help tables of (global) function pointers, for example,
- though they must be emitted in a data section to avoid having
- impure text sections. */
+ relocs *can* be used in shared libs, but pages containing
+ them cannot be shared, so they're not appropriate for
+ common use. Don't warn for sections we don't care about,
+ such as debug sections or non-constant sections. We
+ can't help tables of (global) function pointers, for
+ example, though they must be emitted in a (writable) data
+ section to avoid having impure text sections. */
if (info->shared
&& (sec->flags & SEC_ALLOC) != 0
&& (sec->flags & SEC_READONLY) != 0)
sec,
cris_elf_howto_table[r_type].name);
}
+ if (h != NULL)
+ {
+ h->non_got_ref = 1;
- /* Fall through. */
+ /* Make sure a plt entry is created for this symbol if it
+ turns out to be a function defined by a dynamic object. */
+ if (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ h->plt.refcount++;
+ }
+
+ /* If we are creating a shared library and this is not a local
+ symbol, we need to copy the reloc into the shared library.
+ However when linking with -Bsymbolic and this is a global
+ symbol which is defined in an object we are including in the
+ link (i.e., DEF_REGULAR is set), then we can resolve the
+ reloc directly. At this point we have not seen all the input
+ files, so it is possible that DEF_REGULAR is not set now but
+ will be set later (it is never cleared). In case of a weak
+ definition, DEF_REGULAR may be cleared later by a strong
+ definition in a shared library. We account for that
+ possibility below by storing information in the relocs_copied
+ field of the hash table entry. A similar situation occurs
+ when creating shared libraries and symbol visibility changes
+ render the symbol local. */
+
+ /* No need to do anything if we're not creating a shared object. */
+ if (! info->shared)
+ break;
+
+ /* We don't need to handle relocs into sections not going into
+ the "real" output. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ break;
+
+ /* We may need to create a reloc section in the dynobj and made room
+ for this reloc. */
+ if (sreloc == NULL)
+ {
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
+
+ if (sreloc == NULL)
+ return FALSE;
+ }
+
+ if (sec->flags & SEC_READONLY)
+ info->flags |= DF_TEXTREL;
+
+ sreloc->size += sizeof (Elf32_External_Rela);
+ break;
case R_CRIS_8_PCREL:
case R_CRIS_16_PCREL:
if ((sec->flags & SEC_ALLOC) == 0)
break;
- /* We can only eliminate PC-relative relocs. */
- if (r_type == R_CRIS_8_PCREL
- || r_type == R_CRIS_16_PCREL
- || r_type == R_CRIS_32_PCREL)
- {
- /* If the symbol is local, then we can eliminate the reloc. */
- if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
- break;
-
- /* If this is with -Bsymbolic and the symbol isn't weak, and
- is defined by an ordinary object (the ones we include in
- this shared library) then we can also eliminate the
- reloc. See comment above for more eliminable cases which
- we can't identify at this time. */
- if (info->symbolic
- && h->root.type != bfd_link_hash_defweak
- && h->def_regular)
- break;
+ /* If the symbol is local, then we know already we can
+ eliminate the reloc. */
+ if (h == NULL || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+ break;
- if ((sec->flags & SEC_READONLY) != 0)
- {
- /* FIXME: How do we make this optionally a warning only? */
- (*_bfd_error_handler)
- (_("%B, section %A:\n relocation %s should not be used"
- " in a shared object; recompile with -fPIC"),
- abfd,
- sec,
- cris_elf_howto_table[r_type].name);
- }
- }
+ /* If this is with -Bsymbolic and the symbol isn't weak, and
+ is defined by an ordinary object (the ones we include in
+ this shared library) then we can also eliminate the
+ reloc. See comment above for more eliminable cases which
+ we can't identify at this time. */
+ if (info->symbolic
+ && h->root.type != bfd_link_hash_defweak
+ && h->def_regular)
+ break;
- /* We create a reloc section in dynobj and make room for this
- reloc. */
+ /* We may need to create a reloc section in the dynobj and made room
+ for this reloc. */
if (sreloc == NULL)
{
- const char *name;
-
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
- return FALSE;
-
- BFD_ASSERT (CONST_STRNEQ (name, ".rela")
- && strcmp (bfd_get_section_name (abfd, sec),
- name + 5) == 0);
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
- sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
- {
- sreloc = bfd_make_section_with_flags (dynobj, name,
- (SEC_ALLOC
- | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY));
- if (sreloc == NULL
- || !bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
- if (sec->flags & SEC_READONLY)
- info->flags |= DF_TEXTREL;
+ return FALSE;
}
sreloc->size += sizeof (Elf32_External_Rela);
- /* If we are linking with -Bsymbolic, we count the number of PC
- relative relocations we have entered for this symbol, so that
- we can discard them again if the symbol is later defined by a
- regular object. We know that h is really a pointer to an
+ /* We count the number of PC relative relocations we have
+ entered for this symbol, so that we can discard them
+ again if the symbol is later defined by a regular object.
+ We know that h is really a pointer to an
elf_cris_link_hash_entry. */
- if ((r_type == R_CRIS_8_PCREL
- || r_type == R_CRIS_16_PCREL
- || r_type == R_CRIS_32_PCREL)
- && info->symbolic)
- {
- struct elf_cris_link_hash_entry *eh;
- struct elf_cris_pcrel_relocs_copied *p;
+ {
+ struct elf_cris_link_hash_entry *eh;
+ struct elf_cris_pcrel_relocs_copied *p;
- eh = elf_cris_hash_entry (h);
+ eh = elf_cris_hash_entry (h);
- for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
- if (p->section == sreloc)
- break;
+ for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
+ if (p->section == sreloc)
+ break;
- if (p == NULL)
- {
- p = ((struct elf_cris_pcrel_relocs_copied *)
- bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
- if (p == NULL)
- return FALSE;
- p->next = eh->pcrel_relocs_copied;
- eh->pcrel_relocs_copied = p;
- p->section = sreloc;
- p->count = 0;
- }
+ if (p == NULL)
+ {
+ p = ((struct elf_cris_pcrel_relocs_copied *)
+ bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
+ if (p == NULL)
+ return FALSE;
+ p->next = eh->pcrel_relocs_copied;
+ eh->pcrel_relocs_copied = p;
+ p->section = sreloc;
+ p->count = 0;
+ p->r_type = r_type;
+ }
- ++p->count;
- }
+ ++p->count;
+ }
break;
/* This relocation describes the C++ object vtable hierarchy.
{
for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
s->section->size -= s->count * sizeof (Elf32_External_Rela);
+
+ return TRUE;
+ }
+
+ /* If we have accounted for PC-relative relocs for read-only
+ sections, now is the time to warn for them. We can't do it in
+ cris_elf_check_relocs, because we don't know the status of all
+ symbols at that time (and it's common to force symbols local
+ late). */
+
+ for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
+ {
+ BFD_ASSERT ((s->section->flags & SEC_READONLY) != 0);
+
+ /* FIXME: How do we make this optionally a warning only? */
+ (*_bfd_error_handler)
+ (_("%B, section `%A', to symbol `%s':\n"
+ " relocation %s should not be used"
+ " in a shared object; recompile with -fPIC"),
+ s->section->owner,
+ s->section,
+ h->root.root.root.string,
+ cris_elf_howto_table[s->r_type].name);
+
+ info->flags |= DF_TEXTREL;
}
return TRUE;
unsigned long symndx)
{
struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) hr;
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
bfd_vma eltsiz = 0;
/* We may have one regular GOT entry or up to two TLS GOT
entries. */
if (h == NULL)
{
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (ibfd);
BFD_ASSERT (local_got_refcounts != NULL);
eltsiz += 4;
}
+ /* We're only called when h->got.refcount is non-zero, so we must
+ have a non-zero size. */
+ BFD_ASSERT (eltsiz != 0);
return eltsiz;
}
\f
elf_cris_link_hash_table_create
#define elf_backend_adjust_dynamic_symbol \
elf_cris_adjust_dynamic_symbol
+#define elf_backend_copy_indirect_symbol \
+ elf_cris_copy_indirect_symbol
#define elf_backend_size_dynamic_sections \
elf_cris_size_dynamic_sections
#define elf_backend_init_index_section _bfd_elf_init_1_index_section