Fixes done to TLS.
authorCupertino Miranda <cmiranda@synopsys.com>
Tue, 14 Jun 2016 20:55:44 +0000 (22:55 +0200)
committerClaudiu Zissulescu <claziss@synopsys.com>
Mon, 11 Jul 2016 13:24:35 +0000 (15:24 +0200)
TLS relocations did not support multiple TLS modes for the same
symbol in a single object file.
Refactored how GOT and TLS is implemented. Removed code duplications between
local and global symbols conditioning.

bfd/ChangeLog:

2016-06-14  Cupertino Miranda  <cmiranda@synopsys.com>
  * arc-got.h: Moved got related structures from elf32-arc.c to
    this file. More precisely, tls_type_e, tls_got_entries, got_entry.
  * (arc_get_local_got_ents,
     got_entry_for_type,
     new_got_entry_to_list,
     tls_type_for_reloc,
     symbol_has_entry_of_type,
     get_got_entry_list_for_symbol,
     arc_got_entry_type_for_reloc,
     ADD_SYMBOL_REF_SEC_AND_RELOC,
     arc_fill_got_info_for_reloc,
     relocate_fix_got_relocs_for_got_info,
     create_got_dynrelocs_for_single_entry,
     create_got_dynrelocs_for_got_info): Added to file.
  * elf32-arc.c: Removed GOT & TLS related structs and functions to
                     arc-got.h.

Signed-off-by: Claudiu Zissulescu <claziss@synopsys.com>
bfd/ChangeLog
bfd/arc-got.h [new file with mode: 0644]
bfd/elf32-arc.c
include/elf/arc-reloc.def

index e295eca..8b1b9c7 100644 (file)
@@ -1,3 +1,17 @@
+2016-07-11  Cupertino Miranda  <cmiranda@synopsys.com>
+
+       * arc-got.h: Moved got related structures from elf32-arc.c to
+       this file. More precisely, tls_type_e, tls_got_entries, got_entry.
+       * (arc_get_local_got_ents, got_entry_for_type, new_got_entry_to_list,
+       tls_type_for_reloc, symbol_has_entry_of_type,
+       get_got_entry_list_for_symbol, arc_got_entry_type_for_reloc,
+       ADD_SYMBOL_REF_SEC_AND_RELOC, rc_fill_got_info_for_reloc,
+       relocate_fix_got_relocs_for_got_info,
+       create_got_dynrelocs_for_single_entry,
+       create_got_dynrelocs_for_got_info): Added to file.
+       * elf32-arc.c: Removed GOT & TLS related structs and functions to
+       arc-got.h.
+
 2016-07-08  James Bowman  <james.bowman@ftdichip.com>
 
        * elf32-ft32.c (ft32_reloc_map): Use R_FT32_32 for BFD_RELOC_32.
diff --git a/bfd/arc-got.h b/bfd/arc-got.h
new file mode 100644 (file)
index 0000000..9e8fd10
--- /dev/null
@@ -0,0 +1,511 @@
+/* ARC-specific support for 32-bit ELF
+   Copyright (C) 1994-2016 Free Software Foundation, Inc.
+   Contributed by Cupertino Miranda (cmiranda@synopsys.com).
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#ifndef ARC_GOT_H
+#define ARC_GOT_H
+
+enum tls_type_e
+{
+  GOT_UNKNOWN = 0,
+  GOT_NORMAL,
+  GOT_TLS_GD,
+  GOT_TLS_IE,
+  GOT_TLS_LE
+};
+
+enum tls_got_entries
+{
+  TLS_GOT_NONE = 0,
+  TLS_GOT_MOD,
+  TLS_GOT_OFF,
+  TLS_GOT_MOD_AND_OFF
+};
+
+struct got_entry
+{
+  struct got_entry *next;
+  enum tls_type_e type;
+  bfd_vma offset;
+  bfd_boolean processed;
+  bfd_boolean created_dyn_relocation;
+  enum tls_got_entries existing_entries;
+};
+
+static struct got_entry **
+arc_get_local_got_ents (bfd * abfd)
+{
+  static struct got_entry **local_got_ents = NULL;
+
+  if (local_got_ents == NULL)
+    {
+      size_t      size;
+      Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
+
+      size = symtab_hdr->sh_info * sizeof (bfd_vma);
+      local_got_ents = (struct got_entry **)
+       bfd_alloc (abfd, sizeof (struct got_entry *) * size);
+      if (local_got_ents == NULL)
+       return FALSE;
+
+      memset (local_got_ents, 0, sizeof (struct got_entry *) * size);
+      elf_local_got_ents (abfd) = local_got_ents;
+    }
+
+  return local_got_ents;
+}
+
+static struct got_entry *
+got_entry_for_type (struct got_entry **list,
+                   enum tls_type_e type)
+{
+  struct got_entry **p = list;
+  while (*p != NULL)
+    {
+      if ((*p)->type == type)
+       return *p;
+      p = &((*p)->next);
+    }
+  return NULL;
+}
+
+static void
+new_got_entry_to_list (struct got_entry **list,
+                      enum tls_type_e type,
+                      bfd_vma offset,
+                      enum tls_got_entries existing_entries)
+{
+  /* Find list end.  Avoid having multiple entries of the same
+     type.  */
+  struct got_entry **p = list;
+  while (*p != NULL)
+    {
+      if ((*p)->type == type)
+       return;
+      p = &((*p)->next);
+    }
+
+  struct got_entry *entry
+    = (struct got_entry *) malloc (sizeof (struct got_entry));
+
+  entry->type = type;
+  entry->offset = offset;
+  entry->next = NULL;
+  entry->processed = FALSE;
+  entry->created_dyn_relocation = FALSE;
+  entry->existing_entries = existing_entries;
+
+  ARC_DEBUG ("New GOT got entry added to list: "
+            "type: %d, offset: %d, existing_entries:%d\n",
+            type, offset, existing_entries);
+
+  /* Add the entry to the end of the list.  */
+  *p = entry;
+}
+
+static enum tls_type_e
+tls_type_for_reloc (reloc_howto_type *howto)
+{
+  enum tls_type_e ret = GOT_UNKNOWN;
+  if (is_reloc_for_GOT (howto))
+    ret = GOT_NORMAL;
+  else
+    {
+      switch (howto->type)
+       {
+         case R_ARC_TLS_GD_GOT:
+           ret = GOT_TLS_GD;
+           break;
+         case R_ARC_TLS_IE_GOT:
+           ret = GOT_TLS_IE;
+           break;
+         case R_ARC_TLS_LE_32:
+           ret = GOT_TLS_LE;
+           break;
+         default:
+           ret = GOT_UNKNOWN;
+           break;
+       }
+    }
+  return ret;
+};
+
+static struct got_entry **
+get_got_entry_list_for_symbol (bfd *abfd,
+                              unsigned long r_symndx,
+                              struct elf_link_hash_entry *h)
+{
+  if (h != NULL)
+    {
+      return &h->got.glist;
+    }
+  else
+    {
+      struct got_entry **local_got_ents
+       = arc_get_local_got_ents (abfd);
+      return &local_got_ents[r_symndx];
+    }
+}
+
+
+static enum tls_type_e
+arc_got_entry_type_for_reloc (reloc_howto_type *howto)
+{
+  enum tls_type_e type = GOT_UNKNOWN;
+
+  if (is_reloc_for_GOT (howto))
+    type = GOT_NORMAL;
+  else if (is_reloc_for_TLS (howto))
+    {
+      switch (howto->type)
+       {
+         case R_ARC_TLS_GD_GOT:
+           type = GOT_TLS_GD;
+           break;
+         case R_ARC_TLS_IE_GOT:
+           type = GOT_TLS_IE;
+           break;
+         default:
+           break;
+       }
+    }
+  return type;
+}
+
+#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H)       \
+  htab->s##SECNAME->size;                                              \
+  {                                                                    \
+    if (COND_FOR_RELOC)                                                        \
+      {                                                                        \
+       htab->srel##SECNAME->size += sizeof (Elf32_External_Rela);      \
+         ARC_DEBUG ("arc_info: Added reloc space in "                  \
+                    #SECNAME " section at " __FILE__                   \
+                    ":%d for symbol %s\n",                             \
+                    __LINE__, name_for_global_symbol (H));             \
+      }                                                                        \
+    if (H)                                                             \
+      if (h->dynindx == -1 && !h->forced_local)                                \
+       if (! bfd_elf_link_record_dynamic_symbol (info, H))             \
+         return FALSE;                                                 \
+     htab->s##SECNAME->size += 4;                                      \
+   }                                                                   \
+
+static bfd_boolean
+arc_fill_got_info_for_reloc (enum tls_type_e type,
+                            struct got_entry **list,
+                            struct bfd_link_info *  info,
+                            struct elf_link_hash_entry *h)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+
+  if (got_entry_for_type (list, type) != NULL)
+    return TRUE;
+
+  switch (type)
+    {
+      case GOT_NORMAL:
+       {
+         bfd_vma offset
+           = ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info)
+                                                || h != NULL, h);
+         new_got_entry_to_list (list, type, offset, TLS_GOT_NONE);
+       }
+       break;
+
+
+      case GOT_TLS_GD:
+       {
+         bfd_vma offset
+           = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+         bfd_vma ATTRIBUTE_UNUSED notneeded
+           = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+         new_got_entry_to_list (list, type, offset, TLS_GOT_MOD_AND_OFF);
+       }
+       break;
+      case GOT_TLS_IE:
+      case GOT_TLS_LE:
+       {
+         bfd_vma offset
+           = ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
+         new_got_entry_to_list (list, type, offset, TLS_GOT_OFF);
+       }
+       break;
+
+      default:
+       return FALSE;
+       break;
+    }
+  return TRUE;
+}
+
+
+static bfd_vma
+relocate_fix_got_relocs_for_got_info (struct got_entry **list_p,
+                                     enum tls_type_e type,
+                                     struct bfd_link_info *  info,
+                                     bfd *output_bfd,
+                                     unsigned long r_symndx,
+                                     Elf_Internal_Sym *local_syms,
+                                     asection **local_sections,
+                                     struct elf_link_hash_entry *h,
+                                     struct arc_relocation_data *reloc_data)
+{
+
+  if (list_p == NULL || type == GOT_UNKNOWN || type == GOT_TLS_LE)
+    return 0;
+
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  struct got_entry *entry = NULL;
+
+  entry = got_entry_for_type (list_p, type);
+  BFD_ASSERT (entry);
+
+  if (h == NULL
+      || (! elf_hash_table (info)->dynamic_sections_created
+         || (bfd_link_pic (info)
+         && SYMBOL_REFERENCES_LOCAL (info, h))))
+    {
+      const char ATTRIBUTE_UNUSED *symbol_name;
+      static const char local_name[] = "(local)";
+      asection *tls_sec = NULL;
+      bfd_vma sym_value = 0;
+
+      if (h != NULL)
+       {
+         // TODO: This should not be here.
+         reloc_data->sym_value = h->root.u.def.value;
+         reloc_data->sym_section = h->root.u.def.section;
+
+         sym_value = h->root.u.def.value
+                     + h->root.u.def.section->output_section->vma
+                     + h->root.u.def.section->output_offset;
+
+         tls_sec = elf_hash_table (info)->tls_sec;
+
+         symbol_name = h->root.root.string;
+       }
+      else
+       {
+         Elf_Internal_Sym *sym = local_syms + r_symndx;
+         asection *sec = local_sections[r_symndx];
+
+         sym_value = sym->st_value
+                           + sec->output_section->vma
+                           + sec->output_offset;
+
+         tls_sec = elf_hash_table (info)->tls_sec;
+
+         symbol_name = local_name;
+       }
+
+
+      if (entry && entry->processed == FALSE)
+       {
+         switch (entry->type)
+           {
+             case GOT_TLS_GD:
+               {
+                 BFD_ASSERT (tls_sec && tls_sec->output_section);
+                 bfd_vma sec_vma = tls_sec->output_section->vma;
+
+                 bfd_put_32 (output_bfd,
+                             sym_value - sec_vma,
+                             htab->sgot->contents + entry->offset
+                             + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+                                ? 4 : 0));
+
+                 ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
+                            "@ 0x%x, for symbol %s\n",
+                            (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
+                             "GOT_TLS_IE"),
+                            sym_value - sec_vma,
+                            htab->sgot->contents + entry->offset
+                            + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+                               ? 4 : 0),
+                            symbol_name);
+               }
+               break;
+
+             case GOT_TLS_IE:
+               {
+                 BFD_ASSERT (tls_sec && tls_sec->output_section);
+                 bfd_vma ATTRIBUTE_UNUSED sec_vma
+                   = tls_sec->output_section->vma;
+
+                 ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
+                            "@ 0x%x, for symbol %s\n",
+                            (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
+                             "GOT_TLS_IE"),
+                            sym_value - sec_vma,
+                            htab->sgot->contents + entry->offset
+                            + (entry->existing_entries == TLS_GOT_MOD_AND_OFF
+                               ? 4 : 0),
+                            symbol_name);
+               }
+               break;
+
+             case GOT_NORMAL:
+               {
+                 bfd_vma sec_vma
+                   = reloc_data->sym_section->output_section->vma
+                     + reloc_data->sym_section->output_offset;
+
+                 if (h->root.type != bfd_link_hash_undefweak)
+                   {
+                     bfd_put_32 (output_bfd,
+                                 reloc_data->sym_value + sec_vma,
+                                 htab->sgot->contents + entry->offset);
+
+                     ARC_DEBUG ("arc_info: PATCHED: 0x%08x "
+                                "@ 0x%08x for sym %s in got offset 0x%x\n",
+                                reloc_data->sym_value + sec_vma,
+                                htab->sgot->output_section->vma
+                                + htab->sgot->output_offset + entry->offset,
+                                symbol_name,
+                                entry->offset);
+                   }
+                 else
+                   {
+                     ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
+                                "@ 0x%08x for sym %s in got offset 0x%x "
+                                "(is undefweak)\n",
+                                htab->sgot->output_section->vma
+                                + htab->sgot->output_offset + entry->offset,
+                                symbol_name,
+                                entry->offset);
+                 }
+               }
+               break;
+             default:
+               BFD_ASSERT (0);
+               break;
+           }
+         entry->processed = TRUE;
+       }
+    }
+
+  return entry->offset;
+}
+
+static void
+create_got_dynrelocs_for_single_entry (struct got_entry *list,
+                                      bfd *output_bfd,
+                                      struct bfd_link_info *  info,
+                                      struct elf_link_hash_entry *h)
+{
+  if (list == NULL)
+    return;
+
+  bfd_vma got_offset = list->offset;
+
+  if (list->type == GOT_NORMAL
+      && list->created_dyn_relocation == FALSE)
+    {
+      if (bfd_link_pic (info)
+         && h != NULL
+             && (info->symbolic || h->dynindx == -1)
+             && h->def_regular)
+       {
+         ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
+       }
+      /* Do not fully understand the side effects of this condition.
+        The relocation space might still being reserved.  Perhaps
+        I should clear its value.  */
+      else if (h != NULL && h->dynindx != -1)
+       {
+         ADD_RELA (output_bfd, got, got_offset, h->dynindx, R_ARC_GLOB_DAT, 0);
+       }
+      list->created_dyn_relocation = TRUE;
+    }
+  else if (list->existing_entries != TLS_GOT_NONE
+          && list->created_dyn_relocation == FALSE)
+    {
+       /* TODO TLS: This is not called for local symbols.
+         In order to correctly implement TLS, this should also
+         be called for all local symbols with tls got entries.
+         Should be moved to relocate_section in order to make it
+         work for local symbols.  */
+      struct elf_link_hash_table *htab = elf_hash_table (info);
+      enum tls_got_entries e = list->existing_entries;
+
+      BFD_ASSERT (list->type != GOT_TLS_GD
+             || list->existing_entries == TLS_GOT_MOD_AND_OFF);
+
+      bfd_vma dynindx = (h == NULL || h->dynindx == -1) ? 0 : h->dynindx;
+
+      if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
+       {
+             ADD_RELA (output_bfd, got, got_offset, dynindx,
+                   R_ARC_TLS_DTPMOD, 0);
+             ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
+GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
+                        list->type,
+                        got_offset,
+                        htab->sgot->output_section->vma
+                        + htab->sgot->output_offset + got_offset,
+                        dynindx, 0);
+       }
+      if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
+       {
+         bfd_vma addend = 0;
+         if (list->type == GOT_TLS_IE)
+           addend = bfd_get_32 (output_bfd,
+                                htab->sgot->contents + got_offset);
+
+         ADD_RELA (output_bfd, got,
+                   got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
+                   dynindx,
+                   (list->type == GOT_TLS_IE ? R_ARC_TLS_TPOFF
+                                             : R_ARC_TLS_DTPOFF),
+                   addend);
+
+         ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
+GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
+                    list->type,
+                    got_offset,
+                    htab->sgot->output_section->vma
+                    + htab->sgot->output_offset + got_offset,
+                    dynindx, addend);
+       }
+      list->created_dyn_relocation = TRUE;
+    }
+}
+
+static void
+create_got_dynrelocs_for_got_info (struct got_entry **list_p,
+                                  bfd *output_bfd,
+                                  struct bfd_link_info *  info,
+                                  struct elf_link_hash_entry *h)
+{
+  if (list_p == NULL)
+    return;
+
+  struct got_entry *list = *list_p;
+  /* Traverse the list of got entries for this symbol.  */
+  while (list)
+    {
+      create_got_dynrelocs_for_single_entry (list, output_bfd, info, h);
+      list = list->next;
+    }
+}
+
+#undef ADD_SYMBOL_REF_SEC_AND_RELOC
+
+#endif /* ARC_GOT_H */
index 0161832..b1b5efd 100644 (file)
@@ -35,7 +35,7 @@
 # define PR_DEBUG(fmt, args...)
 #endif
 
-/* #define ARC_ENABLE_DEBUG 1 */
+/* #define ARC_ENABLE_DEBUG 1  */
 #ifndef ARC_ENABLE_DEBUG
 #define ARC_DEBUG(...)
 #else
@@ -58,6 +58,7 @@ name_for_global_symbol (struct elf_link_hash_entry *h)
     Elf_Internal_Rela _rel;                                            \
     bfd_byte * _loc;                                                   \
                                                                        \
+    BFD_ASSERT (_htab->srel##SECTION &&_htab->srel##SECTION->contents); \
     _loc = _htab->srel##SECTION->contents                              \
       + ((_htab->srel##SECTION->reloc_count)                           \
         * sizeof (Elf32_External_Rela));                               \
@@ -103,75 +104,6 @@ const char * dyn_section_names[DYN_SECTION_TYPES_END] =
   ".rela.plt"
 };
 
-enum tls_type_e
-{
-  GOT_UNKNOWN = 0,
-  GOT_NORMAL,
-  GOT_TLS_GD,
-  GOT_TLS_IE,
-  GOT_TLS_LE
-};
-
-enum tls_got_entries
-{
-  TLS_GOT_NONE = 0,
-  TLS_GOT_MOD,
-  TLS_GOT_OFF,
-  TLS_GOT_MOD_AND_OFF
-};
-
-struct got_entry
-{
-  struct got_entry *next;
-  enum tls_type_e type;
-  bfd_vma offset;
-  bfd_boolean processed;
-  bfd_boolean created_dyn_relocation;
-  enum tls_got_entries existing_entries;
-};
-
-static void
-new_got_entry_to_list (struct got_entry **list,
-                      enum tls_type_e type,
-                      bfd_vma offset,
-                      enum tls_got_entries existing_entries)
-{
-  /* Find list end.  Avoid having multiple entries of the same
-     type.  */
-  struct got_entry **p = list;
-  while (*p != NULL)
-    {
-      if ((*p)->type == type)
-       return;
-      p = &((*p)->next);
-    }
-
-  struct got_entry *entry =
-                     (struct got_entry *) malloc (sizeof(struct got_entry));
-
-  entry->type = type;
-  entry->offset = offset;
-  entry->next = NULL;
-  entry->processed = FALSE;
-  entry->created_dyn_relocation = FALSE;
-  entry->existing_entries = existing_entries;
-
-  /* Add the entry to the end of the list.  */
-  *p = entry;
-}
-
-static bfd_boolean
-symbol_has_entry_of_type (struct got_entry *list, enum tls_type_e type)
-{
-  while (list != NULL)
-    {
-      if (list->type == type)
-       return TRUE;
-      list = list->next;
-    }
-
-  return FALSE;
-}
 
 /* The default symbols representing the init and fini dyn values.
    TODO: Check what is the relation of those strings with arclinux.em
@@ -238,6 +170,32 @@ is_reloc_for_TLS (reloc_howto_type *howto)
   return (strstr (howto->name, "TLS") != NULL) ? TRUE : FALSE;
 }
 
+struct arc_relocation_data
+{
+  bfd_signed_vma  reloc_offset;
+  bfd_signed_vma  reloc_addend;
+  bfd_signed_vma  got_offset_value;
+
+  bfd_signed_vma  sym_value;
+  asection *     sym_section;
+
+  reloc_howto_type *howto;
+
+  asection *     input_section;
+
+  bfd_signed_vma  sdata_begin_symbol_vma;
+  bfd_boolean    sdata_begin_symbol_vma_set;
+  bfd_signed_vma  got_symbol_vma;
+
+  bfd_boolean    should_relocate;
+
+  const char *    symbol_name;
+};
+
+/* Should be included at this location due to static declarations
+ * defined before this point.  */
+#include "arc-got.h"
+
 #define arc_bfd_get_8(A,B,C) bfd_get_8(A,B)
 #define arc_bfd_get_16(A,B,C) bfd_get_16(A,B)
 #define arc_bfd_get_32(A,B,C) bfd_get_32(A,B)
@@ -345,7 +303,7 @@ arc_elf_howto (unsigned int r_type)
 struct arc_reloc_map
 {
   bfd_reloc_code_real_type  bfd_reloc_val;
-  unsigned char             elf_reloc_val;
+  unsigned char                    elf_reloc_val;
 };
 
 #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
@@ -626,8 +584,8 @@ arc_elf_object_p (bfd * abfd)
            mach = bfd_mach_arc_arcv2;
            break;
          default:
-           mach = (e_machine == EM_ARC_COMPACT) ?
-             bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
+           mach = (e_machine == EM_ARC_COMPACT)
+             bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
            break;
        }
     }
@@ -688,27 +646,6 @@ DO_NOTHING:
 
 #define BFD_DEBUG_PIC(...)
 
-struct arc_relocation_data
-{
-  bfd_signed_vma  reloc_offset;
-  bfd_signed_vma  reloc_addend;
-  bfd_signed_vma  got_offset_value;
-
-  bfd_signed_vma  sym_value;
-  asection *     sym_section;
-
-  reloc_howto_type *howto;
-
-  asection *     input_section;
-
-  bfd_signed_vma  sdata_begin_symbol_vma;
-  bfd_boolean    sdata_begin_symbol_vma_set;
-  bfd_signed_vma  got_symbol_vma;
-
-  bfd_boolean    should_relocate;
-
-  const char *    symbol_name;
-};
 
 static void
 debug_arc_reloc (struct arc_relocation_data reloc_data)
@@ -752,9 +689,9 @@ debug_arc_reloc (struct arc_relocation_data reloc_data)
               (unsigned int) reloc_data.input_section->output_offset,
               (unsigned int) reloc_data.input_section->output_section->vma);
       PR_DEBUG ( "  changed_address = 0x%08x\n",
-              (unsigned int) (reloc_data.input_section->output_section->vma +
-              reloc_data.input_section->output_offset +
-              reloc_data.reloc_offset));
+              (unsigned int) (reloc_data.input_section->output_section->vma
+              + reloc_data.input_section->output_offset
+              reloc_data.reloc_offset));
       PR_DEBUG ("  file: %s\n", reloc_data.input_section->owner->filename);
     }
   else
@@ -768,9 +705,9 @@ middle_endian_convert (bfd_vma insn, bfd_boolean do_it)
 {
   if (do_it)
     {
-      insn =
-       ((insn & 0xffff0000) >> 16) |
-       ((insn & 0xffff) << 16);
+      insn
+       = ((insn & 0xffff0000) >> 16)
+         | ((insn & 0xffff) << 16);
     }
   return insn;
 }
@@ -781,37 +718,37 @@ middle_endian_convert (bfd_vma insn, bfd_boolean do_it)
 
 static inline bfd_reloc_status_type
 arc_special_overflow_checks (const struct arc_relocation_data reloc_data,
-                             bfd_signed_vma relocation,
+                            bfd_signed_vma relocation,
                             struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   switch (reloc_data.howto->type)
     {
     case R_ARC_NPS_CMEM16:
       if (((relocation >> 16) & 0xffff) != NPS_CMEM_HIGH_VALUE)
-        {
-          if (reloc_data.reloc_addend == 0)
-            (*_bfd_error_handler)
-              (_("%B(%A+0x%lx): CMEM relocation to `%s' is invalid, "
-                 "16 MSB should be 0x%04x (value is 0x%lx)"),
-               reloc_data.input_section->owner,
-               reloc_data.input_section,
-               reloc_data.reloc_offset,
-               reloc_data.symbol_name,
-               NPS_CMEM_HIGH_VALUE,
-               (relocation));
-          else
-            (*_bfd_error_handler)
-              (_("%B(%A+0x%lx): CMEM relocation to `%s+0x%lx' is invalid, "
-                 "16 MSB should be 0x%04x (value is 0x%lx)"),
-               reloc_data.input_section->owner,
-               reloc_data.input_section,
-               reloc_data.reloc_offset,
-               reloc_data.symbol_name,
-               reloc_data.reloc_addend,
-               NPS_CMEM_HIGH_VALUE,
-               (relocation));
-          return bfd_reloc_overflow;
-        }
+       {
+         if (reloc_data.reloc_addend == 0)
+           (*_bfd_error_handler)
+             (_("%B(%A+0x%lx): CMEM relocation to `%s' is invalid, "
+                "16 MSB should be 0x%04x (value is 0x%lx)"),
+              reloc_data.input_section->owner,
+              reloc_data.input_section,
+              reloc_data.reloc_offset,
+              reloc_data.symbol_name,
+              NPS_CMEM_HIGH_VALUE,
+              (relocation));
+         else
+           (*_bfd_error_handler)
+             (_("%B(%A+0x%lx): CMEM relocation to `%s+0x%lx' is invalid, "
+                "16 MSB should be 0x%04x (value is 0x%lx)"),
+              reloc_data.input_section->owner,
+              reloc_data.input_section,
+              reloc_data.reloc_offset,
+              reloc_data.symbol_name,
+              reloc_data.reloc_addend,
+              NPS_CMEM_HIGH_VALUE,
+              (relocation));
+         return bfd_reloc_overflow;
+       }
       break;
 
     default:
@@ -973,10 +910,10 @@ arc_do_relocation (bfd_byte * contents,
   /* Check for relocation overflow.  */
   if (reloc_data.howto->complain_on_overflow != complain_overflow_dont)
     flag = bfd_check_overflow (reloc_data.howto->complain_on_overflow,
-                               reloc_data.howto->bitsize,
-                               reloc_data.howto->rightshift,
-                               bfd_arch_bits_per_address (abfd),
-                               relocation);
+                              reloc_data.howto->bitsize,
+                              reloc_data.howto->rightshift,
+                              bfd_arch_bits_per_address (abfd),
+                              relocation);
   else
     flag = arc_special_overflow_checks (reloc_data, relocation, info);
 
@@ -989,11 +926,11 @@ arc_do_relocation (bfd_byte * contents,
       DEBUG_ARC_RELOC (reloc_data);
 
       PR_DEBUG (
-                "Relocation value = signed -> %d, unsigned -> %u"
-                ", hex -> (0x%08x)\n",
-                (int) relocation,
-                (unsigned int) relocation,
-                (unsigned int) relocation);
+               "Relocation value = signed -> %d, unsigned -> %u"
+               ", hex -> (0x%08x)\n",
+               (int) relocation,
+               (unsigned int) relocation,
+               (unsigned int) relocation);
       return flag;
     }
 #undef  DEBUG_ARC_RELOC
@@ -1040,28 +977,6 @@ arc_do_relocation (bfd_byte * contents,
 
 #undef ARC_RELOC_HOWTO
 
-static struct got_entry **
-arc_get_local_got_ents (bfd * abfd)
-{
-  static struct got_entry **local_got_ents = NULL;
-
-  if (local_got_ents == NULL)
-    {
-      size_t      size;
-      Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
-
-      size = symtab_hdr->sh_info * sizeof (bfd_vma);
-      local_got_ents = (struct got_entry **)
-       bfd_alloc (abfd, sizeof(struct got_entry *) * size);
-      if (local_got_ents == NULL)
-       return FALSE;
-
-      memset (local_got_ents, 0, sizeof(struct got_entry *) * size);
-      elf_local_got_ents (abfd) = local_got_ents;
-    }
-
-  return local_got_ents;
-}
 
 /* Relocate an arc ELF section.
    Function : elf_arc_relocate_section
@@ -1089,7 +1004,6 @@ elf_arc_relocate_section (bfd *              output_bfd,
 {
   Elf_Internal_Shdr *     symtab_hdr;
   struct elf_link_hash_entry ** sym_hashes;
-  struct got_entry **     local_got_ents;
   Elf_Internal_Rela *     rel;
   Elf_Internal_Rela *     wrel;
   Elf_Internal_Rela *     relend;
@@ -1178,8 +1092,8 @@ elf_arc_relocate_section (bfd *              output_bfd,
        /* TODO: Verify this condition.  */
        {
          reloc_data.sdata_begin_symbol_vma =
-           (h2->root.u.def.value +
-            h2->root.u.def.section->output_section->vma);
+           (h2->root.u.def.value
+            h2->root.u.def.section->output_section->vma);
          reloc_data.sdata_begin_symbol_vma_set = TRUE;
        }
 
@@ -1249,11 +1163,6 @@ elf_arc_relocate_section (bfd *             output_bfd,
 
       if (r_symndx < symtab_hdr->sh_info) /* A local symbol.  */
        {
-         struct got_entry *entry;
-
-         local_got_ents = arc_get_local_got_ents (output_bfd);
-         entry = local_got_ents[r_symndx];
-
          reloc_data.sym_value = sym->st_value;
          reloc_data.sym_section = sec;
          reloc_data.symbol_name =
@@ -1277,88 +1186,6 @@ elf_arc_relocate_section (bfd *             output_bfd,
              reloc_data.reloc_addend = rel->r_addend;
            }
 
-         if ((is_reloc_for_GOT (howto)
-              || is_reloc_for_TLS (howto)) && entry != NULL)
-           {
-             if (is_reloc_for_TLS (howto))
-               while (entry->type == GOT_NORMAL && entry->next != NULL)
-                 entry = entry->next;
-
-             if (is_reloc_for_GOT (howto))
-               while (entry->type != GOT_NORMAL && entry->next != NULL)
-                 entry = entry->next;
-
-             if (entry->type == GOT_TLS_GD && entry->processed == FALSE)
-               {
-                 bfd_vma sym_vma = sym->st_value
-                                   + sec->output_section->vma
-                                   + sec->output_offset;
-
-                 /* Create dynamic relocation for local sym.  */
-                 ADD_RELA (output_bfd, got, entry->offset, 0,
-                           R_ARC_TLS_DTPMOD, 0);
-                 ADD_RELA (output_bfd, got, entry->offset+4, 0,
-                           R_ARC_TLS_DTPOFF, 0);
-
-                 bfd_vma sec_vma = sec->output_section->vma
-                                   + sec->output_offset;
-                 bfd_put_32 (output_bfd, sym_vma - sec_vma,
-                             htab->sgot->contents + entry->offset + 4);
-
-                 ARC_DEBUG ("arc_info: FIXED -> GOT_TLS_GD value "
-                        "= 0x%x @ 0x%x, for symbol %s\n",
-                        sym_vma - sec_vma,
-                        htab->sgot->contents + entry->offset + 4,
-                        "(local)");
-
-                 entry->processed = TRUE;
-               }
-             if (entry->type == GOT_TLS_IE && entry->processed == FALSE)
-               {
-                 bfd_vma sym_vma = sym->st_value
-                                   + sec->output_section->vma
-                                   + sec->output_offset;
-                 bfd_vma sec_vma = htab->tls_sec->output_section->vma;
-                 bfd_put_32 (output_bfd, sym_vma - sec_vma,
-                             htab->sgot->contents + entry->offset);
-                 /* TODO: Check if this type of relocs is the cause
-                    for all the ARC_NONE dynamic relocs.  */
-
-                 ARC_DEBUG ("arc_info: FIXED -> GOT_TLS_IE value = "
-                        "0x%x @ 0x%x, for symbol %s\n",
-                        sym_vma - sec_vma,
-                        htab->sgot->contents + entry->offset,
-                        "(local)");
-
-                 entry->processed = TRUE;
-               }
-             if (entry->type == GOT_NORMAL && entry->processed == FALSE)
-               {
-                 bfd_vma sec_vma = reloc_data.sym_section->output_section->vma
-                                   + reloc_data.sym_section->output_offset;
-
-                 bfd_put_32 (output_bfd, reloc_data.sym_value + sec_vma,
-                             htab->sgot->contents + entry->offset);
-
-                 ARC_DEBUG ("arc_info: PATCHED: 0x%08x @ 0x%08x for "
-                        "sym %s in got offset 0x%x\n",
-                        reloc_data.sym_value + sec_vma,
-                        htab->sgot->output_section->vma
-                        + htab->sgot->output_offset + entry->offset,
-                        "(local)",
-                        entry->offset);
-                 entry->processed = TRUE;
-               }
-
-             reloc_data.got_offset_value = entry->offset;
-             ARC_DEBUG ("arc_info: GOT_ENTRY = %d, offset = 0x%x, "
-                    "vma = 0x%x for symbol %s\n",
-                    entry->type, entry->offset,
-                    htab->sgot->output_section->vma
-                    + htab->sgot->output_offset + entry->offset,
-                    "(local)");
-           }
-
          BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto));
          if (htab->sgot != NULL)
            reloc_data.got_symbol_vma = htab->sgot->output_section->vma
@@ -1459,118 +1286,44 @@ elf_arc_relocate_section (bfd *                   output_bfd,
                   rel->r_offset, TRUE);
            }
 
-         if (h->got.glist != NULL)
-           {
-             struct got_entry *entry = h->got.glist;
-
-             if (is_reloc_for_GOT (howto) || is_reloc_for_TLS (howto))
-               {
-                 if (! elf_hash_table (info)->dynamic_sections_created
-                     || (bfd_link_pic (info)
-                         && SYMBOL_REFERENCES_LOCAL (info, h)))
-                   {
-                     reloc_data.sym_value = h->root.u.def.value;
-                     reloc_data.sym_section = h->root.u.def.section;
-
-                     if (is_reloc_for_TLS (howto))
-                       while (entry->type == GOT_NORMAL && entry->next != NULL)
-                         entry = entry->next;
-
-                     if (entry->processed == FALSE
-                         && (entry->type == GOT_TLS_GD
-                             || entry->type == GOT_TLS_IE))
-                       {
-                         bfd_vma sym_value = h->root.u.def.value
-                           + h->root.u.def.section->output_section->vma
-                           + h->root.u.def.section->output_offset;
-
-                         bfd_vma sec_vma =
-                           elf_hash_table (info)->tls_sec->output_section->vma;
-
-                         bfd_put_32 (output_bfd,
-                                     sym_value - sec_vma,
-                                     htab->sgot->contents + entry->offset
-                                     + (entry->existing_entries == TLS_GOT_MOD_AND_OFF ? 4 : 0));
-
-                         ARC_DEBUG ("arc_info: FIXED -> %s value = 0x%x "
-                                    "@ 0x%x, for symbol %s\n",
-                                    (entry->type == GOT_TLS_GD ? "GOT_TLS_GD" :
-                                     "GOT_TLS_IE"),
-                                    sym_value - sec_vma,
-                                    htab->sgot->contents + entry->offset
-                                    + (entry->existing_entries == TLS_GOT_MOD_AND_OFF ? 4 : 0),
-                                    h->root.root.string);
-
-                         entry->processed = TRUE;
-                       }
-
-                     if (entry->type == GOT_TLS_IE && entry->processed == FALSE)
-                       {
-                         bfd_vma sec_vma = htab->tls_sec->output_section->vma;
-                         bfd_put_32 (output_bfd,
-                                     reloc_data.sym_value - sec_vma,
-                                     htab->sgot->contents + entry->offset);
-                       }
-
-                     if (entry->type == GOT_NORMAL && entry->processed == FALSE)
-                       {
-                         bfd_vma sec_vma =
-                           reloc_data.sym_section->output_section->vma
-                           + reloc_data.sym_section->output_offset;
-
-                         if (h->root.type != bfd_link_hash_undefweak)
-                           {
-                             bfd_put_32 (output_bfd,
-                                         reloc_data.sym_value + sec_vma,
-                                         htab->sgot->contents + entry->offset);
-
-                             ARC_DEBUG ("arc_info: PATCHED: 0x%08x "
-                                        "@ 0x%08x for sym %s in got offset 0x%x\n",
-                                        reloc_data.sym_value + sec_vma,
-                                        htab->sgot->output_section->vma
-                                        + htab->sgot->output_offset + entry->offset,
-                                        h->root.root.string,
-                                        entry->offset);
-                           }
-                         else
-                           {
-                             ARC_DEBUG ("arc_info: PATCHED: NOT_PATCHED "
-                                        "@ 0x%08x for sym %s in got offset 0x%x "
-                                        "(is undefweak)\n",
-                                        htab->sgot->output_section->vma
-                                        + htab->sgot->output_offset + entry->offset,
-                                        h->root.root.string,
-                                        entry->offset);
-                           }
-
-                         entry->processed = TRUE;
-                       }
-                   }
-               }
-
-             reloc_data.got_offset_value = entry->offset;
-
-             ARC_DEBUG ("arc_info: GOT_ENTRY = %d, offset = 0x%x, "
-                        "vma = 0x%x for symbol %s\n",
-                        entry->type, entry->offset,
-                        htab->sgot->output_section->vma
-                        + htab->sgot->output_offset + entry->offset,
-                        h->root.root.string);
-           }
-
          BFD_ASSERT (htab->sgot != NULL || !is_reloc_for_GOT (howto));
          if (htab->sgot != NULL)
            reloc_data.got_symbol_vma = htab->sgot->output_section->vma
                                        + htab->sgot->output_offset;
        }
 
+      if ((is_reloc_for_GOT (howto)
+          || is_reloc_for_TLS (howto)))
+       {
+         struct got_entry **list
+           = get_got_entry_list_for_symbol (output_bfd, r_symndx, h);
+
+         reloc_data.got_offset_value
+           = relocate_fix_got_relocs_for_got_info (list,
+                                                   tls_type_for_reloc (howto),
+                                                   info,
+                                                   output_bfd,
+                                                   r_symndx,
+                                                   local_syms,
+                                                   local_sections,
+                                                   h,
+                                                   &reloc_data);
+
+         if (h == NULL)
+           {
+             create_got_dynrelocs_for_single_entry (
+                 got_entry_for_type (list,
+                               arc_got_entry_type_for_reloc (howto)),
+                 output_bfd, info, NULL);
+           }
+       }
       switch (r_type)
        {
          case R_ARC_32:
          case R_ARC_32_ME:
          case R_ARC_PC32:
          case R_ARC_32_PCREL:
-           if ((bfd_link_pic (info) || bfd_link_pie (info))
+           if ((bfd_link_pic (info))// || bfd_link_pie (info))
                && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL)
                    || (h != NULL
                        && h->dynindx != -1
@@ -1666,7 +1419,7 @@ elf_arc_relocate_section (bfd *              output_bfd,
       DEBUG_ARC_RELOC (reloc_data);
 
       /* Make sure we have with a dynamic linker.  In case of GOT and PLT
-         the sym_section should point to .got or .plt respectively.  */
+        the sym_section should point to .got or .plt respectively.  */
       if ((is_reloc_for_GOT (howto) || is_reloc_for_PLT (howto))
          && reloc_data.sym_section == NULL)
        {
@@ -1735,38 +1488,18 @@ arc_create_dynamic_sections (bfd * abfd, struct bfd_link_info *info)
   return ds;
 }
 
-#define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H)       \
-  htab->s##SECNAME->size;                                              \
-  {                                                                    \
-    if (COND_FOR_RELOC)                                                        \
-      {                                                                        \
-       htab->srel##SECNAME->size += sizeof (Elf32_External_Rela);      \
-         ARC_DEBUG ("arc_info: Added reloc space in "                  \
-                    #SECNAME " section at " __FILE__                   \
-                    ":%d for symbol\n",                                \
-                    __LINE__, name_for_global_symbol (H));             \
-      }                                                                        \
-    if (H)                                                             \
-      if (h->dynindx == -1 && !h->forced_local)                                \
-       if (! bfd_elf_link_record_dynamic_symbol (info, H))             \
-         return FALSE;                                                 \
-     htab->s##SECNAME->size += 4;                      \
-   }
-
 static bfd_boolean
-elf_arc_check_relocs (bfd *                     abfd,
+elf_arc_check_relocs (bfd *                     abfd,
                      struct bfd_link_info *     info,
                      asection *                 sec,
                      const Elf_Internal_Rela *  relocs)
 {
   Elf_Internal_Shdr *          symtab_hdr;
   struct elf_link_hash_entry **        sym_hashes;
-  struct got_entry **          local_got_ents;
   const Elf_Internal_Rela *    rel;
   const Elf_Internal_Rela *    rel_end;
   bfd *                                dynobj;
   asection *                   sreloc = NULL;
-  struct elf_link_hash_table *  htab = elf_hash_table (info);
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -1774,7 +1507,6 @@ elf_arc_check_relocs (bfd *                        abfd,
   dynobj = (elf_hash_table (info))->dynobj;
   symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
   sym_hashes = elf_sym_hashes (abfd);
-  local_got_ents = arc_get_local_got_ents (abfd);
 
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
@@ -1849,7 +1581,7 @@ elf_arc_check_relocs (bfd *                        abfd,
            /* FALLTHROUGH */
          case R_ARC_PC32:
          case R_ARC_32_PCREL:
-           if ((bfd_link_pic (info) || bfd_link_pie (info))
+           if ((bfd_link_pic (info))// || bfd_link_pie (info))
                && ((r_type != R_ARC_PC32 && r_type != R_ARC_32_PCREL)
                    || (h != NULL
                        && h->dynindx != -1
@@ -1880,75 +1612,15 @@ elf_arc_check_relocs (bfd *                      abfd,
            h->needs_plt = 1;
        }
 
-      if (is_reloc_for_GOT (howto) == TRUE)
-       {
-         if (h == NULL)
-           {
-             /* Local symbol.  */
-             if (local_got_ents[r_symndx] == NULL)
-               {
-                 bfd_vma offset =
-                   ADD_SYMBOL_REF_SEC_AND_RELOC (got,
-                                                 bfd_link_pic (info),
-                                                 NULL);
-                 new_got_entry_to_list (&(local_got_ents[r_symndx]),
-                                        GOT_NORMAL, offset, TLS_GOT_NONE);
-               }
-           }
-         else
-           {
-             /* Global symbol.  */
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             if (h->got.glist == NULL)
-               {
-                 bfd_vma offset =
-                   ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
-                 new_got_entry_to_list (&h->got.glist,
-                                        GOT_NORMAL, offset, TLS_GOT_NONE);
-               }
-           }
-       }
-
-      if (is_reloc_for_TLS (howto) == TRUE)
+      /* Add info to the symbol got_entry_list.  */
+      if (is_reloc_for_GOT (howto) == TRUE
+         || is_reloc_for_TLS (howto) == TRUE)
        {
-         enum tls_type_e type = GOT_UNKNOWN;
-
-         switch (r_type)
-           {
-             case R_ARC_TLS_GD_GOT:
-               type = GOT_TLS_GD;
-               break;
-             case R_ARC_TLS_IE_GOT:
-               type = GOT_TLS_IE;
-               break;
-             default:
-               break;
-           }
-
-         struct got_entry **list = NULL;
-         if (h != NULL)
-           list = &(h->got.glist);
-         else
-           list = &(local_got_ents[r_symndx]);
-
-         if (type != GOT_UNKNOWN && !symbol_has_entry_of_type (*list, type))
-           {
-             enum tls_got_entries entries = TLS_GOT_NONE;
-             bfd_vma offset =
-               ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
-
-             if (type == GOT_TLS_GD)
-               {
-                 bfd_vma ATTRIBUTE_UNUSED notneeded =
-                   ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
-                 entries = TLS_GOT_MOD_AND_OFF;
-               }
-
-             if (entries == TLS_GOT_NONE)
-               entries = TLS_GOT_OFF;
-
-             new_got_entry_to_list (list, type, offset, entries);
-           }
+         arc_fill_got_info_for_reloc (
+                 arc_got_entry_type_for_reloc (howto),
+                 get_got_entry_list_for_symbol (abfd, r_symndx, h),
+                 info,
+                 h);
        }
     }
 
@@ -2026,9 +1698,9 @@ plt_do_relocs_for_symbol (bfd *abfd,
       switch (SYM_ONLY (reloc->symbol))
        {
          case SGOT:
-               relocation =
-                   htab->sgotplt->output_section->vma +
-                   htab->sgotplt->output_offset + symbol_got_offset;
+               relocation
+                 = htab->sgotplt->output_section->vma
+                   htab->sgotplt->output_offset + symbol_got_offset;
                break;
        }
       relocation += reloc->addend;
@@ -2048,9 +1720,9 @@ plt_do_relocs_for_symbol (bfd *abfd,
         section of which is applying the relocation. */
       if (IS_MIDDLE_ENDIAN (reloc->symbol) && !bfd_big_endian (abfd))
        {
-         relocation =
-             ((relocation & 0xffff0000) >> 16) |
-             ((relocation & 0xffff) << 16);
+         relocation
+           = ((relocation & 0xffff0000) >> 16)
+             ((relocation & 0xffff) << 16);
        }
 
       switch (reloc->size)
@@ -2193,7 +1865,7 @@ elf_arc_adjust_dynamic_symbol (struct bfd_link_info *info,
        {
          bfd_vma loc = add_symbol_to_plt (info);
 
-         if (!bfd_link_pic (info) && !h->def_regular)
+         if (bfd_link_executable (info) && !h->def_regular)
            {
              h->root.u.def.section = htab->splt;
              h->root.u.def.value = loc;
@@ -2302,84 +1974,15 @@ elf_arc_finish_dynamic_symbol (bfd * output_bfd,
        }
     }
 
-  if (h->got.glist != NULL)
-    {
-      struct got_entry *list = h->got.glist;
 
-      /* Traverse the list of got entries for this symbol.  */
-      while (list)
-       {
-         bfd_vma got_offset = h->got.glist->offset;
-
-         if (list->type == GOT_NORMAL
-             && list->created_dyn_relocation == FALSE)
-           {
-             if (bfd_link_pic (info)
-                 && (info->symbolic || h->dynindx == -1)
-                 && h->def_regular)
-               {
-                 ADD_RELA (output_bfd, got, got_offset, 0, R_ARC_RELATIVE, 0);
-               }
-             /* Do not fully understand the side effects of this condition.
-                The relocation space might still being reserved.  Perhaps
-                I should clear its value.  */
-             else if (h->dynindx != -1)
-               {
-                 ADD_RELA (output_bfd, got, got_offset, h->dynindx,
-                         R_ARC_GLOB_DAT, 0);
-               }
-             list->created_dyn_relocation = TRUE;
-           }
-         else if (list->existing_entries != TLS_GOT_NONE)
-           {
-             struct elf_link_hash_table *htab = elf_hash_table (info);
-             enum tls_got_entries e = list->existing_entries;
-
-             BFD_ASSERT (list->type != GOT_TLS_GD
-                         || list->existing_entries == TLS_GOT_MOD_AND_OFF);
-
-             bfd_vma dynindx = h->dynindx == -1 ? 0 : h->dynindx;
-             if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_MOD)
-               {
-                 ADD_RELA (output_bfd, got, got_offset, dynindx,
-                           R_ARC_TLS_DTPMOD, 0);
-                 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
-GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
-                            list->type,
-                            got_offset,
-                            htab->sgot->output_section->vma
-                            + htab->sgot->output_offset + got_offset,
-                            dynindx, 0);
-               }
-             if (e == TLS_GOT_MOD_AND_OFF || e == TLS_GOT_OFF)
-               {
-                 bfd_vma addend = 0;
-                 if (list->type == GOT_TLS_IE)
-                   addend = bfd_get_32 (output_bfd,
-                                        htab->sgot->contents + got_offset);
-
-                 ADD_RELA (output_bfd, got,
-                           got_offset + (e == TLS_GOT_MOD_AND_OFF ? 4 : 0),
-                           dynindx,
-                           (list->type == GOT_TLS_IE ?
-                            R_ARC_TLS_TPOFF : R_ARC_TLS_DTPOFF),
-                           addend);
-
-                 ARC_DEBUG ("arc_info: TLS_DYNRELOC: type = %d, \
-GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
-                            list->type,
-                            got_offset,
-                            htab->sgot->output_section->vma
-                            + htab->sgot->output_offset + got_offset,
-                            dynindx, addend);
-               }
-           }
-
-         list = list->next;
-       }
-
-      h->got.glist = NULL;
-    }
+  /* This function traverses list of GOT entries and
+     create respective dynamic relocs.  */
+  /* TODO: Make function to get list and not access the list directly.  */
+  /* TODO: Move function to relocate_section create this relocs eagerly.  */
+  create_got_dynrelocs_for_got_info (&h->got.glist,
+                                    output_bfd,
+                                    info,
+                                    h);
 
   if (h->needs_copy)
     {
@@ -2387,8 +1990,8 @@ GOT_OFFSET = 0x%x, GOT_VMA = 0x%x, INDEX = %d, ADDEND = 0x%x\n",
                            + h->root.u.def.section->output_section->vma
                            + h->root.u.def.section->output_offset);
 
-      asection *srelbss =
-       bfd_get_section_by_name (h->root.u.def.section->owner,
+      asection *srelbss
+       bfd_get_section_by_name (h->root.u.def.section->owner,
                                 ".rela.bss");
 
       bfd_byte * loc = srelbss->contents
@@ -2444,8 +2047,8 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd,
       Elf32_External_Dyn *dyncon, *dynconend;
 
       dyncon = (Elf32_External_Dyn *) ds.sdyn->contents;
-      dynconend =
-       (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size);
+      dynconend
+       (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size);
       for (; dyncon < dynconend; dyncon++)
        {
          Elf_Internal_Dyn internal_dyn;
@@ -2483,8 +2086,8 @@ elf_arc_finish_dynamic_sections (bfd * output_bfd,
              if (asec_ptr->output_section != NULL)
                {
                  internal_dyn.d_un.d_val +=
-                   (asec_ptr->output_section->vma +
-                    asec_ptr->output_offset);
+                   (asec_ptr->output_section->vma
+                    asec_ptr->output_offset);
                }
              else
                {
@@ -2834,7 +2437,7 @@ elf_arc_add_symbol_hook (bfd * abfd,
 
 #define elf_backend_finish_dynamic_sections  elf_arc_finish_dynamic_sections
 #define elf_backend_size_dynamic_sections    elf_arc_size_dynamic_sections
-#define elf_backend_add_symbol_hook          elf_arc_add_symbol_hook
+#define elf_backend_add_symbol_hook         elf_arc_add_symbol_hook
 
 #define elf_backend_can_gc_sections    1
 #define elf_backend_want_got_plt       1
index faa1389..a995056 100644 (file)
@@ -454,7 +454,7 @@ ARC_RELOC_HOWTO(ARC_TLS_DTPOFF, 67, \
                 32, \
                 replace_word32, \
                 dont, \
-                ( ME ( ( S - TLS_REL ) ) ))
+                ( ME ( S - SECTSTART ) + A ))
 
 ARC_RELOC_HOWTO(ARC_TLS_DTPOFF_S9, 73, \
                 2, \