/* CRIS-specific support for 32-bit ELF.
- Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
Contributed by Axis Communications AB.
Written by Hans-Peter Nilsson, based on elf32-fr30.c
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);
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
+ || elf_cris_hash_table (info)->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 (elf_cris_hash_table (info)->dtpmod_refcount > 0
+ && (input_section->flags & SEC_ALLOC) != 0)
{
asection *sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
BFD_ASSERT (sgotplt != NULL);
}
/* The thread-based offset to the local symbol is the
- relocation. */
+ relocation.
+ For the executable, TLS data begins at the thread pointer plus
+ the negative size of the TLS data. For a DSO, that's part of
+ the module TLS offset. */
relocation -= elf_hash_table (info)->tls_sec == NULL
- ? 0 : elf_hash_table (info)->tls_sec->vma;
+ ? 0 : (elf_hash_table (info)->tls_sec->vma
+ + (info->shared
+ ? 0 : elf_hash_table (info)->tls_size));
break;
case R_CRIS_32_GD:
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;
bfd_byte *loc;
bfd_boolean has_gotplt = gotplt_offset != 0;
- /* Get the index in the procedure linkage table which
- corresponds to this symbol. This is the index of this symbol
- in all the symbols for which we are making plt entries. The
- first entry in the procedure linkage table is reserved. */
- /* We have to count backwards here, and the result is only valid as
- an index into .got.plt and its relocations. FIXME: Constants... */
- bfd_vma gotplt_index = gotplt_offset/4 - 3;
+ /* Get the index in the .rela.plt relocations for the .got.plt
+ entry that corresponds to this symbol.
+ We have to count backwards here, and the result is only valid
+ as an index into .rela.plt. We also have to undo the effect
+ of the R_CRIS_DTPMOD entry at .got index 3 (offset 12 into
+ .got.plt) for which gotplt_offset is adjusted, because while
+ that entry goes into .got.plt, its relocation goes into
+ .rela.got, not .rela.plt. (It's not PLT-specific; not to be
+ 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
+ ? gotplt_offset/4 - 2 - 3 : gotplt_offset/4 - 3);
/* Get the offset into the .got table of the entry that corresponds
to this function. Note that we embed knowledge that "incoming"
{
/* Fill in the offset to the reloc table. */
bfd_put_32 (output_bfd,
- gotplt_index * sizeof (Elf32_External_Rela),
+ rela_plt_index * sizeof (Elf32_External_Rela),
splt->contents + h->plt.offset + plt_off2);
/* Fill in the offset to the first PLT entry, where to "jump". */
+ got_offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_JUMP_SLOT);
rela.r_addend = 0;
- loc = srela->contents + gotplt_index * sizeof (Elf32_External_Rela);
+ loc = srela->contents + rela_plt_index * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
}
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)
/* 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);
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)