/* CRIS-specific support for 32-bit ELF.
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
- Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010 Free Software Foundation, Inc.
Contributed by Axis Communications AB.
Written by Hans-Peter Nilsson, based on elf32-fr30.c
PIC and shlib bits based primarily on elf32-m68k.c and elf32-i386.c.
#define elf_cris_link_hash_traverse(table, func, info) \
(elf_link_hash_traverse \
(&(table)->root, \
- (bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \
+ (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
(info)))
/* Get the CRIS ELF linker hash table from a link_info structure. */
#define elf_cris_hash_table(p) \
- ((struct elf_cris_link_hash_table *) (p)->hash)
+ (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+ == CRIS_ELF_DATA ? ((struct elf_cris_link_hash_table *) ((p)->hash)) : NULL)
/* Get the CRIS ELF linker hash entry from a regular hash entry (the
"parent class"). The .root reference is just a simple type
/* Create an entry in a CRIS ELF linker hash table. */
static struct bfd_hash_entry *
-elf_cris_link_hash_newfunc (entry, table, string)
- struct bfd_hash_entry *entry;
- struct bfd_hash_table *table;
- const char *string;
+elf_cris_link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
{
struct elf_cris_link_hash_entry *ret =
(struct elf_cris_link_hash_entry *) entry;
/* Create a CRIS ELF linker hash table. */
static struct bfd_link_hash_table *
-elf_cris_link_hash_table_create (abfd)
- bfd *abfd;
+elf_cris_link_hash_table_create (bfd *abfd)
{
struct elf_cris_link_hash_table *ret;
bfd_size_type amt = sizeof (struct elf_cris_link_hash_table);
if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
elf_cris_link_hash_newfunc,
- sizeof (struct elf_cris_link_hash_entry)))
+ sizeof (struct elf_cris_link_hash_entry),
+ CRIS_ELF_DATA))
{
free (ret);
return NULL;
copied, for further comments. */
static bfd_boolean
-cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
- contents, relocs, local_syms, local_sections)
- bfd *output_bfd ATTRIBUTE_UNUSED;
- struct bfd_link_info *info;
- bfd *input_bfd;
- asection *input_section;
- bfd_byte *contents;
- Elf_Internal_Rela *relocs;
- Elf_Internal_Sym *local_syms;
- asection **local_sections;
+cris_elf_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ Elf_Internal_Rela *relocs,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections)
{
+ struct elf_cris_link_hash_table * htab;
bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
Elf_Internal_Rela *relend;
asection *srelgot;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
dynobj = elf_hash_table (info)->dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd);
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
if (sreloc == NULL)
{
sreloc = _bfd_elf_get_dynamic_reloc_section
- (input_bfd, input_section, /*rela?*/ TRUE);
+ (dynobj, 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. */
rel->r_offset);
if (outrel.r_offset == (bfd_vma) -1)
skip = TRUE;
- else if (outrel.r_offset == (bfd_vma) -2)
+ else if (outrel.r_offset == (bfd_vma) -2
+ /* For now, undefined weak symbols with non-default
+ visibility (yielding 0), like exception info for
+ discarded sections, will get a R_CRIS_NONE
+ relocation rather than no relocation, because we
+ notice too late that the symbol doesn't need a
+ relocation. */
+ || (h != NULL
+ && h->root.type == bfd_link_hash_undefweak
+ && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT))
skip = TRUE, relocate = TRUE;
outrel.r_offset += (input_section->output_section->vma
+ input_section->output_offset);
indx = elf_section_data (osec)->dynindx;
if (indx == 0)
{
- struct elf_cris_link_hash_table *htab;
- htab = elf_cris_hash_table (info);
osec = htab->root.text_index_section;
indx = elf_section_data (osec)->dynindx;
}
case R_CRIS_16_DTPREL:
case R_CRIS_32_DTPREL:
/* This relocation must only be performed against local
- symbols. It's also ok when we link a program and the
- symbol is defined in an ordinary (non-DSO) object (if
- it's undefined there, we've already seen an error). */
+ symbols, or to sections that are not loadable. It's also
+ ok when we link a program and the symbol is defined in an
+ ordinary (non-DSO) object (if it's undefined there, we've
+ already seen an error). */
if (h != NULL
+ && (input_section->flags & SEC_ALLOC) != 0
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
&& (info->shared
|| (!h->def_regular
return FALSE;
}
- BFD_ASSERT (elf_cris_hash_table (info)->dtpmod_refcount != 0);
+ BFD_ASSERT ((input_section->flags & SEC_ALLOC) == 0
+ || htab->dtpmod_refcount != 0);
/* Fill in a R_CRIS_DTPMOD reloc at offset 3 if we haven't
already done so. Note that we do this in .got.plt, not
in .got, as .got.plt contains the first part, still the
reloc is against .got, because the linker script directs
(is required to direct) them both into .got. */
- if (elf_cris_hash_table (info)->dtpmod_refcount > 0)
+ if (htab->dtpmod_refcount > 0
+ && (input_section->flags & SEC_ALLOC) != 0)
{
asection *sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgotplt != NULL);
/* Reverse the sign to mark that we've emitted the
required GOT entry. */
- elf_cris_hash_table (info)->dtpmod_refcount
- = -elf_cris_hash_table (info)->dtpmod_refcount;
+ htab->dtpmod_refcount = - htab->dtpmod_refcount;
}
- /* The thread-based offset to the local symbol is the
- relocation. */
+ /* The relocation is the offset from the start of the module
+ TLS block to the (local) symbol. */
relocation -= elf_hash_table (info)->tls_sec == NULL
? 0 : elf_hash_table (info)->tls_sec->vma;
break;
return FALSE;
}
- if (!info->shared && (h == NULL || h->def_regular))
+ if (!info->shared
+ && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h)))
{
/* Known contents of the GOT. */
bfd_vma off;
bfd_vma off;
/* The symbol is defined in the program, so just write
- the known_tpoffset into the GOT. */
+ the -prog_tls_size+known_tpoffset into the GOT. */
relocation -= elf_hash_table (info)->tls_sec->vma;
+ relocation -= elf_hash_table (info)->tls_size;
if (h != NULL)
off = h->got.offset;
if (h != NULL
&& ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- && !h->def_regular
+ && !(h->def_regular || ELF_COMMON_DEF_P (h))
/* If it's undefined, then an error message has already
been emitted. */
&& h->root.type != bfd_link_hash_undefined)
/* NULL if we had an error. */
relocation -= elf_hash_table (info)->tls_sec == NULL
- ? 0 : elf_hash_table (info)->tls_sec->vma;
+ ? 0
+ : (elf_hash_table (info)->tls_sec->vma
+ + elf_hash_table (info)->tls_size);
/* The TLS-relative offset is the relocation. */
break;
dynamic sections here. */
static bfd_boolean
-elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
- bfd *output_bfd;
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
+elf_cris_finish_dynamic_symbol (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
{
+ struct elf_cris_link_hash_table * htab;
bfd *dynobj;
/* Where in the plt entry to put values. */
const bfd_byte *plt_entry = elf_cris_plt_entry;
const bfd_byte *plt_pic_entry = elf_cris_pic_plt_entry;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
/* Adjust the various PLT entry offsets. */
if (bfd_get_mach (output_bfd) == bfd_mach_cris_v32)
{
{
asection *splt;
asection *sgotplt;
- asection *sgot;
asection *srela;
bfd_vma got_base;
processed as part of the runtime lazy .rela.plt relocation).
FIXME: There be literal constants here... */
bfd_vma rela_plt_index
- = (elf_cris_hash_table (info)->dtpmod_refcount != 0
+ = (htab->dtpmod_refcount != 0
? gotplt_offset/4 - 2 - 3 : gotplt_offset/4 - 3);
/* Get the offset into the .got table of the entry that corresponds
bfd_vma got_offset
= (has_gotplt
? gotplt_offset
- : h->got.offset + elf_cris_hash_table(info)->next_gotplt_entry);
+ : h->got.offset + htab->next_gotplt_entry);
/* This symbol has an entry in the procedure linkage table. Set it
up. */
BFD_ASSERT (h->dynindx != -1);
splt = bfd_get_section_by_name (dynobj, ".plt");
- sgot = bfd_get_section_by_name (dynobj, ".got");
sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
srela = bfd_get_section_by_name (dynobj, ".rela.plt");
BFD_ASSERT (splt != NULL && sgotplt != NULL
asection *sec,
const Elf_Internal_Rela *relocs)
{
+ struct elf_cris_link_hash_table * htab;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_signed_vma *local_got_refcounts;
if (dynobj == NULL)
return TRUE;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
break;
case R_CRIS_32_DTPREL:
+ /* This'd be a .dtpreld entry in e.g. debug info. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ break;
+ /* Fall through. */
case R_CRIS_16_DTPREL:
- elf_cris_hash_table (info)->dtpmod_refcount--;
- if (elf_cris_hash_table (info)->dtpmod_refcount == 0)
- elf_cris_hash_table (info)->next_gotplt_entry -= 8;
+ htab->dtpmod_refcount--;
+ if (htab->dtpmod_refcount == 0)
+ htab->next_gotplt_entry -= 8;
BFD_ASSERT (local_got_refcounts != NULL);
local_got_refcounts[-1]--;
break;
return TRUE;
}
+/* The elf_backend_plt_sym_val hook function. */
+
+static bfd_vma
+cris_elf_plt_sym_val (bfd_vma i, const asection *plt,
+ const arelent *rel ATTRIBUTE_UNUSED)
+{
+ bfd_size_type plt_entry_size;
+
+ plt_entry_size
+ = (bfd_get_mach (plt->owner) == bfd_mach_cris_v32
+ ? PLT_ENTRY_SIZE_V32 : PLT_ENTRY_SIZE);
+
+ return plt->vma + (i + 1) * plt_entry_size;
+}
+
/* Make sure we emit a GOT entry if the symbol was supposed to have a PLT
entry but we found we will not create any. Called when we find we will
not have any PLT for this symbol, by for example
understand. */
static bfd_boolean
-elf_cris_adjust_dynamic_symbol (info, h)
- struct bfd_link_info *info;
- struct elf_link_hash_entry *h;
+elf_cris_adjust_dynamic_symbol (struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
{
+ struct elf_cris_link_hash_table * htab;
bfd *dynobj;
asection *s;
bfd_size_type plt_entry_size;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
dynobj = elf_hash_table (info)->dynobj;
/* Make sure we know what is going on here. */
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
((struct elf_cris_link_hash_entry *) h)->gotplt_offset
- = elf_cris_hash_table (info)->next_gotplt_entry;
- elf_cris_hash_table (info)->next_gotplt_entry += 4;
+ = htab->next_gotplt_entry;
+ htab->next_gotplt_entry += 4;
s = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (s != NULL);
/* 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;
+ {
+ /* Still, we need to copy flags for e.g. weak definitions. */
+ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+ 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);
+ if (eind->pcrel_relocs_copied != NULL)
+ {
+ if (edir->pcrel_relocs_copied != NULL)
+ {
+ struct elf_cris_pcrel_relocs_copied **pp;
+ struct elf_cris_pcrel_relocs_copied *p;
+
+ /* Add reloc counts against the indirect sym to the direct sym
+ list. Merge any entries against the same section. */
+ for (pp = &eind->pcrel_relocs_copied; *pp != NULL;)
+ {
+ struct elf_cris_pcrel_relocs_copied *q;
+ p = *pp;
+ for (q = edir->pcrel_relocs_copied; q != NULL; q = q->next)
+ if (q->section == p->section)
+ {
+ q->count += p->count;
+ *pp = p->next;
+ break;
+ }
+ if (q == NULL)
+ pp = &p->next;
+ }
+ *pp = edir->pcrel_relocs_copied;
+ }
+ XMOVOPZ (pcrel_relocs_copied, =, NULL);
+ }
XMOVE (gotplt_refcount);
XMOVE (gotplt_offset);
XMOVE (reg_got_refcount);
/* Look through the relocs for a section during the first phase. */
static bfd_boolean
-cris_elf_check_relocs (abfd, info, sec, relocs)
- bfd *abfd;
- struct bfd_link_info *info;
- asection *sec;
- const Elf_Internal_Rela *relocs;
+cris_elf_check_relocs (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *sec,
+ const Elf_Internal_Rela *relocs)
{
+ struct elf_cris_link_hash_table * htab;
bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
if (info->relocatable)
return TRUE;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
dynobj = elf_hash_table (info)->dynobj;
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
on the first input bfd we found that contained dynamic relocs. */
switch (r_type)
{
- case R_CRIS_16_DTPREL:
case R_CRIS_32_DTPREL:
+ if ((sec->flags & SEC_ALLOC) == 0)
+ /* This'd be a .dtpreld entry in e.g. debug info. We have
+ several different switch statements below, but none of
+ that is needed; we need no preparations for resolving
+ R_CRIS_32_DTPREL into a non-allocated section (debug
+ info), so let's just move on to the next
+ relocation. */
+ continue;
+ /* Fall through. */
+ case R_CRIS_16_DTPREL:
/* The first .got.plt entry is right after the R_CRIS_DTPMOD
entry at index 3. */
- if (elf_cris_hash_table (info)->dtpmod_refcount == 0)
- elf_cris_hash_table (info)->next_gotplt_entry += 8;
- elf_cris_hash_table (info)->dtpmod_refcount++;
+ if (htab->dtpmod_refcount == 0)
+ htab->next_gotplt_entry += 8;
+
+ htab->dtpmod_refcount++;
/* Fall through. */
case R_CRIS_32_IE:
eh = elf_cris_hash_entry (h);
for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
- if (p->section == sreloc)
+ if (p->section == sec)
break;
if (p == NULL)
return FALSE;
p->next = eh->pcrel_relocs_copied;
eh->pcrel_relocs_copied = p;
- p->section = sreloc;
+ p->section = sec;
p->count = 0;
p->r_type = r_type;
}
/* Set the sizes of the dynamic sections. */
static bfd_boolean
-elf_cris_size_dynamic_sections (output_bfd, info)
- bfd *output_bfd ATTRIBUTE_UNUSED;
- struct bfd_link_info *info;
+elf_cris_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info)
{
+ struct elf_cris_link_hash_table * htab;
bfd *dynobj;
asection *s;
bfd_boolean plt;
bfd_boolean relocs;
+ htab = elf_cris_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
dynobj = elf_hash_table (info)->dynobj;
BFD_ASSERT (dynobj != NULL);
else
{
/* Adjust all expected GOTPLT uses to use a GOT entry instead. */
- elf_cris_link_hash_traverse (elf_cris_hash_table (info),
- elf_cris_adjust_gotplt_to_got,
- (PTR) info);
+ elf_cris_link_hash_traverse (htab, elf_cris_adjust_gotplt_to_got,
+ info);
/* We may have created entries in the .rela.got section.
However, if we are not creating the dynamic sections, we will
visibility changes. For programs, we discard space for relocs for
symbols not referenced by any dynamic object. */
if (info->shared)
- elf_cris_link_hash_traverse (elf_cris_hash_table (info),
+ elf_cris_link_hash_traverse (htab,
elf_cris_discard_excess_dso_dynamics,
- (PTR) info);
+ info);
else
- elf_cris_link_hash_traverse (elf_cris_hash_table (info),
+ elf_cris_link_hash_traverse (htab,
elf_cris_discard_excess_program_dynamics,
- (PTR) info);
+ info);
/* The check_relocs and adjust_dynamic_symbol entry points have
determined the sizes of the various dynamic sections. Allocate
/* The .got.plt contains the .got header as well as the
actual .got.plt contents. The .got header may contain a
R_CRIS_DTPMOD entry at index 3. */
- s->size += elf_cris_hash_table (info)->dtpmod_refcount != 0
+ s->size += htab->dtpmod_refcount != 0
? 8 : 0;
}
else if (CONST_STRNEQ (name, ".rela"))
{
if (strcmp (name, ".rela.got") == 0
- && elf_cris_hash_table (info)->dtpmod_refcount != 0
+ && htab->dtpmod_refcount != 0
&& info->shared)
s->size += sizeof (Elf32_External_Rela);
|| info->symbolic))
{
for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
- s->section->size -= s->count * sizeof (Elf32_External_Rela);
-
+ {
+ asection *sreloc
+ = _bfd_elf_get_dynamic_reloc_section (elf_hash_table (info)
+ ->dynobj,
+ s->section,
+ /*rela?*/ TRUE);
+ sreloc->size -= s->count * sizeof (Elf32_External_Rela);
+ }
return TRUE;
}
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;
- }
+ if ((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;
}
#define elf_backend_relocate_section cris_elf_relocate_section
#define elf_backend_gc_mark_hook cris_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook cris_elf_gc_sweep_hook
+#define elf_backend_plt_sym_val cris_elf_plt_sym_val
#define elf_backend_check_relocs cris_elf_check_relocs
#define elf_backend_grok_prstatus cris_elf_grok_prstatus
#define elf_backend_grok_psinfo cris_elf_grok_psinfo