]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - bfd/elf32-cris.c
Merge commit 'upstream/2.20'
[msp430-binutils.git] / bfd / elf32-cris.c
index dcff1ebcd174f32c0fc6eb395d2bb9079ca4f58c..2037b10f59ec6f82e628fe3c09532fcc45cb3f76 100644 (file)
@@ -1,5 +1,5 @@
 /* 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, 2009
    Free Software Foundation, Inc.
    Contributed by Axis Communications AB.
    Written by Hans-Peter Nilsson, based on elf32-fr30.c
@@ -27,6 +27,7 @@
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/cris.h"
+#include <limits.h>
 
 /* Forward declarations.  */
 static reloc_howto_type * cris_reloc_type_lookup
@@ -409,7 +410,34 @@ static reloc_howto_type cris_elf_howto_table [] =
         FALSE,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        TRUE)                  /* pcrel_offset */
+        TRUE),                 /* pcrel_offset */
+
+  /* We don't handle these in any special manner and cross-format
+     linking is not supported; just recognize them enough to pass them
+     around.  FIXME: do the same for most PIC relocs and add sanity
+     tests to actually refuse gracefully to handle these and PIC
+     relocs for cross-format linking.  */
+#define TLSHOWTO32(name) \
+ HOWTO (name, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, \
+        bfd_elf_generic_reloc, #name, FALSE, 0, 0xffffffff, FALSE)
+#define TLSHOWTO16X(name, X)        \
+ HOWTO (name, 0, 1, 16, FALSE, 0, complain_overflow_ ## X, \
+        bfd_elf_generic_reloc, #name, FALSE, 0, 0xffff, FALSE)
+#define TLSHOWTO16(name) TLSHOWTO16X(name, unsigned)
+#define TLSHOWTO16S(name) TLSHOWTO16X(name, signed)
+
+  TLSHOWTO32 (R_CRIS_32_GOT_GD),
+  TLSHOWTO16 (R_CRIS_16_GOT_GD),
+  TLSHOWTO32 (R_CRIS_32_GD),
+  TLSHOWTO32 (R_CRIS_DTP),
+  TLSHOWTO32 (R_CRIS_32_DTPREL),
+  TLSHOWTO16S (R_CRIS_16_DTPREL),
+  TLSHOWTO32 (R_CRIS_32_GOT_TPREL),
+  TLSHOWTO16S (R_CRIS_16_GOT_TPREL),
+  TLSHOWTO32 (R_CRIS_32_TPREL),
+  TLSHOWTO16S (R_CRIS_16_TPREL),
+  TLSHOWTO32 (R_CRIS_DTPMOD),
+  TLSHOWTO32 (R_CRIS_32_IE)
 };
 \f
 /* Map BFD reloc types to CRIS ELF reloc types.  */
@@ -441,7 +469,19 @@ static const struct cris_reloc_map cris_reloc_map [] =
   { BFD_RELOC_CRIS_32_GOTPLT,  R_CRIS_32_GOTPLT },
   { BFD_RELOC_CRIS_32_GOTREL,  R_CRIS_32_GOTREL },
   { BFD_RELOC_CRIS_32_PLT_GOTREL, R_CRIS_32_PLT_GOTREL },
-  { BFD_RELOC_CRIS_32_PLT_PCREL, R_CRIS_32_PLT_PCREL }
+  { BFD_RELOC_CRIS_32_PLT_PCREL, R_CRIS_32_PLT_PCREL },
+  { BFD_RELOC_CRIS_32_GOT_GD,  R_CRIS_32_GOT_GD },
+  { BFD_RELOC_CRIS_16_GOT_GD,  R_CRIS_16_GOT_GD },
+  { BFD_RELOC_CRIS_32_GD,      R_CRIS_32_GD },
+  { BFD_RELOC_CRIS_DTP,        R_CRIS_DTP },
+  { BFD_RELOC_CRIS_32_DTPREL,  R_CRIS_32_DTPREL },
+  { BFD_RELOC_CRIS_16_DTPREL,  R_CRIS_16_DTPREL },
+  { BFD_RELOC_CRIS_32_GOT_TPREL, R_CRIS_32_GOT_TPREL },
+  { BFD_RELOC_CRIS_16_GOT_TPREL, R_CRIS_16_GOT_TPREL },
+  { BFD_RELOC_CRIS_32_TPREL,   R_CRIS_32_TPREL },
+  { BFD_RELOC_CRIS_16_TPREL,   R_CRIS_16_TPREL },
+  { BFD_RELOC_CRIS_DTPMOD,     R_CRIS_DTPMOD },
+  { BFD_RELOC_CRIS_32_IE,      R_CRIS_32_IE }
 };
 
 static reloc_howto_type *
@@ -481,7 +521,7 @@ cris_info_to_howto_rela (abfd, cache_ptr, dst)
      arelent * cache_ptr;
      Elf_Internal_Rela * dst;
 {
-  unsigned int r_type;
+  enum elf_cris_reloc_type r_type;
 
   r_type = ELF32_R_TYPE (dst->r_info);
   BFD_ASSERT (r_type < (unsigned int) R_CRIS_max);
@@ -756,10 +796,15 @@ struct elf_cris_pcrel_relocs_copied
 {
   /* 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.  */
@@ -783,8 +828,39 @@ struct elf_cris_link_hash_entry
      this with gotplt_refcount in a union, like the got and plt unions in
      elf_link_hash_entry.  */
   bfd_size_type gotplt_offset;
+
+  /* The root.got.refcount is the sum of the regular reference counts
+     (this) and those members below.  We have to keep a separate count
+     to track when we've found the first (or last) reference to a
+     regular got entry.  The offset is in root.got.offset.  */
+  bfd_signed_vma reg_got_refcount;
+
+  /* Similar to the above, the number of reloc references to this
+     symbols that need a R_CRIS_32_TPREL slot.  The offset is in
+     root.got.offset, because this and .dtp_refcount can't validly
+     happen when there's also a regular GOT entry; that's invalid
+     input for which an error is emitted.  */
+  bfd_signed_vma tprel_refcount;
+
+  /* Similar to the above, the number of reloc references to this
+     symbols that need a R_CRIS_DTP slot.  The offset is in
+     root.got.offset; plus 4 if .tprel_refcount > 0.  */
+  bfd_signed_vma dtp_refcount;
 };
 
+/* The local_got_refcounts and local_got_offsets are a multiple of
+   LSNUM in size, namely LGOT_ALLOC_NELTS_FOR(LSNUM) (plus one for the
+   refcount for GOT itself, see code), with the summary / group offset
+   for local symbols located at offset N, reference counts for
+   ordinary (address) relocs at offset N + LSNUM, for R_CRIS_DTP
+   relocs at offset N + 2*LSNUM, and for R_CRIS_32_TPREL relocs at N +
+   3*LSNUM.  */
+
+#define LGOT_REG_NDX(x) ((x) + symtab_hdr->sh_info)
+#define LGOT_DTP_NDX(x) ((x) + 2 * symtab_hdr->sh_info)
+#define LGOT_TPREL_NDX(x) ((x) + 3 * symtab_hdr->sh_info)
+#define LGOT_ALLOC_NELTS_FOR(x) ((x) * 4)
+
 /* CRIS ELF linker hash table.  */
 
 struct elf_cris_link_hash_table
@@ -795,6 +871,13 @@ struct elf_cris_link_hash_table
      since we try and avoid creating GOTPLT:s when there's already a GOT.
      Instead, we keep and update the next available index here.  */
   bfd_size_type next_gotplt_entry;
+
+  /* The number of R_CRIS_32_DTPREL and R_CRIS_16_DTPREL that have
+     been seen for any input; if != 0, then the constant-offset
+     R_CRIS_DTPMOD is needed for this DSO/executable.  This turns
+     negative at relocation, so that we don't need an extra flag for
+     when the reloc is output.  */
+  bfd_signed_vma dtpmod_refcount;
 };
 
 /* Traverse a CRIS ELF linker hash table.  */
@@ -810,6 +893,13 @@ struct elf_cris_link_hash_table
 #define elf_cris_hash_table(p) \
   ((struct elf_cris_link_hash_table *) (p)->hash)
 
+/* Get the CRIS ELF linker hash entry from a regular hash entry (the
+   "parent class").  The .root reference is just a simple type
+   check on the argument.  */
+
+#define elf_cris_hash_entry(p) \
+ ((struct elf_cris_link_hash_entry *) (&(p)->root))
+
 /* Create an entry in a CRIS ELF linker hash table.  */
 
 static struct bfd_hash_entry *
@@ -839,6 +929,9 @@ elf_cris_link_hash_newfunc (entry, table, string)
       ret->pcrel_relocs_copied = NULL;
       ret->gotplt_refcount = 0;
       ret->gotplt_offset = 0;
+      ret->dtp_refcount = 0;
+      ret->tprel_refcount = 0;
+      ret->reg_got_refcount = 0;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -869,6 +962,9 @@ elf_cris_link_hash_table_create (abfd)
      are used for run-time symbol evaluation.  */
   ret->next_gotplt_entry = 12;
 
+  /* We haven't seen any R_CRIS_nn_GOT_TPREL initially.  */
+  ret->dtpmod_refcount = 0;
+
   return &ret->root.root;
 }
 \f
@@ -886,11 +982,12 @@ cris_final_link_relocate (howto, input_bfd, input_section, contents, rel,
      bfd_vma             relocation;
 {
   bfd_reloc_status_type r;
+  enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
 
   /* PC-relative relocations are relative to the position *after*
      the reloc.  Note that for R_CRIS_8_PCREL the adjustment is
      not a single byte, since PC must be 16-bit-aligned.  */
-  switch (ELF32_R_TYPE (rel->r_info))
+  switch (r_type)
     {
       /* Check that the 16-bit GOT relocs are positive.  */
     case R_CRIS_16_GOTPLT:
@@ -918,6 +1015,14 @@ cris_final_link_relocate (howto, input_bfd, input_section, contents, rel,
   return r;
 }
 \f
+
+/* The number of errors left before we stop outputting reloc-specific
+   explanatory messages.  By coincidence, this works nicely together
+   with the default number of messages you'll get from LD about
+   "relocation truncated to fit" messages before you get an
+   "additional relocation overflows omitted from the output".  */
+static int additional_relocation_error_msg_count = 10;
+
 /* Relocate an CRIS ELF section.  See elf32-fr30.c, from where this was
    copied, for further comments.  */
 
@@ -942,6 +1047,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   asection *sreloc;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
+  asection *srelgot;
 
   dynobj = elf_hash_table (info)->dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
@@ -952,6 +1058,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
   sgot = NULL;
   splt = NULL;
   sreloc = NULL;
+  srelgot = NULL;
 
   if (dynobj != NULL)
     {
@@ -969,7 +1076,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
       bfd_vma relocation;
       bfd_reloc_status_type r;
       const char *symname = NULL;
-      int r_type;
+      enum elf_cris_reloc_type r_type;
 
       r_type = ELF32_R_TYPE (rel->r_info);
 
@@ -1004,6 +1111,8 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
 
+         symname = h->root.root.string;
+
          if (unresolved_reloc
              /* Perhaps we should detect the cases that
                 sec->output_section is expected to be NULL like i386 and
@@ -1222,20 +1331,21 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
                    if (info->shared)
                      {
-                       asection *s;
                        Elf_Internal_Rela outrel;
                        bfd_byte *loc;
 
-                       s = bfd_get_section_by_name (dynobj, ".rela.got");
-                       BFD_ASSERT (s != NULL);
+                       if (srelgot == NULL)
+                         srelgot
+                           = bfd_get_section_by_name (dynobj, ".rela.got");
+                       BFD_ASSERT (srelgot != NULL);
 
                        outrel.r_offset = (sgot->output_section->vma
                                           + sgot->output_offset
                                           + off);
                        outrel.r_info = ELF32_R_INFO (0, R_CRIS_RELATIVE);
                        outrel.r_addend = relocation;
-                       loc = s->contents;
-                       loc += s->reloc_count++ * sizeof (Elf32_External_Rela);
+                       loc = srelgot->contents;
+                       loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
                        bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
                      }
 
@@ -1371,7 +1481,8 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
        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.  */
@@ -1385,7 +1496,7 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                   && 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;
@@ -1397,33 +1508,13 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
 
              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;
                    }
@@ -1437,7 +1528,16 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
                                         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);
@@ -1511,6 +1611,426 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
            }
 
          break;
+
+       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
+             && (info->shared
+                 || (!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.  */
+                ? _("%B, section %A: relocation %s has an undefined"
+                    " reference to `%s', perhaps a declaration mixup?")
+                : ("%B, section %A: 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
+                     || 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
+             && (input_section->flags & SEC_ALLOC) != 0)
+           {
+             asection *sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+             BFD_ASSERT (sgotplt != NULL);
+
+             if (info->shared)
+               {
+                 Elf_Internal_Rela outrel;
+                 bfd_byte *loc;
+
+                 if (srelgot == NULL)
+                   srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                 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.  */
+             elf_cris_hash_table (info)->dtpmod_refcount
+               = -elf_cris_hash_table (info)->dtpmod_refcount;
+           }
+
+         /* The thread-based offset to the local symbol is the
+            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
+                  + (info->shared
+                     ? 0 : elf_hash_table (info)->tls_size));
+         break;
+
+       case R_CRIS_32_GD:
+         if (info->shared)
+           {
+             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)
+               (_("%B, section %A: relocation %s with non-zero addend %d"
+                  " against symbol `%s'"),
+                input_bfd,
+                input_section,
+                cris_elf_howto_table[r_type].name,
+                rel->r_addend,
+                symname[0] != '\0' ? symname : _("[whose name is lost]"));
+
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+
+         if (!info->shared
+             && (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);
+
+                 if (srelgot == NULL)
+                   srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                 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 (info->shared)
+           {
+             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)
+               (_("%B, section %A: relocation %s with non-zero addend %d"
+                  " against symbol `%s'"),
+                input_bfd,
+                input_section,
+                cris_elf_howto_table[r_type].name,
+                rel->r_addend,
+                symname[0] != '\0' ? symname : _("[whose name is lost]"));
+             bfd_set_error (bfd_error_bad_value);
+             return FALSE;
+           }
+
+         if (!info->shared && (h == NULL || h->def_regular))
+           {
+             /* 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;
+
+                 if (srelgot == NULL)
+                   srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                 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 (info->shared)
+           {
+             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)
+               (_("%B, section %A: 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;
        }
 
       r = cris_final_link_relocate (howto, input_bfd, input_section,
@@ -1526,6 +2046,37 @@ cris_elf_relocate_section (output_bfd, info, input_bfd, input_section,
              r = info->callbacks->reloc_overflow
                (info, (h ? &h->root : NULL), symname, howto->name,
                 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
+             if (additional_relocation_error_msg_count > 0)
+               {
+                 additional_relocation_error_msg_count--;
+                 switch (r_type)
+                   {
+                   case R_CRIS_16_GOTPLT:
+                   case R_CRIS_16_GOT:
+
+                     /* Not just TLS is involved here, so we make
+                        generation and message depend on -fPIC/-fpic
+                        only.  */
+                   case R_CRIS_16_GOT_TPREL:
+                   case R_CRIS_16_GOT_GD:
+                     (*_bfd_error_handler)
+                       (_("(too many global variables for -fpic:"
+                          " recompile with -fPIC)"));
+                     break;
+
+                   case R_CRIS_16_TPREL:
+                   case R_CRIS_16_DTPREL:
+                     (*_bfd_error_handler)
+                       (_("(thread-local data too big for -fpic or"
+                          " -msmall-tls: recompile with -fPIC or"
+                          " -mno-small-tls)"));
+                     break;
+
+                     /* No known cause for overflow for other relocs.  */
+                   default:
+                     break;
+                   }
+               }
              break;
 
            case bfd_reloc_undefined:
@@ -1612,18 +2163,24 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
       bfd_vma got_base;
 
       bfd_vma gotplt_offset
-       = ((struct elf_cris_link_hash_entry *) h)->gotplt_offset;
+       = elf_cris_hash_entry (h)->gotplt_offset;
       Elf_Internal_Rela rela;
       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"
@@ -1673,7 +2230,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
        {
          /* 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".  */
@@ -1696,7 +2253,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
                           + 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);
        }
 
@@ -1725,6 +2282,7 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
      where we do not output a PLT: the PLT reloc was output above and all
      references to the function symbol are redirected to the PLT.  */
   if (h->got.offset != (bfd_vma) -1
+      && (elf_cris_hash_entry (h)->reg_got_refcount > 0)
       && (info->shared
          || (h->dynindx != -1
              && h->plt.offset == (bfd_vma) -1
@@ -1806,7 +2364,9 @@ elf_cris_finish_dynamic_symbol (output_bfd, info, h, sym)
   return TRUE;
 }
 \f
-/* Finish up the dynamic sections.  */
+/* Finish up the dynamic sections.  Do *not* emit relocs here, as their
+   offsets were changed, as part of -z combreloc handling, from those we
+   computed.  */
 
 static bfd_boolean
 elf_cris_finish_dynamic_sections (output_bfd, info)
@@ -1959,12 +2519,16 @@ cris_elf_gc_mark_hook (asection *sec,
                       struct elf_link_hash_entry *h,
                       Elf_Internal_Sym *sym)
 {
+  enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
   if (h != NULL)
-    switch (ELF32_R_TYPE (rel->r_info))
+    switch (r_type)
       {
       case R_CRIS_GNU_VTINHERIT:
       case R_CRIS_GNU_VTENTRY:
        return NULL;
+
+      default:
+       break;
       }
 
   return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
@@ -1986,6 +2550,9 @@ cris_elf_gc_sweep_hook (bfd *abfd,
   asection *sgot;
   asection *srelgot;
 
+  if (info->relocatable)
+    return TRUE;
+
   dynobj = elf_hash_table (info)->dynobj;
   if (dynobj == NULL)
     return TRUE;
@@ -2002,6 +2569,9 @@ cris_elf_gc_sweep_hook (bfd *abfd,
     {
       unsigned long r_symndx;
       struct elf_link_hash_entry *h = NULL;
+      bfd_signed_vma got_element_size = 4;
+      bfd_signed_vma *specific_refcount = NULL;
+      enum elf_cris_reloc_type r_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx >= symtab_hdr->sh_info)
@@ -2012,21 +2582,63 @@ cris_elf_gc_sweep_hook (bfd *abfd,
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
        }
 
-      switch (ELF32_R_TYPE (rel->r_info))
+      r_type = ELF32_R_TYPE (rel->r_info);
+      switch (r_type)
        {
+       case R_CRIS_32_GOT:
+       case R_CRIS_16_GOT:
+       case R_CRIS_16_GOTPLT:
+       case R_CRIS_32_GOTPLT:
+         specific_refcount = h != NULL
+           ? &((struct elf_cris_link_hash_entry *) h)->reg_got_refcount
+           : &local_got_refcounts[LGOT_REG_NDX (r_symndx)];
+         break;
+
+       case R_CRIS_32_GD:
+       case R_CRIS_32_GOT_GD:
+       case R_CRIS_16_GOT_GD:
+         got_element_size = 8;
+         specific_refcount = h != NULL
+           ? &((struct elf_cris_link_hash_entry *) h)->dtp_refcount
+           : &local_got_refcounts[LGOT_DTP_NDX (r_symndx)];
+         break;
+
+       case R_CRIS_32_IE:
+       case R_CRIS_16_GOT_TPREL:
+       case R_CRIS_32_GOT_TPREL:
+         specific_refcount = h != NULL
+           ? &((struct elf_cris_link_hash_entry *) h)->tprel_refcount
+           : &local_got_refcounts[LGOT_TPREL_NDX (r_symndx)];
+         break;
+
+       default:
+         break;
+       }
+
+      switch (r_type)
+       {
+       case R_CRIS_32_IE:
+       case R_CRIS_32_GD:
+       case R_CRIS_16_GOT_TPREL:
+       case R_CRIS_32_GOT_TPREL:
+       case R_CRIS_32_GOT_GD:
+       case R_CRIS_16_GOT_GD:
        case R_CRIS_16_GOT:
        case R_CRIS_32_GOT:
          if (h != NULL)
            {
-             if (h->got.refcount > 0)
+             /* If the counters are 0 when we got here, we've
+                miscounted somehow somewhere, an internal error.  */
+             BFD_ASSERT (h->got.refcount > 0);
+             --h->got.refcount;
+
+             BFD_ASSERT (*specific_refcount > 0);
+             --*specific_refcount;
+             if (*specific_refcount == 0)
                {
-                 --h->got.refcount;
-                 if (h->got.refcount == 0)
-                   {
-                     /* We don't need the .got entry any more.  */
-                     sgot->size -= 4;
-                     srelgot->size -= sizeof (Elf32_External_Rela);
-                   }
+                 /* We don't need the .got entry any more.  */
+                 sgot->size -= got_element_size;
+                 srelgot->size -= sizeof (Elf32_External_Rela);
                }
              break;
            }
@@ -2034,16 +2646,19 @@ cris_elf_gc_sweep_hook (bfd *abfd,
        local_got_reloc:
          if (local_got_refcounts != NULL)
            {
-             if (local_got_refcounts[r_symndx] > 0)
+             /* If the counters are 0 when we got here, we've
+                miscounted somehow somewhere, an internal error.  */
+             BFD_ASSERT (local_got_refcounts[r_symndx] > 0);
+             --local_got_refcounts[r_symndx];
+
+             BFD_ASSERT (*specific_refcount > 0);
+             --*specific_refcount;
+             if (*specific_refcount == 0)
                {
-                 --local_got_refcounts[r_symndx];
-                 if (local_got_refcounts[r_symndx] == 0)
-                   {
-                     /* We don't need the .got entry any more.  */
-                     sgot->size -= 4;
-                     if (info->shared)
-                       srelgot->size -= sizeof (Elf32_External_Rela);
-                   }
+                 /* We don't need the .got entry any more.  */
+                 sgot->size -= got_element_size;
+                 if (info->shared)
+                   srelgot->size -= sizeof (Elf32_External_Rela);
                }
            }
          break;
@@ -2073,6 +2688,19 @@ cris_elf_gc_sweep_hook (bfd *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;
+         BFD_ASSERT (local_got_refcounts != NULL);
+         local_got_refcounts[-1]--;
+         break;
+
        default:
          break;
        }
@@ -2102,12 +2730,13 @@ elf_cris_adjust_gotplt_to_got (h, p)
   if (h->gotplt_refcount <= 0)
     return TRUE;
 
-  if (h->root.got.refcount > 0)
+  if (h->reg_got_refcount > 0)
     {
-      /* There's a GOT entry for this symbol.  Just adjust the refcount.
-        Probably not necessary at this stage, but keeping it accurate
+      /* There's a GOT entry for this symbol.  Just adjust the refcounts.
+        Probably not necessary at this stage, but keeping them accurate
         helps avoiding surprises later.  */
       h->root.got.refcount += h->gotplt_refcount;
+      h->reg_got_refcount += h->gotplt_refcount;
       h->gotplt_refcount = 0;
     }
   else
@@ -2121,8 +2750,9 @@ elf_cris_adjust_gotplt_to_got (h, p)
       sgot = bfd_get_section_by_name (dynobj, ".got");
       srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 
-      /* Put an accurate refcount there.  */
-      h->root.got.refcount = h->gotplt_refcount;
+      /* Put accurate refcounts there.  */
+      h->root.got.refcount += h->gotplt_refcount;
+      h->reg_got_refcount = h->gotplt_refcount;
 
       h->gotplt_refcount = 0;
 
@@ -2432,6 +3062,44 @@ elf_cris_adjust_dynamic_symbol (info, h)
   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)
+    {
+      /* 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);
+  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
@@ -2443,7 +3111,7 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
 {
   bfd *dynobj;
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_link_hash_entry **sym_hashes;
   bfd_signed_vma *local_got_refcounts;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
@@ -2457,26 +3125,27 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
   dynobj = elf_hash_table (info)->dynobj;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym);
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
   sgot = NULL;
   srelgot = NULL;
   sreloc = NULL;
 
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
       struct elf_link_hash_entry *h;
       unsigned long r_symndx;
       enum elf_cris_reloc_type r_type;
+      bfd_signed_vma got_element_size = 4;
+      unsigned long r_symndx_lgot = INT_MAX;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
-        h = NULL;
+       {
+         h = NULL;
+         r_symndx_lgot = LGOT_REG_NDX (r_symndx);
+       }
       else
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
@@ -2491,6 +3160,30 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
         on the first input bfd we found that contained dynamic relocs.  */
       switch (r_type)
        {
+       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++;
+         /* Fall through.  */
+
+       case R_CRIS_32_IE:
+       case R_CRIS_32_GD:
+       case R_CRIS_16_GOT_GD:
+       case R_CRIS_32_GOT_GD:
+       case R_CRIS_32_GOT_TPREL:
+       case R_CRIS_16_GOT_TPREL:
        case R_CRIS_16_GOT:
        case R_CRIS_32_GOT:
        case R_CRIS_32_GOTREL:
@@ -2519,6 +3212,26 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
              if (!_bfd_elf_create_got_section (dynobj, info))
                return FALSE;
            }
+
+         if (sgot == NULL)
+           sgot = bfd_get_section_by_name (dynobj, ".got");
+
+         if (local_got_refcounts == NULL)
+           {
+             bfd_size_type amt;
+
+             /* We use index local_got_refcounts[-1] to count all
+                GOT-relative relocations that do not have explicit
+                GOT entries.  */
+             amt = LGOT_ALLOC_NELTS_FOR (symtab_hdr->sh_info) + 1;
+             amt *= sizeof (bfd_signed_vma);
+             local_got_refcounts = ((bfd_signed_vma *) bfd_zalloc (abfd, amt));
+             if (local_got_refcounts == NULL)
+               return FALSE;
+
+             local_got_refcounts++;
+             elf_local_got_refcounts (abfd) = local_got_refcounts;
+           }
          break;
 
        default:
@@ -2529,6 +3242,24 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
         specific GOT entry).  */
       switch (r_type)
        {
+       case R_CRIS_16_DTPREL:
+       case R_CRIS_32_DTPREL:
+         /* Not requesting .got.rela for an executable: the contents
+            of the first entry is constant there.  For a shared
+            library, we need .got.rela for the R_CRIS_DTPMOD
+            relocation at index 3.  */
+         if (!info->shared)
+           break;
+         /* Fall through.  */
+
+       case R_CRIS_32_IE:
+       case R_CRIS_32_GD:
+       case R_CRIS_16_GOT_GD:
+       case R_CRIS_32_GOT_GD:
+       case R_CRIS_32_GOT_TPREL:
+       case R_CRIS_16_GOT_TPREL:
+         /* Fall through.  */
+
          /* For R_CRIS_16_GOTPLT and R_CRIS_32_GOTPLT, we need a GOT
             entry only for local symbols.  Unfortunately, we don't know
             until later on if there's a version script that forces the
@@ -2559,31 +3290,69 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
                    return FALSE;
                }
            }
-         /* Fall through.  */
+         break;
 
-       case R_CRIS_32_GOTREL:
-       case R_CRIS_32_PLT_GOTREL:
-         if (sgot == NULL)
-           sgot = bfd_get_section_by_name (dynobj, ".got");
+       default:
+         break;
+       }
 
-         if (local_got_refcounts == NULL)
+      /* Warn and error for invalid input.  */
+      switch (r_type)
+       {
+       case R_CRIS_32_IE:
+       case R_CRIS_32_TPREL:
+       case R_CRIS_16_TPREL:
+       case R_CRIS_32_GD:
+         if (info->shared)
            {
-             bfd_size_type amt;
+             (*_bfd_error_handler)
+               (_("%B, section %A:\n  relocation %s not valid"
+                  " in a shared object;"
+                  " typically an option mixup, recompile with -fPIC"),
+                abfd,
+                sec,
+                cris_elf_howto_table[r_type].name);
+             /* Don't return FALSE here; we want messages for all of
+                these and the error behavior is ungraceful
+                anyway.  */
+           }
+       default:
+         break;
+       }
 
-             /* We use index local_got_refcounts[-1] to count all
-                GOT-relative relocations that do not have explicit
-                GOT entries.  */
-             amt = symtab_hdr->sh_info + 1;
-             amt *= sizeof (bfd_signed_vma);
-             local_got_refcounts = ((bfd_signed_vma *) bfd_zalloc (abfd, amt));
-             if (local_got_refcounts == NULL)
-               return FALSE;
+      switch (r_type)
+       {
+       case R_CRIS_32_GD:
+       case R_CRIS_16_GOT_GD:
+       case R_CRIS_32_GOT_GD:
+         /* These are requests for tls_index entries, run-time R_CRIS_DTP.  */
+         got_element_size = 8;
+         r_symndx_lgot = LGOT_DTP_NDX (r_symndx);
+         break;
 
-             local_got_refcounts++;
-             elf_local_got_refcounts (abfd) = local_got_refcounts;
-           }
+       case R_CRIS_16_DTPREL:
+       case R_CRIS_32_DTPREL:
+         /* These two just request for the constant-index
+            module-local tls_index-sized GOT entry, which we add
+            elsewhere.  */
          break;
 
+       case R_CRIS_32_IE:
+       case R_CRIS_32_GOT_TPREL:
+       case R_CRIS_16_GOT_TPREL:
+         r_symndx_lgot = LGOT_TPREL_NDX (r_symndx);
+
+         /* Those relocs also require that a DSO is of type
+            Initial Exec.  Like other targets, we don't reset this
+            flag even if the relocs are GC:ed away.  */
+         if (info->shared)
+           info->flags |= DF_STATIC_TLS;
+         break;
+
+         /* Let's list the other assembler-generated TLS-relocs too,
+            just to show that they're not forgotten. */
+       case R_CRIS_16_TPREL:
+       case R_CRIS_32_TPREL:
        default:
          break;
        }
@@ -2597,13 +3366,19 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
             symbol.  */
          if (h != NULL)
            {
-             ((struct elf_cris_link_hash_entry *) h)->gotplt_refcount++;
+             elf_cris_hash_entry (h)->gotplt_refcount++;
              goto handle_gotplt_reloc;
            }
          /* If h is NULL then this is a local symbol, and we must make a
             GOT entry for it, so handle it like a GOT reloc.  */
          /* Fall through.  */
 
+       case R_CRIS_32_IE:
+       case R_CRIS_32_GD:
+       case R_CRIS_16_GOT_GD:
+       case R_CRIS_32_GOT_GD:
+       case R_CRIS_32_GOT_TPREL:
+       case R_CRIS_16_GOT_TPREL:
        case R_CRIS_16_GOT:
        case R_CRIS_32_GOT:
          /* This symbol requires a global offset table entry.  */
@@ -2617,32 +3392,81 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
                      if (!bfd_elf_link_record_dynamic_symbol (info, h))
                        return FALSE;
                    }
-
-                 /* Allocate space in the .got section.  */
-                 sgot->size += 4;
-                 /* Allocate relocation space.  */
-                 srelgot->size += sizeof (Elf32_External_Rela);
                }
+
+             /* Update the sum of reloc counts for this symbol.  */
              h->got.refcount++;
+
+             switch (r_type)
+               {
+               case R_CRIS_16_GOT:
+               case R_CRIS_32_GOT:
+                 if (elf_cris_hash_entry (h)->reg_got_refcount == 0)
+                   {
+                     /* Allocate space in the .got section.  */
+                     sgot->size += got_element_size;
+                     /* Allocate relocation space.  */
+                     srelgot->size += sizeof (Elf32_External_Rela);
+                   }
+                 elf_cris_hash_entry (h)->reg_got_refcount++;
+                 break;
+
+               case R_CRIS_32_GD:
+               case R_CRIS_16_GOT_GD:
+               case R_CRIS_32_GOT_GD:
+                 if (elf_cris_hash_entry (h)->dtp_refcount == 0)
+                   {
+                     /* Allocate space in the .got section.  */
+                     sgot->size += got_element_size;
+                     /* Allocate relocation space.  */
+                     srelgot->size += sizeof (Elf32_External_Rela);
+                   }
+                 elf_cris_hash_entry (h)->dtp_refcount++;
+                 break;
+
+               case R_CRIS_32_IE:
+               case R_CRIS_32_GOT_TPREL:
+               case R_CRIS_16_GOT_TPREL:
+                 if (elf_cris_hash_entry (h)->tprel_refcount == 0)
+                   {
+                     /* Allocate space in the .got section.  */
+                     sgot->size += got_element_size;
+                     /* Allocate relocation space.  */
+                     srelgot->size += sizeof (Elf32_External_Rela);
+                   }
+                 elf_cris_hash_entry (h)->tprel_refcount++;
+                 break;
+
+               default:
+                 BFD_FAIL ();
+                 break;
+               }
            }
          else
            {
              /* This is a global offset table entry for a local symbol.  */
-             if (local_got_refcounts[r_symndx] == 0)
+             if (local_got_refcounts[r_symndx_lgot] == 0)
                {
-                 sgot->size += 4;
+                 sgot->size += got_element_size;
                  if (info->shared)
                    {
-                     /* If we are generating a shared object, we need to
-                        output a R_CRIS_RELATIVE reloc so that the dynamic
-                        linker can adjust this GOT entry.  */
+                     /* If we are generating a shared object, we need
+                        to output a R_CRIS_RELATIVE reloc so that the
+                        dynamic linker can adjust this GOT entry.
+                        Similarly for non-regular got entries.  */
                      srelgot->size += sizeof (Elf32_External_Rela);
                    }
                }
+             /* Update the reloc-specific count.  */
+             local_got_refcounts[r_symndx_lgot]++;
+
+             /* This one is the sum of all the others.  */
              local_got_refcounts[r_symndx]++;
            }
          break;
 
+       case R_CRIS_16_DTPREL:
+       case R_CRIS_32_DTPREL:
        case R_CRIS_32_GOTREL:
          /* This reference requires a global offset table.
             FIXME: The actual refcount isn't used currently; the .got
@@ -2683,12 +3507,13 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
        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)
@@ -2701,7 +3526,56 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
                 sec,
                 cris_elf_howto_table[r_type].name);
            }
-         /* Fall through.  */
+         if (h != NULL)
+           {
+             h->non_got_ref = 1;
+
+             /* 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:
@@ -2740,107 +3614,64 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
          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 = (struct elf_cris_link_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.
@@ -2853,10 +3684,17 @@ cris_elf_check_relocs (abfd, info, sec, relocs)
         /* This relocation describes which C++ vtable entries are actually
            used.  Record for later use during GC.  */
         case R_CRIS_GNU_VTENTRY:
-          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+          BFD_ASSERT (h != NULL);
+          if (h != NULL
+              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
             return FALSE;
           break;
 
+       case R_CRIS_16_TPREL:
+       case R_CRIS_32_TPREL:
+         /* Already warned above, when necessary.  */
+         break;
+
        default:
          /* Other relocs do not appear here.  */
          bfd_set_error (bfd_error_bad_value);
@@ -2947,8 +3785,21 @@ elf_cris_size_dynamic_sections (output_bfd, info)
          /* Remember whether there is a PLT.  */
          plt = s->size != 0;
        }
+      else if (strcmp (name, ".got.plt") == 0)
+       {
+         /* 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
+           ? 8 : 0;
+       }
       else if (CONST_STRNEQ (name, ".rela"))
        {
+         if (strcmp (name, ".rela.got") == 0
+             && elf_cris_hash_table (info)->dtpmod_refcount != 0
+             && info->shared)
+           s->size += sizeof (Elf32_External_Rela);
+
          if (s->size != 0)
            {
              /* Remember whether there are any reloc sections other
@@ -3070,6 +3921,31 @@ elf_cris_discard_excess_dso_dynamics (h, inf)
     {
       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;
@@ -3097,7 +3973,7 @@ elf_cris_discard_excess_program_dynamics (h, inf)
   if (!h->root.def_dynamic
       || h->root.plt.refcount > 0)
     {
-      if (h->root.got.refcount > 0
+      if (h->reg_got_refcount > 0
          /* The size of this section is only valid and in sync with the
             various reference counts if we do dynamic; don't decrement it
             otherwise.  */
@@ -3352,7 +4228,8 @@ static enum elf_reloc_type_class
 elf_cris_reloc_type_class (rela)
      const Elf_Internal_Rela *rela;
 {
-  switch ((int) ELF32_R_TYPE (rela->r_info))
+  enum elf_cris_reloc_type r_type = ELF32_R_TYPE (rela->r_info);
+  switch (r_type)
     {
     case R_CRIS_RELATIVE:
       return reloc_class_relative;
@@ -3364,6 +4241,68 @@ elf_cris_reloc_type_class (rela)
       return reloc_class_normal;
     }
 }
+
+/* The elf_backend_got_elt_size worker.  For one symbol, we can have up to
+   two GOT entries from three types with two different sizes.  We handle
+   it as a single entry, so we can use the regular offset-calculation
+   machinery.  */
+
+static bfd_vma
+elf_cris_got_elt_size (bfd *abfd ATTRIBUTE_UNUSED,
+                      struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                      struct elf_link_hash_entry *hr,
+                      bfd *ibfd,
+                      unsigned long symndx)
+{
+  struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) hr;
+  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);
+
+      if (local_got_refcounts[LGOT_REG_NDX (symndx)] > 0)
+       {
+         /* We can't have a variable referred to both as a regular
+            variable and through TLS relocs.  */
+         BFD_ASSERT (local_got_refcounts[LGOT_DTP_NDX (symndx)] == 0
+                     && local_got_refcounts[LGOT_TPREL_NDX (symndx)] == 0);
+         return 4;
+       }
+
+      if (local_got_refcounts[LGOT_DTP_NDX (symndx)] > 0)
+       eltsiz += 8;
+
+      if (local_got_refcounts[LGOT_TPREL_NDX (symndx)] > 0)
+       eltsiz += 4;
+    }
+  else
+    {
+      struct elf_cris_link_hash_entry *hh = elf_cris_hash_entry (h);
+      if (hh->reg_got_refcount > 0)
+       {
+         /* The actual error-on-input is emitted elsewhere.  */
+         BFD_ASSERT (hh->dtp_refcount == 0 && hh->tprel_refcount == 0);
+         return 4;
+       }
+
+      if (hh->dtp_refcount > 0)
+       eltsiz += 8;
+
+      if (hh->tprel_refcount > 0)
+       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
 #define ELF_ARCH               bfd_arch_cris
 #define ELF_MACHINE_CODE       EM_CRIS
@@ -3402,6 +4341,8 @@ elf_cris_reloc_type_class (rela)
        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
@@ -3420,6 +4361,7 @@ elf_cris_reloc_type_class (rela)
 #define elf_backend_plt_readonly       1
 #define elf_backend_want_plt_sym       0
 #define elf_backend_got_header_size    12
+#define elf_backend_got_elt_size elf_cris_got_elt_size
 
 /* Later, we my want to optimize RELA entries into REL entries for dynamic
    linking and libraries (if it's a win of any significance).  Until then,