+
+ case R_CRIS_16_DTPREL:
+ case R_CRIS_32_DTPREL:
+ /* This relocation must only be performed against local
+ 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
+ && (bfd_link_pic (info)
+ || (!h->def_regular
+ && h->root.type != bfd_link_hash_undefined)))
+ {
+ _bfd_error_handler
+ ((h->root.type == bfd_link_hash_undefined)
+ /* We shouldn't get here for GCC-emitted code. */
+ /* xgettext:c-format */
+ ? _("%pB, section %pA: relocation %s has an undefined"
+ " reference to `%s', perhaps a declaration mixup?")
+ /* xgettext:c-format */
+ : _("%pB, section %pA: relocation %s is"
+ " not allowed for `%s', a global symbol with default"
+ " visibility, perhaps a declaration mixup?"),
+ input_bfd,
+ input_section,
+ cris_elf_howto_table[r_type].name,
+ symname != NULL && symname[0] != '\0'
+ ? symname : _("[whose name is lost]"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ 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 (htab->dtpmod_refcount > 0
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ asection *sgotplt = htab->root.sgotplt;
+ BFD_ASSERT (sgotplt != NULL);
+
+ if (bfd_link_pic (info))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ srelgot = htab->root.srelgot;
+ BFD_ASSERT (srelgot != NULL);
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 12);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 16);
+ outrel.r_offset = (sgotplt->output_section->vma
+ + sgotplt->output_offset
+ + 12);
+ outrel.r_info = ELF32_R_INFO (0, R_CRIS_DTPMOD);
+ outrel.r_addend = 0;
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+ else
+ {
+ /* For an executable, the GOT entry contents is known. */
+ bfd_put_32 (output_bfd, (bfd_vma) 1, sgotplt->contents + 12);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 16);
+ }
+
+ /* Reverse the sign to mark that we've emitted the
+ required GOT entry. */
+ htab->dtpmod_refcount = - htab->dtpmod_refcount;
+ }
+
+ /* 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;
+
+ case R_CRIS_32_GD:
+ if (bfd_link_pic (info))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+
+ /* We've already informed in cris_elf_check_relocs that
+ this is an error. */
+ return FALSE;
+ }
+ /* Fall through. */
+
+ case R_CRIS_16_GOT_GD:
+ case R_CRIS_32_GOT_GD:
+ if (rel->r_addend != 0)
+ {
+ /* We can't do anything for a relocation which is against a
+ symbol *plus offset*. The GOT holds relocations for
+ symbols. Make this an error; the compiler isn't allowed
+ to pass us these kinds of things. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB, section %pA: relocation %s with non-zero addend"
+ " %" PRId64 " against symbol `%s'"),
+ input_bfd,
+ input_section,
+ cris_elf_howto_table[r_type].name,
+ (int64_t) rel->r_addend,
+ symname[0] != '\0' ? symname : _("[whose name is lost]"));
+
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ if (!bfd_link_pic (info)
+ && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h)))
+ {
+ /* Known contents of the GOT. */
+ bfd_vma off;
+
+ /* The symbol is defined in the program, so just write
+ (1, known_tpoffset) into the GOT. */
+ relocation -= elf_hash_table (info)->tls_sec->vma;
+
+ if (h != NULL)
+ {
+ off = elf_cris_hash_entry (h)->tprel_refcount > 0
+ ? h->got.offset + 4 : h->got.offset;
+ }
+ else
+ {
+ off = local_got_offsets[r_symndx];
+ if (local_got_offsets[LGOT_TPREL_NDX (r_symndx)])
+ off += 4;
+ }
+
+ /* We use bit 1 of the offset as a flag for GOT entry with
+ the R_CRIS_DTP reloc, setting it when we've emitted the
+ GOT entry and reloc. Bit 0 is used for R_CRIS_32_TPREL
+ relocs. */
+ if ((off & 2) == 0)
+ {
+ off &= ~3;
+
+ if (h != NULL)
+ h->got.offset |= 2;
+ else
+ local_got_offsets[r_symndx] |= 2;
+
+ bfd_put_32 (output_bfd, 1, sgot->contents + off);
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off + 4);
+ }
+ else
+ off &= ~3;
+
+ relocation = sgot->output_offset + off
+ + (r_type == R_CRIS_32_GD ? sgot->output_section->vma : 0);
+ }
+ else
+ {
+ /* Not all parts of the GOT entry are known; emit a real
+ relocation. */
+ bfd_vma off;
+
+ if (h != NULL)
+ off = elf_cris_hash_entry (h)->tprel_refcount > 0
+ ? h->got.offset + 4 : h->got.offset;
+ else
+ {
+ off = local_got_offsets[r_symndx];
+ if (local_got_offsets[LGOT_TPREL_NDX (r_symndx)])
+ off += 4;
+ }
+
+ /* See above re bit 1 and bit 0 usage. */
+ if ((off & 2) == 0)
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ off &= ~3;
+
+ if (h != NULL)
+ h->got.offset |= 2;
+ else
+ local_got_offsets[r_symndx] |= 2;
+
+ /* Clear the target contents of the GOT (just as a
+ gesture; it's already cleared on allocation): this
+ relocation is not like the other dynrelocs. */
+ bfd_put_32 (output_bfd, 0, sgot->contents + off);
+ bfd_put_32 (output_bfd, 0, sgot->contents + off + 4);
+
+ srelgot = htab->root.srelgot;
+ BFD_ASSERT (srelgot != NULL);
+
+ if (h != NULL && h->dynindx != -1)
+ {
+ outrel.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_DTP);
+ relocation = 0;
+ }
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (0, R_CRIS_DTP);
+
+ /* NULL if we had an error. */
+ relocation -= elf_hash_table (info)->tls_sec == NULL
+ ? 0 : elf_hash_table (info)->tls_sec->vma;
+ }
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_addend = relocation;
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+
+ /* NULL if we had an error. */
+ if (srelgot->contents != NULL)
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+ else
+ off &= ~3;
+
+ relocation = sgot->output_offset + off
+ + (r_type == R_CRIS_32_GD ? sgot->output_section->vma : 0);
+ }
+
+ /* The GOT-relative offset to the GOT entry is the
+ relocation, or for R_CRIS_32_GD, the actual address of
+ the GOT entry. */
+ break;
+
+ case R_CRIS_32_IE:
+ if (bfd_link_pic (info))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+
+ /* We've already informed in cris_elf_check_relocs that
+ this is an error. */
+ return FALSE;
+ }
+ /* Fall through. */
+
+ case R_CRIS_32_GOT_TPREL:
+ case R_CRIS_16_GOT_TPREL:
+ if (rel->r_addend != 0)
+ {
+ /* We can't do anything for a relocation which is
+ against a symbol *plus offset*. GOT holds
+ relocations for symbols. Make this an error; the
+ compiler isn't allowed to pass us these kinds of
+ things. */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB, section %pA: relocation %s with non-zero addend"
+ " %" PRId64 " against symbol `%s'"),
+ input_bfd,
+ input_section,
+ cris_elf_howto_table[r_type].name,
+ (int64_t) rel->r_addend,
+ symname[0] != '\0' ? symname : _("[whose name is lost]"));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ if (!bfd_link_pic (info)
+ && (h == NULL || h->def_regular || ELF_COMMON_DEF_P (h)))
+ {
+ /* Known contents of the GOT. */
+ bfd_vma off;
+
+ /* The symbol is defined in the program, so just write
+ 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;
+ else
+ off = local_got_offsets[r_symndx];
+
+ /* Bit 0 is used to mark whether we've emitted the required
+ entry (and if needed R_CRIS_32_TPREL reloc). Bit 1
+ is used similarly for R_CRIS_DTP, see above. */
+ if ((off & 1) == 0)
+ {
+ off &= ~3;
+
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+ }
+ else
+ off &= ~3;
+
+ relocation = sgot->output_offset + off
+ + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0);
+ }
+ else
+ {
+ /* Emit a real relocation. */
+ bfd_vma off;
+
+ if (h != NULL)
+ off = h->got.offset;
+ else
+ off = local_got_offsets[r_symndx];
+
+ /* See above re usage of bit 0 and 1. */
+ if ((off & 1) == 0)
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+
+ off &= ~3;
+
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+
+ srelgot = htab->root.srelgot;
+ BFD_ASSERT (srelgot != NULL);
+
+ if (h != NULL && h->dynindx != -1)
+ {
+ outrel.r_info = ELF32_R_INFO (h->dynindx, R_CRIS_32_TPREL);
+ relocation = 0;
+ }
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (0, R_CRIS_32_TPREL);
+
+ /* NULL if we had an error. */
+ relocation -= elf_hash_table (info)->tls_sec == NULL
+ ? 0 : elf_hash_table (info)->tls_sec->vma;
+ }
+
+ /* Just "define" the initial contents in some
+ semi-logical way. */
+ bfd_put_32 (output_bfd, relocation, sgot->contents + off);
+
+ outrel.r_offset = (sgot->output_section->vma
+ + sgot->output_offset
+ + off);
+ outrel.r_addend = relocation;
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+ /* NULL if we had an error. */
+ if (srelgot->contents != NULL)
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ }
+ else
+ off &= ~3;
+
+ relocation = sgot->output_offset + off
+ + (r_type == R_CRIS_32_IE ? sgot->output_section->vma : 0);
+ }
+
+ /* The GOT-relative offset to the GOT entry is the relocation,
+ or for R_CRIS_32_GD, the actual address of the GOT entry. */
+ break;
+
+ case R_CRIS_16_TPREL:
+ case R_CRIS_32_TPREL:
+ /* This relocation must only be performed against symbols
+ defined in an ordinary (non-DSO) object. */
+ if (bfd_link_pic (info))
+ {
+ bfd_set_error (bfd_error_invalid_operation);
+
+ /* We've already informed in cris_elf_check_relocs that
+ this is an error. */
+ return FALSE;
+ }
+
+ if (h != NULL
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ && !(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)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB, section %pA: relocation %s is"
+ " not allowed for symbol: `%s'"
+ " which is defined outside the program,"
+ " perhaps a declaration mixup?"),
+ input_bfd,
+ input_section,
+ cris_elf_howto_table[r_type].name,
+ symname);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* NULL if we had an error. */
+ relocation -= elf_hash_table (info)->tls_sec == NULL
+ ? 0
+ : (elf_hash_table (info)->tls_sec->vma
+ + elf_hash_table (info)->tls_size);
+
+ /* The TLS-relative offset is the relocation. */
+ break;
+
+ default:
+ BFD_FAIL ();
+ return FALSE;