Thread-Local Storage: ARC binutils patch

本文分享了2008年为ARC binutils添加Thread-LocalStorage (TLS)支持的补丁,详细展示了针对bfd-in2.h和config.bfd等文件的修改内容,包括新增的TLS重定位类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下是我2008年做的、使ARC binutils支持Thread-Local Storage的补丁,供有兴趣的人员参考。

--------------------

diff -ruN binutils-2.17.orig/bfd/bfd-in2.h binutils-2.17/bfd/bfd-in2.h
--- binutils-2.17.orig/bfd/bfd-in2.h    2008-10-11 00:36:34.000000000 +0800
+++ binutils-2.17/bfd/bfd-in2.h    2010-04-02 16:17:43.000000000 +0800
@@ -3291,6 +3291,30 @@
 /* small data reloc 9  */
   BFD_RELOC_ARC_SDA32_ME,
 
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_GD32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_LD32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_LDO32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_IE32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_LE32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_DTPMOD32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_DTPOFF32,
+
+/* arc tls reloc, joshua zhan 2008/08/09  */
+  BFD_RELOC_ARC_TLS_TPOFF32,
+
 
 /* ADI Blackfin 16 bit immediate absolute reloc.  */
   BFD_RELOC_BFIN_16_IMM,
diff -ruN binutils-2.17.orig/bfd/config.bfd binutils-2.17/bfd/config.bfd
--- binutils-2.17.orig/bfd/config.bfd    2008-10-11 00:36:33.000000000 +0800
+++ binutils-2.17/bfd/config.bfd    2008-12-16 15:13:51.000000000 +0800
@@ -199,7 +199,7 @@
   am33_2.0-*-linux*)
     targ_defvec=bfd_elf32_am33lin_vec
     ;;
-  arc-*-elf* | arc-*-linux-uclibc*)
+  arc-*-elf* | arc-*-linux-uclibc* | arc-*-linux*)
     targ_defvec=bfd_elf32_littlearc_vec
     targ_selvecs=bfd_elf32_bigarc_vec
     ;;
 
 cat >>confdefs.h <<_ACEOF
diff -ruN binutils-2.17.orig/bfd/elf32-arc.c binutils-2.17/bfd/elf32-arc.c
--- binutils-2.17.orig/bfd/elf32-arc.c    2008-11-12 21:35:30.000000000 +0800
+++ binutils-2.17/bfd/elf32-arc.c    2010-04-02 16:18:53.000000000 +0800
@@ -89,9 +89,13 @@
 static reloc_howto_type * arc_elf_calculate_howto_index
   (enum elf_arc_reloc_type r_type);
 
+/* joshua zhan 2008/09/11 */
+static int elf_arc_tls_transition(struct bfd_link_info *, int, int);
+static bfd_vma dtpoff_base(struct bfd_link_info *);
+static bfd_vma tpoff(struct bfd_link_info *, bfd_vma);
 
-#define INIT_SYM_STRING "_init"
-#define FINI_SYM_STRING "_fini"
+#define INIT_SYM_STRING "init"
+#define FINI_SYM_STRING "fini"
 
 /* The default symbols representing the init and fini dyn values */
 char * init_str = INIT_SYM_STRING;
@@ -126,13 +130,52 @@
 
   /* Number of PC relative relocs copied for this symbol.  */
   struct elf_ARC_pcrel_relocs_copied *pcrel_relocs_copied;
+
+  /* joshua zhan 2008/09/11 */
+  enum {
+    GOT_UNKNOWN = 0, GOT_NORMAL/* not used yet */, GOT_TLS_GD, GOT_TLS_IE
+  } tls_type;
 };
 
+/* joshua zhan 2008/09/25 start */
+
+#define  elf_arc_hash_entry(ent) ((struct elf_ARC_link_hash_entry *)(ent))
+
+struct elf_arc_obj_tdata
+{
+  struct elf_obj_tdata root;
+
+  /* tls_type for each local got entry.  */
+  char *local_got_tls_type;
+};
+
+#define elf_arc_tdata(abfd) /
+  ((struct elf_arc_obj_tdata *) (abfd)->tdata.any)
+
+#define elf_arc_local_got_tls_type(abfd) /
+  (elf_arc_tdata (abfd)->local_got_tls_type)
+
+/* joshua zhan 2008/09/25 end */
+
 /* ARC ELF linker hash table.  */
 
 struct elf_ARC_link_hash_table
 {
   struct elf_link_hash_table root;
+
+  /* joshua zhan 2008/09/25 */
+  /* Short-cuts to get to dynamic linker sections.  */
+  asection *sgot;
+  asection *srelgot;
+  asection *splt;
+  asection *srelplt;
+
+  /* Data for R_ARC_TLS_LD32 relocations.  */
+  union
+    {
+      bfd_signed_vma refcount;
+      bfd_vma offset;
+    } tls_ldm_got;
 };
 
 /* Declare this now that the above structures are defined.  */
@@ -179,6 +222,8 @@
   if (ret != (struct elf_ARC_link_hash_entry *) NULL)
     {
       ret->pcrel_relocs_copied = NULL;
+      /* joshua zhan 2008/10/01 */
+      ret->tls_type = GOT_UNKNOWN;
     }
 
   return (struct bfd_hash_entry *) ret;
@@ -204,9 +249,73 @@
       return NULL;
     }
 
+  /* joshua zhan 2008/09/25 */
+  ret->sgot = NULL;
+  ret->srelgot = NULL;
+  ret->splt = NULL;
+  ret->srelplt = NULL;
+  ret->tls_ldm_got.offset = 0;
+
   return &ret->root.root;
 }
 
+/* create_got_section() & elf_arc_create_dynamic_sections copied from
+  elf32-arm.c, joshua zhan 2008/10/01 */
+
+/* Create .got, .gotplt, and .rel(a).got sections in DYNOBJ, and set up
+   shortcuts to them in our hash table.  */
+
+static bfd_boolean
+create_got_section (bfd *dynobj, struct bfd_link_info *info)
+{
+  struct elf_ARC_link_hash_table *htab;
+
+  if (! _bfd_elf_create_got_section (dynobj, info))
+    return FALSE;
+
+  htab = elf_ARC_hash_table (info);
+  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
+  if (!htab->sgot)
+    abort ();
+
+  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
+                           (SEC_ALLOC | SEC_LOAD
+                        | SEC_HAS_CONTENTS
+                        | SEC_IN_MEMORY
+                        | SEC_LINKER_CREATED
+                        | SEC_READONLY));
+  if (htab->srelgot == NULL
+      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
+    return FALSE;
+  return TRUE;
+}
+
+/* Create .plt, .rel(a).plt, .got, .got.plt, .rel(a).got, .dynbss, and
+   .rel(a).bss sections in DYNOBJ, and set up shortcuts to them in our
+   hash table.  */
+
+static bfd_boolean
+elf_arc_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
+{
+  struct elf_ARC_link_hash_table *htab;
+
+  htab = elf_ARC_hash_table (info);
+  if (!htab->sgot && !create_got_section (dynobj, info))
+    return FALSE;
+
+  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
+    return FALSE;
+
+  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
+  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+
+  if (!htab->splt
+      || !htab->srelplt)
+    abort ();
+
+  return TRUE;
+}
+
 /* This function is called via elf_ARC_link_hash_traverse if we are
    creating a shared object with -Bsymbolic.  It discards the space
    allocated to copy PC relative relocs against symbols which are
@@ -400,6 +509,29 @@
 
   ARC_RELA_HOWTO (R_ARC_GOTPC, 0, 2, 32, FALSE,0 , arcompact_elf_me_reloc,
                   "R_ARC_GOTPC",-1),
+
+  /* joshua zhan 2008/08/20 */
+  /* bug? R_ARC_GOT32 is defined but not in this table. we leave it as a hole
+  */
+  #define R_ARC_hole2_base R_ARC_GOTPC
+  #define R_ARC_reloc_hole2_gap (1)
+
+  ARC_RELA_HOWTO (R_ARC_TLS_GD32, 0, 2, 32, FALSE, 0, arcompact_elf_me_reloc,
+                  "R_ARC_TLS_GD32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_LD32, 0, 2, 32, FALSE, 0, arcompact_elf_me_reloc,
+                  "R_ARC_TLS_LD32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_LDO32, 0, 2, 32, FALSE, 0, arcompact_elf_me_reloc,
+                  "R_ARC_TLS_LDO32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_IE32, 0, 2, 32, FALSE, 0, arcompact_elf_me_reloc,
+                  "R_ARC_TLS_IE32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_LE32, 0, 2, 32, FALSE, 0, arcompact_elf_me_reloc,
+                  "R_ARC_TLS_LE32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_DTPMOD32, 0, 2, 32, FALSE, 0, bfd_elf_generic_reloc,
+                  "R_ARC_TLS_DTPMOD32", - 1),
+  ARC_RELA_HOWTO (R_ARC_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, bfd_elf_generic_reloc,
+                  "R_ARC_TLS_DTPOFF32", -1),
+  ARC_RELA_HOWTO (R_ARC_TLS_TPOFF32, 0, 2, 32, FALSE, 0, bfd_elf_generic_reloc,
+                  "R_ARC_TLS_TPOFF32", -1),
 };
 
 /*Indicates whether the value contained in
@@ -481,6 +613,16 @@
   0, //  R_ARC_GOTOFF
   0, //  R_ARC_GOTPC             0x3a
   0, //  R_ARC_GOT32             0x3b
+
+  /* joshua zhan 2008/08/20 */
+  0, // R_ARC_TLS_GD32           0x3c
+  0, // R_ARC_TLS_LD32           0x3d
+  0, // R_ARC_TLS_LDO32          0x3e
+  0, // R_ARC_TLS_IE32           0x3f
+  0, // R_ARC_TLS_LE32           0x40
+  0, // R_ARC_TLS_DTPMOD32       0x41
+  0, // R_ARC_TLS_DTPOFF32       0x42
+  0, // R_ARC_TLS_TPOFF32        0x43
 };
 
 
@@ -540,7 +682,17 @@
   { BFD_RELOC_ARC_SDA_LDST2, R_ARC_SDA_LDST2 },
   { BFD_RELOC_ARC_SDA16_LD, R_ARC_SDA16_LD },
   { BFD_RELOC_ARC_SDA16_LD1, R_ARC_SDA16_LD1 },
-  { BFD_RELOC_ARC_SDA16_LD2, R_ARC_SDA16_LD2 }
+  { BFD_RELOC_ARC_SDA16_LD2, R_ARC_SDA16_LD2 },
+
+  /* joshua zhan 2008/08/20 */
+  { BFD_RELOC_ARC_TLS_GD32, R_ARC_TLS_GD32 },
+  { BFD_RELOC_ARC_TLS_LD32, R_ARC_TLS_LD32 },
+  { BFD_RELOC_ARC_TLS_LDO32, R_ARC_TLS_LDO32 },
+  { BFD_RELOC_ARC_TLS_IE32, R_ARC_TLS_IE32 },
+  { BFD_RELOC_ARC_TLS_LE32, R_ARC_TLS_LE32 },
+  { BFD_RELOC_ARC_TLS_DTPMOD32, R_ARC_TLS_DTPMOD32 },
+  { BFD_RELOC_ARC_TLS_DTPOFF32, R_ARC_TLS_DTPOFF32 },
+  { BFD_RELOC_ARC_TLS_TPOFF32, R_ARC_TLS_TPOFF32 },
 };
 
 static reloc_howto_type *
@@ -587,10 +739,13 @@
   BFD_ASSERT ((r_type < (unsigned int) R_ARC_hole_base)
           || (r_type
           >= (unsigned int) R_ARC_hole_base + R_ARC_reloc_hole_gap));
-  if (r_type > R_ARC_hole_base)
+
+  /* joshua zhan 2008/09/29 */
+  if (r_type > R_ARC_hole2_base)
+    r_type -= R_ARC_reloc_hole2_gap + R_ARC_reloc_hole_gap;
+  else if (r_type > R_ARC_hole_base)
     r_type -= R_ARC_reloc_hole_gap;
   return &elf_arc_howto_table[r_type];
-
 }
 /* Set the howto pointer for an ARC ELF reloc.  */
 
@@ -907,6 +1062,21 @@
   case R_ARC_32_ME:
       insn = sym_value;
       break;
+
+  /* joshua zhan 2008/09/21 */
+  case R_ARC_TLS_GD32:
+  case R_ARC_TLS_LD32:
+  case R_ARC_TLS_LDO32:
+  case R_ARC_TLS_IE32:
+  case R_ARC_TLS_LE32:
+/* for static build?
+  case R_ARC_TLS_DTPMOD32:
+  case R_ARC_TLS_DTPOFF32:
+  case R_ARC_TLS_TPOFF32:
+*/
+      insn = sym_value;
+    break;
+
   default:
     return bfd_reloc_notsupported;
     break;
@@ -954,7 +1124,12 @@
 
 /* This will be overridden by the interpreter specified in
    the linker specs */
-#define ELF_DYNAMIC_INTERPRETER  "/sbin/ld-uClibc.so"
+/* joshua zhan 2008/09/11 */
+/* #define ELF_DYNAMIC_INTERPRETER  "/sbin/ld-uClibc.so" */
+#define ELF_DYNAMIC_INTERPRETER "/lib/libc.so.1"
+
+/* 2008/11/22 */
+#define ELIMINATE_COPY_RELOCS 1
 
 /* size of one plt entry */
 #define PLT_ENTRY_SIZE  12
@@ -1276,6 +1451,7 @@
   case R_ARC_GOTPC32:
   case R_ARC_32_ME:
       insn = value;
+      /* missing break here? joshua zhan 2008/09/27 */
      
   case R_ARC_8:
   case R_ARC_16:
@@ -1315,6 +1491,22 @@
     insn |= ((value >> 2) & 0x1ff) <<16;
     break;
 
+  /* joshua zhan 2008/09/11 */
+  case R_ARC_TLS_GD32:
+  case R_ARC_TLS_LD32:
+  case R_ARC_TLS_LDO32:
+  case R_ARC_TLS_IE32:
+  case R_ARC_TLS_LE32:
+  /* FIXME: R_ARC_TLS_DTPMOD32 & R_ARC_TLS_DTPOFF32, to be fixed up by the dynamic resolver?
+    But static build is different
+  */
+ /* case R_ARC_TLS_DTPMOD32:
+  case R_ARC_TLS_DTPOFF32:
+  case R_ARC_TLS_TPOFF32:
+*/
+    insn = value;
+    break;
+
   default:
     /* FIXME:: This should go away once the HOWTO Array
        is used for this purpose.
@@ -1326,6 +1518,97 @@
   return insn;
 }
 
+/* joshua zhan 2008/11/22 */
+/* Copy the extra info we tack onto an elf_link_hash_entry.  */
+
+static void
+elf_arc_copy_indirect_symbol (struct bfd_link_info *info,
+                   struct elf_link_hash_entry *dir,
+                   struct elf_link_hash_entry *ind)
+{
+  struct elf_ARC_link_hash_entry *edir, *eind;
+
+  edir = (struct elf_ARC_link_hash_entry *) dir;
+  eind = (struct elf_ARC_link_hash_entry *) ind;
+
+  if (eind->pcrel_relocs_copied != NULL)
+    {
+      if (edir->pcrel_relocs_copied != NULL)
+    {
+      struct elf_ARC_pcrel_relocs_copied **pp;
+      struct elf_ARC_pcrel_relocs_copied *p;
+
+      /* Add reloc counts against the indirect sym to the direct sym
+         list.  Merge any entries against the same section.  */
+      for (pp = &eind->pcrel_relocs_copied; (p = *pp) != NULL; )
+        {
+          struct elf_ARC_pcrel_relocs_copied *q;
+
+          for (q = edir->pcrel_relocs_copied; q != NULL; q = q->next)
+        if (q->section == p->section)
+          {
+            /*q->pc_count += p->pc_count;*/
+            q->count += p->count;
+            *pp = p->next;
+            break;
+          }
+          if (q == NULL)
+        pp = &p->next;
+        }
+      *pp = edir->pcrel_relocs_copied;
+    }
+
+      edir->pcrel_relocs_copied = eind->pcrel_relocs_copied;
+      eind->pcrel_relocs_copied = NULL;
+    }
+
+  if (ind->root.type == bfd_link_hash_indirect
+      && dir->got.refcount <= 0)
+    {
+      edir->tls_type = eind->tls_type;
+      eind->tls_type = GOT_UNKNOWN;
+    }
+
+  if (ELIMINATE_COPY_RELOCS
+      && ind->root.type != bfd_link_hash_indirect
+      && dir->dynamic_adjusted)
+    {
+      /* If called to transfer flags for a weakdef during processing
+     of elf_adjust_dynamic_symbol, don't copy non_got_ref.
+     We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
+      dir->ref_dynamic |= ind->ref_dynamic;
+      dir->ref_regular |= ind->ref_regular;
+      dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
+      dir->needs_plt |= ind->needs_plt;
+      dir->pointer_equality_needed |= ind->pointer_equality_needed;
+    }
+  else
+    _bfd_elf_link_hash_copy_indirect (info, dir, ind);
+}
+
+/* joshua zhan 2008/09/25*/
+static int
+elf_arc_tls_transition (struct bfd_link_info *info, int r_type, int is_local)
+{
+  if (info->shared)
+    return r_type;
+
+/* no linker optimization for the time being
+  switch (r_type)
+    {
+    case R_ARC_TLS_GD32:
+    case R_ARC_TLS_IE32:
+      if (is_local)
+    return R_ARC_TLS_LE32;
+      return R_ARC_TLS_IE32;
+    case R_ARC_TLS_LD32:
+      return R_ARC_TLS_LE32;
+    }
+*/
+
+  return r_type;
+}
+
 /* Function : elf_arc_check_relocs
  * Brief    : Check the relocation entries and take any special
  *           actions, depending on the relocation type if needed.
@@ -1344,51 +1627,65 @@
   bfd *dynobj;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
+  asection *sreloc = NULL;
   bfd_vma *local_got_offsets;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
-  asection *sgot;
-  asection *srelgot;
-  asection *sreloc;
+  /* joshua zhan 2008/09/25 */
+  int tls_type, old_tls_type;
+  struct elf_ARC_link_hash_table *htab;
 
   if (info->relocatable)
     return TRUE;
 
+  htab = elf_ARC_hash_table (info);
   dynobj = elf_hash_table (info)->dynobj;
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
   local_got_offsets = elf_local_got_offsets (abfd);
 
-  sgot = NULL;
-  srelgot = NULL;
-  sreloc = NULL;
-
   rel_end = relocs + sec->reloc_count;
   for (rel = relocs; rel < rel_end; rel++)
     {
+      unsigned int r_type;
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       BFD_DEBUG_PIC (fprintf(stderr,"Processing reloc #%d in %s/n",
                  rel-relocs,__PRETTY_FUNCTION__));
 
       r_symndx = ELF32_R_SYM (rel->r_info);
+      /* joshua zhan 2008/09/25 */
+      r_type = ELF32_R_TYPE (rel->r_info);
 
       if (r_symndx < symtab_hdr->sh_info)
     h = NULL;
       else
     h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
+      r_type = elf_arc_tls_transition (info, r_type, h == NULL);
+
       /* Some relocs require a global offset table.  */
       if (dynobj == NULL)
     {
+        /* joshua zhan 2008/09/25 *
       switch (ELF32_R_TYPE (rel->r_info))
+        */
+      switch (r_type)
         {
         case R_ARC_GOTPC32:
         case R_ARC_GOTOFF:
         case R_ARC_GOTPC:
-          elf_hash_table (info)->dynobj = dynobj = abfd;
-          if (! _bfd_elf_create_got_section (dynobj, info))
-        return FALSE;
+            /* joshua zhan 2008/09/11 */
+        case R_ARC_TLS_GD32:
+        case R_ARC_TLS_LD32:
+        case R_ARC_TLS_IE32:
+          if (htab->sgot == NULL)
+        {
+          if (htab->root.dynobj == NULL)
+            htab->root.dynobj = abfd;
+          if (!create_got_section (htab->root.dynobj, info))
+            return FALSE;
+        }
           break;
 
         default:
@@ -1396,24 +1693,227 @@
         }
     }
 
+      /* joshua zhan 2008/09/25
       switch (ELF32_R_TYPE (rel->r_info))
+      */
+      switch (r_type)
     {
+    /* joshua zhan 2008/09/30 */
+    case R_ARC_TLS_IE32:
+      if (info->shared)
+        info->flags |= DF_STATIC_TLS;
+      /* FALLTHROUGH */
+    case R_ARC_TLS_GD32:
+      switch (r_type)
+        {
+        default:
+          tls_type = GOT_NORMAL;
+          break;
+        case R_ARC_TLS_GD32:
+          tls_type = GOT_TLS_GD;
+          break;
+        case R_ARC_TLS_IE32:
+          tls_type = GOT_TLS_IE;
+          break;
+        }
+
+      /* This symbol requires a global offset table entry.  */
+
+      /* joshua zhan 2008/10/01 */
+      if (htab->sgot == NULL)
+        {
+          if (htab->root.dynobj == NULL)
+        htab->root.dynobj = abfd;
+          if (!create_got_section (htab->root.dynobj, info))
+        return FALSE;
+        }
+
+      if (h != NULL)
+        {
+          old_tls_type = elf_arc_hash_entry (h)->tls_type;
+
+          if (h->got.offset != (bfd_vma) -1)
+        {
+          BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry already done%d/n",r_symndx));
+
+          /* We have already allocated space in the .got.  */
+
+          /* FIXME: TLS transition */
+              if (old_tls_type != tls_type)
+            {
+              (*_bfd_error_handler)
+            (_("%B: '%s' accessed as different TLS models. TLS transition is not supported yet by ARC gcc."),
+            abfd, h->root.root.string);
+              return FALSE;
+            }
+
+              if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+            && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+            {
+              if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+            tls_type = GOT_TLS_IE;
+              else
+            {
+              (*_bfd_error_handler)
+                (_("%B: `%s' accessed both as normal and thread local symbol"),
+                abfd, h->root.root.string);
+              return FALSE;
+            }
+            }
+
+          if (old_tls_type != tls_type)
+            {
+              if (h != NULL)
+            {
+              elf_arc_hash_entry (h)->tls_type = tls_type;
+                }
+              else
+                elf_arc_local_got_tls_type (abfd) [r_symndx] = tls_type;
+            }
+
+          break;
+        }
+
+          h->got.offset = htab->sgot->size;
+          BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry %d got offset=0x%x/n",r_symndx,
+                    h->got.offset));
+
+          /* Make sure this symbol is output as a dynamic symbol.  */
+          if (h->dynindx == -1)
+        {
+          if (! bfd_elf_link_record_dynamic_symbol (info, h))
+            return FALSE;
+        }
+
+          BFD_DEBUG_PIC(fprintf (stderr, "Got raw size increased/n"));
+          htab->srelgot->size += sizeof (Elf32_External_Rela);
+          if (r_type == R_ARC_TLS_GD32)
+        htab->srelgot->size += sizeof (Elf32_External_Rela);
+        }
+      else
+        {
+        /* This is a global offset table entry for a local
+             symbol.  */
+          if (local_got_offsets == NULL)
+        {
+          size_t size;
+          register unsigned int i;
+
+          size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char));
+          local_got_offsets = (bfd_vma *) bfd_zalloc (abfd, size);
+          if (local_got_offsets == NULL)
+            return FALSE;
+          elf_local_got_offsets (abfd) = local_got_offsets;
+          for (i = 0; i < symtab_hdr->sh_info; i++)
+            local_got_offsets[i] = (bfd_vma) -1;
+
+          /* symtab_hdr->sh_info: one greater than the symbol table index of the last local symbol */
+          elf_arc_local_got_tls_type (abfd) = (char *) (local_got_offsets + symtab_hdr->sh_info);
+        }
+
+          /* joshua zhan 2008/10/02 */
+          old_tls_type = elf_arc_local_got_tls_type(abfd) [r_symndx];
+
+          if (local_got_offsets[r_symndx] != (bfd_vma) -1)
+        {
+          BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry already done%d/n",r_symndx));
+
+          /* We have already allocated space in the .got.  */
+          break;
+        }
+
+          BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry %d/n",r_symndx));
+
+          local_got_offsets[r_symndx] = htab->sgot->size;
+
+          if (info->shared)
+        {
+          htab->srelgot->size += sizeof (Elf32_External_Rela);
+          if (r_type == R_ARC_TLS_GD32)
+            htab->srelgot->size += sizeof (Elf32_External_Rela);
+        }
+        }
+
+      /* FIXME: TLS transition */
+      if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN)
+        {
+          (*_bfd_error_handler)
+        (_("%B: symbol `%s' accessed as different TLS models. TLS transition is not supported yet by ARC gcc."),
+        abfd, h ? h->root.root.string : "<local>");
+          return FALSE;
+        }
+
+      /* If a TLS symbol is accessed using IE at least once,
+         there is no point to use dynamic model for it.  */
+      if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+          && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+        {
+          if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
+        tls_type = GOT_TLS_IE;
+          else
+        {
+          (*_bfd_error_handler)
+            (_("%B: `%s' accessed both as normal and thread local symbol"),
+             abfd, h ? h->root.root.string : "<local>");
+          return FALSE;
+        }
+        }
+      if (old_tls_type != tls_type)
+        {
+          if (h != NULL)
+            elf_arc_hash_entry (h)->tls_type = tls_type;
+          else
+        elf_arc_local_got_tls_type (abfd) [r_symndx] = tls_type;
+        }
+
+      BFD_DEBUG_PIC(fprintf (stderr, "Got raw size increased/n"));
+
+      htab->sgot->size += sizeof (Elf32_External_Rela);
+      if (r_type == R_ARC_TLS_GD32)
+        htab->sgot->size += sizeof (Elf32_External_Rela);
+      break;
+
+    case R_ARC_TLS_LD32:
+      /* needs 2 got entries and one dynamic reloc */
+      if (info->shared)
+        {
+          htab->srelgot->size += sizeof (Elf32_External_Rela);
+        }
+      htab->tls_ldm_got.offset = htab->sgot->size;
+      htab->sgot->size += 2 * sizeof (Elf32_External_Rela);
+      break;
+
+    case R_ARC_TLS_LE32:
+      if (info->shared)
+        {
+          (*_bfd_error_handler)
+        (_("%B: TLS local exec code cannot be linked into shared objects"),
+         abfd);
+          return FALSE;
+        }
+
+      break;
+
+    case R_ARC_TLS_LDO32:
+      /* Nothing to do.  */
+      break;
+
     case R_ARC_GOTPC32:
       /* This symbol requires a global offset table entry.  */
 
-      if (sgot == NULL)
+      if (htab->sgot == NULL)
         {
-          sgot = bfd_get_section_by_name (dynobj, ".got");
-          BFD_ASSERT (sgot != NULL);
+          htab->sgot = bfd_get_section_by_name (dynobj, ".got");
+          BFD_ASSERT (htab->sgot != NULL);
         }
 
-      if (srelgot == NULL
+      if (htab->srelgot == NULL
           && (h != NULL || info->shared))
         {
-          srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-          if (srelgot == NULL)
+          htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+          if (htab->srelgot == NULL)
         {
-          srelgot
+          htab->srelgot
             = bfd_make_section_with_flags (dynobj, ".rela.got",
                            SEC_ALLOC
                            | SEC_LOAD
@@ -1421,8 +1921,8 @@
                            | SEC_IN_MEMORY
                            | SEC_LINKER_CREATED
                            | SEC_READONLY);
-          if (srelgot == NULL
-              || ! bfd_set_section_alignment (dynobj, srelgot, 2))
+          if (htab->srelgot == NULL
+              || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
             return FALSE;
         }
         }
@@ -1438,7 +1938,7 @@
         }
 
 
-          h->got.offset = sgot->size;
+          h->got.offset = htab->sgot->size;
           BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry %d got offset=0x%x/n",r_symndx,
                     h->got.offset));
 
@@ -1450,7 +1950,7 @@
         }
 
           BFD_DEBUG_PIC(fprintf (stderr, "Got raw size increased/n"));
-          srelgot->size += sizeof (Elf32_External_Rela);
+          htab->srelgot->size += sizeof (Elf32_External_Rela);
         }
       else
         {
@@ -1461,13 +1961,15 @@
           size_t size;
           register unsigned int i;
 
-          size = symtab_hdr->sh_info * sizeof (bfd_vma);
-          local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
+          size = symtab_hdr->sh_info * (sizeof (bfd_vma) + sizeof (char));
+          local_got_offsets = (bfd_vma *) bfd_zalloc (abfd, size);
           if (local_got_offsets == NULL)
             return FALSE;
           elf_local_got_offsets (abfd) = local_got_offsets;
           for (i = 0; i < symtab_hdr->sh_info; i++)
             local_got_offsets[i] = (bfd_vma) -1;
+
+          elf_arc_local_got_tls_type (abfd) = (char *) (local_got_offsets + symtab_hdr->sh_info);
         }
           if (local_got_offsets[r_symndx] != (bfd_vma) -1)
         {
@@ -1480,21 +1982,20 @@
           BFD_DEBUG_PIC(fprintf(stderr, "got entry stab entry %d/n",r_symndx));
 
          
-          local_got_offsets[r_symndx] = sgot->size;
+          local_got_offsets[r_symndx] = htab->sgot->size;
 
           if (info->shared)
         {
           /* If we are generating a shared object, we need to
                      output a R_ARC_RELATIVE reloc so that the dynamic
                      linker can adjust this GOT entry.  */
-          srelgot->size += sizeof (Elf32_External_Rela);
+          htab->srelgot->size += sizeof (Elf32_External_Rela);
         }
         }
      
       BFD_DEBUG_PIC(fprintf (stderr, "Got raw size increased/n"));
 
-      sgot->size += 4;
-
+      htab->sgot->size += 4;
       break;
 
     case R_ARC_PLT32:
@@ -1612,7 +2113,6 @@
     default:
       break;
     }
-
     }
 
   return TRUE;
@@ -1645,26 +2145,25 @@
                           Elf_Internal_Sym *local_syms,
                           asection **local_sections)
 {
+
   bfd *dynobj;
   Elf_Internal_Shdr *symtab_hdr;
   struct elf_link_hash_entry **sym_hashes;
+  asection *sreloc = NULL;
   bfd_vma *local_got_offsets;
-  asection *sgot;
-  asection *splt;
-  asection *sreloc;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
   short overflow_detected=0;
 
+  /* joshua zhan 2008/09/30 */
+  struct elf_ARC_link_hash_table *htab;
+  htab = elf_ARC_hash_table (info);
+
   dynobj = elf_hash_table (info)->dynobj;
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (input_bfd);
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
-  sgot = NULL;
-  splt = NULL;
-  sreloc = NULL;
-
   rel = relocs;
   relend = relocs + input_section->reloc_count;
   for (; rel < relend; rel++)
@@ -1679,6 +2178,11 @@
       bfd_reloc_status_type r;
       bfd_boolean symbol_defined = TRUE;
 
+      /* joshua zhan 2008/09/30 */
+      bfd_vma addend = (bfd_vma) 0;
+      bfd_vma off;
+      int tls_type;
+
       /* Distance of the relocation slot in the insn .This value is used for
      handling relative relocations. */
       long offset_in_insn = 0;
@@ -1799,11 +2303,19 @@
                      obscure cases sec->output_section will be NULL.  */
           relocation = 0;
         }
+
+          /* runtime relocations joshua zhan 2008/10/04 */
+          else if (sec->output_section == NULL
+              && (elf_arc_hash_entry (h)->tls_type == GOT_TLS_IE
+              || elf_arc_hash_entry (h)->tls_type == GOT_TLS_GD))
+/* 2008/11/22
+        continue;
+*/              relocation = 0;
           else if (sec->output_section == NULL)
         {
           (*_bfd_error_handler)
-            ("%s: warning: unresolvable relocation against symbol `%s' from %s section",
-             bfd_get_filename (input_bfd), h->root.root.string,
+            ("%s: WARNING: unresolvable relocation against symbol `%s' (reloc type: %x) from %s section",
+             bfd_get_filename (input_bfd), h->root.root.string, r_type,
              bfd_get_section_name (input_bfd, input_section));
           relocation = 0;
         }
@@ -1845,12 +2357,9 @@
     case R_ARC_GOTPC32:
       /* Relocation is to the entry for this symbol in the global
          offset table.  */
-      if (sgot == NULL)
-        {
-          sgot = bfd_get_section_by_name (dynobj, ".got");
-          BFD_DEBUG_PIC (fprintf (stderr, "made got/n"));
-          BFD_ASSERT (sgot != NULL);
-        }
+      /* changed to use the cache, joshua zhan 2008/10/02 */
+      if (htab->sgot == NULL)
+        abort ();
 
       if (h != NULL)
         {
@@ -1881,13 +2390,13 @@
           else
             {
               bfd_put_32 (output_bfd, relocation,
-                  sgot->contents + off);
+                  htab->sgot->contents + off);
               h->got.offset |= 1;
             }
         }
 
-          relocation = sgot->output_section->vma + sgot->output_offset + off;
-          BFD_DEBUG_PIC(fprintf(stderr, "OFFSET=0x%x output_offset=%x (1)/n", off, sgot->output_offset));
+          relocation = htab->sgot->output_section->vma + htab->sgot->output_offset + off;
+          BFD_DEBUG_PIC(fprintf(stderr, "OFFSET=0x%x output_offset=%x (1)/n", off, htab->sgot->output_offset));
         }
       else
         {
@@ -1906,33 +2415,35 @@
           else
         {
           bfd_put_32 (output_bfd, relocation,
-                  sgot->contents + off);
+                  htab->sgot->contents + off);
 
           if (info->shared)
             {
-              asection *srelgot;
+              /* asection *srelgot;
+            moved to the top scope, joshua zhan 2008/09/30
+            */
               Elf_Internal_Rela outrel;
               bfd_byte *loc;             
 
-              srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-              BFD_ASSERT (srelgot != NULL);
+              if (!htab->srelgot)
+            abort();
 
-              outrel.r_offset = (sgot->output_section->vma
-                     + sgot->output_offset
+              outrel.r_offset = (htab->sgot->output_section->vma
+                     + htab->sgot->output_offset
                      + off);
               /* RELA relocs */
-              outrel.r_addend = 0; //PBB??
+              outrel.r_addend = 0;
 
               outrel.r_info = ELF32_R_INFO (0, R_ARC_RELATIVE);
-              loc = srelgot->contents;
-              loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); /* relA */
+              loc = htab->srelgot->contents;
+              loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rela); /* relA */
               bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
             }
 
           local_got_offsets[r_symndx] |= 1;
         }
 
-          relocation = sgot->output_section->vma + sgot->output_offset + off;
+          relocation = htab->sgot->output_section->vma + htab->sgot->output_offset + off;
           BFD_DEBUG_PIC(fprintf(stderr, "OFFSET=0x%x (2)/n", off));
         }
 
@@ -1946,33 +2457,28 @@
       /* Relocation is relative to the start of the global offset
          table.  */
 
-      if (sgot == NULL)
-        {
-          sgot = bfd_get_section_by_name (dynobj, ".got");
-          BFD_ASSERT (sgot != NULL);
-        }
+      /* changed to use the cache, joshua zhan 2008/10/02 */
+      if (htab->sgot == NULL)
+        abort();
 
       /* Note that sgot->output_offset is not involved in this
          calculation.  We always want the start of .got.  If we
          defined _GLOBAL_OFFSET_TABLE in a different way, as is
          permitted by the ABI, we might have to change this
          calculation.  */
-      BFD_DEBUG_PIC(fprintf(stderr,"GOTOFF relocation = %x. Subtracting %x/n",relocation, sgot->output_section->vma));
-      relocation -= sgot->output_section->vma;
+      BFD_DEBUG_PIC(fprintf(stderr,"GOTOFF relocation = %x. Subtracting %x/n",relocation, htab->sgot->output_section->vma));
+      relocation -= htab->sgot->output_section->vma;
 
       break;
 
     case R_ARC_GOTPC:
       /* Use global offset table as symbol value.  */
 
-      if (sgot == NULL)
-        {
-          sgot = bfd_get_section_by_name (dynobj, ".got");
-          BFD_ASSERT (sgot != NULL);
-        }
+      /* changed to use the cache, joshua zhan 2008/10/02 */
+      if (htab->sgot == NULL)
+        abort();
 
-      relocation = sgot->output_section->vma;
-     
+      relocation = htab->sgot->output_section->vma;
       offset_in_insn = 4;
       break;
 
@@ -1993,14 +2499,12 @@
           break;
         }
 
-      if (splt == NULL)
-        {
-          splt = bfd_get_section_by_name (dynobj, ".plt");
-          BFD_ASSERT (splt != NULL);
-        }
+      /* changed to use the cache, joshua zhan 2008/10/02 */
+      if (htab->splt == NULL)
+        abort();
 
-      relocation = (splt->output_section->vma
-            + splt->output_offset
+      relocation = (htab->splt->output_section->vma
+            + htab->splt->output_offset
             + h->plt.offset);
 
       break;
@@ -2147,6 +2651,212 @@
         //        fprintf (stderr, "relocation AFTER = 0x%x SDATA_BEGIN = 0x%x/n", relocation, h->root.u.def.value);
         break;
       }
+
+    /* joshua zhan 2008/09/11 */
+
+    case R_ARC_TLS_GD32:
+      if (htab->sgot == NULL)
+        abort ();
+
+      if (h != NULL)
+        off = h->got.offset;
+      else
+        {
+          if (local_got_offsets == NULL)
+        abort ();
+
+          off = local_got_offsets[r_symndx];
+        }
+
+      tls_type = GOT_UNKNOWN;
+      if (h == NULL && local_got_offsets)
+        tls_type = elf_arc_local_got_tls_type (input_bfd) [r_symndx];
+      else if (h != NULL)
+        {
+          tls_type = elf_arc_hash_entry (h)->tls_type;
+          if (! info->shared
+          && (h->dynindx == -1
+              || h->def_regular))
+        r_type = R_ARC_TLS_LE32;
+        }
+
+      if (r_type == R_ARC_TLS_GD32 && tls_type == GOT_TLS_IE)
+        r_type = R_ARC_TLS_IE32;
+
+      /* The offset must always be a multiple of 4.  We use
+     the least significant bit to record whether we have
+     already generated the necessary reloc.  */
+          if ((off & 1) != 0)
+        off &= ~1;
+      else
+        {
+          Elf_Internal_Rela outrel;
+          bfd_byte *loc;
+          int dr_type, indx;
+
+          if (htab->srelgot == NULL)
+        abort();
+
+          if (h == NULL || h->dynindx == -1)
+        indx = 0;
+          else
+        indx = h->dynindx;
+
+          outrel.r_offset = htab->sgot->output_section->vma + htab->sgot->output_offset + off;
+          outrel.r_addend = 0;
+          outrel.r_info = ELF32_R_INFO (indx, R_ARC_TLS_DTPMOD32);
+          loc = htab->srelgot->contents;
+          loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+          bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+/* 2008/10/31
+              outrel.r_offset += 4;
+              outrel.r_addend = 0;
+              outrel.r_info = ELF32_R_INFO (indx, R_ARC_TLS_DTPOFF32);
+              htab->srelgot->reloc_count++;
+              loc += sizeof (Elf32_External_Rela);
+              bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+*/
+          if (indx == 0)
+        {
+          /* the symbol is not visible outside this DSO */
+          bfd_put_32 (output_bfd, relocation - dtpoff_base (info), htab->sgot->contents + off + 4);
+        }
+          else
+        {
+                  outrel.r_offset += 4;
+                  outrel.r_addend = 0;
+                  outrel.r_info = ELF32_R_INFO (indx, R_ARC_TLS_DTPOFF32);
+                  htab->srelgot->reloc_count++;
+                  loc += sizeof (Elf32_External_Rela);
+                  bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+        }
+          if (h != NULL)
+        h->got.offset |= 1;
+          else
+        local_got_offsets[r_symndx] |= 1;
+        }
+
+     /*relocation = htab->sgot->output_offset + off;*/
+      if (r_type == (int) ELF32_R_TYPE (rel->r_info))
+        relocation = htab->sgot->output_offset + off;
+      else
+        {
+          /* shouldn't come here */
+          printf("TODO/n");
+          abort ();
+        }
+
+          BFD_DEBUG_PIC(fprintf(stderr, "RELOCATION =%x/n",relocation));
+      break;
+
+    case R_ARC_TLS_IE32:
+      if (htab->sgot == NULL)
+        abort ();
+
+      if (h != NULL)
+        off = h->got.offset;
+      else
+        {
+          if (local_got_offsets == NULL)
+        abort ();
+
+          off = local_got_offsets[r_symndx];
+        }
+      /* The offset must always be a multiple of 4.  We use
+     the least significant bit to record whether we have
+     already generated the necessary reloc.  */
+          if ((off & 1) != 0)
+        off &= ~1;
+      else
+        {
+          Elf_Internal_Rela outrel;
+          bfd_byte *loc;
+          int dr_type, indx;
+
+          if (htab->srelgot == NULL)
+        abort();
+
+          if (h == NULL || h->dynindx == -1)
+        indx = 0;
+          else
+        indx = h->dynindx;
+
+          outrel.r_offset = htab->sgot->output_section->vma + htab->sgot->output_offset + off;
+
+              if (indx == 0)
+                outrel.r_addend = relocation - dtpoff_base (info);
+              else
+            outrel.r_addend = 0;
+
+          outrel.r_info = ELF32_R_INFO (indx, R_ARC_TLS_TPOFF32);
+          loc = htab->srelgot->contents;
+          loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+          bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+
+          if (h != NULL)
+        h->got.offset |= 1;
+          else
+        local_got_offsets[r_symndx] |= 1;
+        }
+
+      relocation = htab->sgot->output_offset + off;
+          BFD_DEBUG_PIC(fprintf(stderr, "RELOCATION =%x/n",relocation));
+      break;
+
+    case R_ARC_TLS_LD32:
+      if (htab->sgot == NULL)
+        abort ();
+
+      off = htab->tls_ldm_got.offset;
+      if (off & 1)
+        off &= ~1;
+      else
+        {
+          Elf_Internal_Rela outrel;
+          bfd_byte *loc;
+
+          if (htab->srelgot == NULL)
+        abort ();
+
+          outrel.r_addend = 0;
+          outrel.r_offset = htab->sgot->output_section->vma + htab->sgot->output_offset + off;
+          outrel.r_info = ELF32_R_INFO (0, R_ARC_TLS_DTPMOD32);
+          loc = htab->srelgot->contents;
+          loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
+          bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+          htab->tls_ldm_got.offset |= 1;
+
+          /* offset */
+          bfd_put_32 (output_bfd, 0, htab->sgot->contents + off + 4);
+        }
+          /* FIXME: deleted htab->sgotplt, now what? joshua zhan 2008/10/31 */
+      relocation = htab->sgot->output_offset + off;
+          BFD_DEBUG_PIC(fprintf(stderr, "RELOCATION =%x/n",relocation));
+      break;
+
+    case R_ARC_TLS_LDO32:
+      if (info->shared)
+        relocation -= dtpoff_base (info);
+      else
+        relocation = tpoff (info, relocation);
+      break;
+
+    case R_ARC_TLS_LE32:
+      if (info->shared)
+        {
+          /* FIXME: i386 support shared */
+          (*_bfd_error_handler)
+            (_("%B(%A+0x%lx): R_ARC_TLS_LE32 relocation not permitted in shared object"),
+             input_bfd, input_section,
+             (long) rel->r_offset, howto->name);
+          return FALSE;
+        }
+      else
+        {
+          relocation = tpoff (info, relocation);
+        }
+      break;
+
     default:
       /* FIXME: Putting in a random dummy relocation value for the time being */
       //      fprintf (stderr, "In %s, relocation = 0x%x,  r_type = %d/n", __PRETTY_FUNCTION__, relocation, r_type);
@@ -2219,6 +2929,7 @@
 
       r = bfd_reloc_ok;
      
+      /* dead code? joshua zhan 2008/09/30 */
 
       if (r != bfd_reloc_ok)
     {
@@ -2363,7 +3074,10 @@
 
     }
 
-  if (h->got.offset != (bfd_vma) -1)
+  if (h->got.offset != (bfd_vma) -1
+      /* joshua zhan 2008/10/05 */
+      && elf_arc_hash_entry (h)->tls_type != GOT_TLS_GD
+      && elf_arc_hash_entry (h)->tls_type != GOT_TLS_IE)
     {
       asection *sgot;
       asection *srel;
@@ -2494,11 +3208,18 @@
         case DT_INIT:
           oldname = INIT_SYM_STRING;
           name = init_str;
+          /* fix for glibc: warning: specified init/fini symbol fini not found.Defaulting to address of symbol fini,
+            joshua zhan 2008/10/18 */
+          name = info->init_function;
           goto get_sym;
 
         case DT_FINI:
           oldname = FINI_SYM_STRING;
           name = fini_str;
+          /* fix for glibc: warning: specified init/fini symbol fini not found.Defaulting to address of symbol fini,
+            joshua zhan 2008/10/18
+        change from init_function -> fini_function, joshua zhan 2008/12/04*/
+          name = info->fini_function;
           goto get_sym;
 
         get_sym:
@@ -3048,7 +3769,7 @@
         /*Ravi: changed from bfd_elf32_add_dynamic_entry */
         if (! _bfd_elf_add_dynamic_entry (info, DT_RELA, 0)
         || ! _bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0)
-        || ! _bfd_elf_add_dynamic_entry (info, DT_RELENT,
+        || ! _bfd_elf_add_dynamic_entry (info, /*DT_RELENT, joshua zhan 2008/10/10*/DT_RELAENT,
                           sizeof (Elf32_External_Rela)))
         return FALSE;
     }
@@ -3064,6 +3785,38 @@
   return TRUE;
 }
 
+/* joshua zhan 2008/09/11 */
+
+/* Return the base VMA address which should be subtracted from real addresses
+   when resolving @dtpoff relocation.
+   This is PT_TLS segment p_vaddr.  */
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (elf_hash_table (info)->tls_sec == NULL)
+    return 0;
+  return elf_hash_table (info)->tls_sec->vma;
+}
+
+/* Return the relocation value for R_ARC_TLS_TPOFF32.
+   copied from elf32-arm.c
+*/
+/* The size of the thread control block.  */
+#define TCB_SIZE    8
+static bfd_vma
+tpoff (struct bfd_link_info *info, bfd_vma address)
+{
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  bfd_vma base;
+
+  /* If tls_sec is NULL, we should have signalled an error already.  */
+  if (htab->tls_sec == NULL)
+    return 0;
+  base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power);
+  return address - htab->tls_sec->vma + base;
+}
+
 #define TARGET_LITTLE_SYM    bfd_elf32_littlearc_vec
 #define TARGET_LITTLE_NAME    "elf32-littlearc"
 #define TARGET_BIG_SYM        bfd_elf32_bigarc_vec
@@ -3071,7 +3824,11 @@
 #define ELF_ARCH        bfd_arch_arc
 #define ELF_MACHINE_CODE    EM_ARC
 #define ELF_MACHINE_ALT1    EM_ARCOMPACT
-#define ELF_MAXPAGESIZE        0x1000
+
+/* changed from 0x1000 to 0x2000, see linux headers asm-arc/param.h where page size is defined to 8kb
+#define EXEC_PAGESIZE   8192
+ joshua zhan 2008/10/30 */
+#define ELF_MAXPAGESIZE        0x2000  /* 0x1000 */
 
 #define elf_info_to_howto                    arc_info_to_howto_rel
 #define elf_info_to_howto_rel                arc_info_to_howto_rel
@@ -3082,13 +3839,22 @@
 #define elf_backend_final_write_processing   arc_elf_final_write_processing
 #define elf_backend_relocate_section         elf_arc_relocate_section
 #define elf_backend_check_relocs             elf_arc_check_relocs
+/* joshua zhan 2008/11/22 */
+#define elf_backend_copy_indirect_symbol      elf_arc_copy_indirect_symbol
+
 #define elf_backend_adjust_dynamic_symbol    elf_arc_adjust_dynamic_symbol
 
 #define elf_backend_finish_dynamic_sections  elf_arc_finish_dynamic_sections
 
 #define elf_backend_finish_dynamic_symbol    elf_arc_finish_dynamic_symbol
 
+/* joshua zhan 2008/10/01
 #define elf_backend_create_dynamic_sections  _bfd_elf_create_dynamic_sections
+*/
+#define elf_backend_create_dynamic_sections  elf_arc_create_dynamic_sections
+/* added but not used yet, joshua zhan 2008/10/05
+#define elf_backend_gc_sweep_hook               elf_arc_gc_sweep_hook
+*/
 
 #define elf_backend_size_dynamic_sections    elf_arc_size_dynamic_sections
 
diff -ruN binutils-2.17.orig/bfd/libbfd.h binutils-2.17/bfd/libbfd.h
--- binutils-2.17.orig/bfd/libbfd.h    2008-10-11 00:36:34.000000000 +0800
+++ binutils-2.17/bfd/libbfd.h    2008-12-16 15:13:51.000000000 +0800
@@ -1419,6 +1419,14 @@
   "BFD_RELOC_ARC_SDA16_LD1",
   "BFD_RELOC_ARC_SDA16_LD2",
   "BFD_RELOC_ARC_SDA32_ME",
+  "BFD_RELOC_ARC_TLS_GD32",
+  "BFD_RELOC_ARC_TLS_LD32",
+  "BFD_RELOC_ARC_TLS_LDO32",
+  "BFD_RELOC_ARC_TLS_IE32",
+  "BFD_RELOC_ARC_TLS_LE32",
+  "BFD_RELOC_ARC_TLS_DTPMOD32",
+  "BFD_RELOC_ARC_TLS_DTPOFF32",
+  "BFD_RELOC_ARC_TLS_TPOFF32",
 
   "BFD_RELOC_BFIN_16_IMM",
   "BFD_RELOC_BFIN_16_HIGH",
diff -ruN binutils-2.17.orig/bfd/reloc.c binutils-2.17/bfd/reloc.c
--- binutils-2.17.orig/bfd/reloc.c    2008-10-11 00:36:35.000000000 +0800
+++ binutils-2.17/bfd/reloc.c    2010-04-02 16:20:08.000000000 +0800
@@ -3287,6 +3287,38 @@
 BFD_RELOC_ARC_SDA32_ME
 ENUMDOC
 small data reloc 9
+ENUM
+BFD_RELOC_ARC_TLS_GD32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_LD32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_LDO32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_IE32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_LE32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_DTPMOD32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_DTPOFF32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
+ENUM
+BFD_RELOC_ARC_TLS_TPOFF32
+ENUMDOC
+arc tls reloc, joshua zhan 2008/08/09
 COMMENT
 
 ENUM
diff -ruN binutils-2.17.orig/configure.ac binutils-2.17/configure.ac
--- binutils-2.17.orig/configure.ac    2008-10-11 00:36:28.000000000 +0800
+++ binutils-2.17/configure.ac    2008-12-16 15:13:50.000000000 +0800
@@ -502,6 +502,9 @@
      ;;
     esac
     ;;
+  arc-*-linux-*)
+    noconfigdirs="$noconfigdirs target-libgloss"
+    ;;
   arc-*-*)
     noconfigdirs="$noconfigdirs target-libgloss ${libgcj}"
     ;;
@@ -2400,7 +2403,7 @@
     # For an installed makeinfo, we require it to be from texinfo 4.4 or
     # higher, else we use the "missing" dummy.
     if ${MAKEINFO} --version /
-       | egrep 'texinfo[^0-9]*([1-3][0-9]|4/.[4-9]|[5-9])' >/dev/null 2>&1; then
+       | egrep 'texinfo[^0-9]*([1-3][0-9]|4/.([4-9]|[1-9][0-9])|[5-9])' >/dev/null 2>&1; then
       :
     else
       MAKEINFO="$MISSING makeinfo"
diff -ruN binutils-2.17.orig/gas/config/tc-arc.c binutils-2.17/gas/config/tc-arc.c
--- binutils-2.17.orig/gas/config/tc-arc.c    2008-10-11 00:36:36.000000000 +0800
+++ binutils-2.17/gas/config/tc-arc.c    2010-04-02 16:20:47.000000000 +0800
@@ -281,6 +281,13 @@
     PLT_TYPE,
     GOTOFF_TYPE,
     SDA_REF_TYPE,
+    /* joshua zhan 2008/09/08 */
+    TLS_GD_TYPE,
+    TLS_LD_TYPE,
+    TLS_LDO_TYPE,
+    TLS_IE_TYPE,
+    TLS_LE_TYPE,
+
     NO_TYPE
   } arc700_special_symtype;
 
@@ -4469,6 +4476,19 @@
     case BFD_RELOC_ARC_SDA32_ME:
       break;
 
+        /* joshua zhan 2008/08/21 */
+        case BFD_RELOC_ARC_TLS_GD32:
+        case BFD_RELOC_ARC_TLS_LD32:
+        case BFD_RELOC_ARC_TLS_IE32:
+          value = 0; /* Fully resolved at runtime.  No addend.  */
+          /* Fallthrough */
+        case BFD_RELOC_ARC_TLS_LDO32:
+        case BFD_RELOC_ARC_TLS_LE32:
+          S_SET_THREAD_LOCAL (fixP->fx_addsy);
+      md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+                  value, -4);
+          break;
+
     default:
       abort ();
     }
@@ -4496,6 +4516,8 @@
   reloc = xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
 
+  /* moved up, joshua zhan 2008/08/21 */
+  reloc->addend = fixP->fx_offset;
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
@@ -4510,7 +4532,9 @@
 
   assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
  
+  /* moved up, joshua zhan 2008/08/21
   reloc->addend = fixP->fx_offset;
+  */
 
   return reloc;
 }
@@ -5177,7 +5201,13 @@
             && (!strncmp (tmpbuf + 1, "gotpc", 5)
             || !strncmp (tmpbuf + 1, "gotoff", 6)
             || !strncmp (tmpbuf + 1, "plt", 3)
-            || !strncmp (tmpbuf + 1, "h30", 3)))
+            || !strncmp (tmpbuf + 1, "h30", 3)
+                        /* TLS joshua zhan 2008/09/08 */
+                        || !strncmp (tmpbuf + 1, "tlsgd", 5)
+                        || !strncmp (tmpbuf + 1, "tlsldm", 6)
+                        || !strncmp (tmpbuf + 1, "dtpoff", 6)
+                        || !strncmp (tmpbuf + 1, "gottpoff", 8)
+                        || !strncmp (tmpbuf + 1, "tpoff", 5)))
           *tmpbuf = 0;
 
         input_line_pointer = str;
@@ -5187,7 +5217,13 @@
             && (!strncmp (tmpbuf + 1, "gotpc", 5)
             || !strncmp (tmpbuf + 1, "gotoff", 6)
             || !strncmp (tmpbuf + 1, "plt", 3)
-            || !strncmp (tmpbuf + 1, "h30", 3)))
+            || !strncmp (tmpbuf + 1, "h30", 3)
+                        /* TLS joshua zhan 2008/09/08 */
+                        || !strncmp (tmpbuf + 1, "tlsgd", 5)
+                        || !strncmp (tmpbuf + 1, "tlsldm", 6)
+                        || !strncmp (tmpbuf + 1, "dtpoff", 6)
+                        || !strncmp (tmpbuf + 1, "gottpoff", 8)
+                        || !strncmp (tmpbuf + 1, "tpoff", 5)))
           *tmpbuf = '@';
         str = input_line_pointer;
         input_line_pointer = hold;
@@ -5580,6 +5616,55 @@
                 str += 7;
                 needGOTSymbol = 1;
                 }
+
+                          /* TLS type, joshua zhan 2008/09/08 */
+                          else if (!strncmp (str, "@tlsgd", 6))
+                            {
+                  str += 6;
+                  if (arc_mach_type != bfd_mach_arc_arc700)
+                as_warn ("TLS not supported for processors prior to ARC 700/n");
+                  else
+                current_special_sym_flag = TLS_GD_TYPE;
+
+                needGOTSymbol = 1;
+                            }
+                          else if (!strncmp (str, "@tlsldm", 7))
+                            {
+                  str += 7;
+                  if (arc_mach_type != bfd_mach_arc_arc700)
+                as_warn ("TLS not supported for processors prior to ARC 700/n");
+                  else
+                current_special_sym_flag = TLS_LD_TYPE;
+
+                needGOTSymbol = 1;
+                            }
+                          else if (!strncmp (str, "@dtpoff", 7))
+                            {
+                  str += 7;
+                  if (arc_mach_type != bfd_mach_arc_arc700)
+                as_warn ("TLS not supported for processors prior to ARC 700/n");
+                  else
+                current_special_sym_flag = TLS_LDO_TYPE;
+                            }
+                          else if (!strncmp (str, "@gottpoff", 9))
+                            {
+                  str += 9;
+                  if (arc_mach_type != bfd_mach_arc_arc700)
+                as_warn ("TLS not supported for processors prior to ARC 700/n");
+                  else
+                current_special_sym_flag = TLS_IE_TYPE;
+
+                needGOTSymbol = 1;
+                            }
+                          else if (!strncmp (str, "@tpoff", 6))
+                            {
+                  str += 6;
+                  if (arc_mach_type != bfd_mach_arc_arc700)
+                as_warn ("TLS not supported for processors prior to ARC 700/n");
+                  else
+                current_special_sym_flag = TLS_LE_TYPE;
+                            }
+
               else
                 {
                   if (!strncmp (str, "@sda", 3))
@@ -6022,6 +6107,24 @@
           case GOTOFF_TYPE:
           reloc_type = BFD_RELOC_ARC_GOTOFF;
           break;
+
+              /* TLS, joshua zhan 2008/09/08 */
+              case TLS_GD_TYPE:
+                  reloc_type = BFD_RELOC_ARC_TLS_GD32;
+                  break;
+              case TLS_LD_TYPE:
+                  reloc_type = BFD_RELOC_ARC_TLS_LD32;
+                  break;
+              case TLS_LDO_TYPE:
+                  reloc_type = BFD_RELOC_ARC_TLS_LDO32;
+                  break;
+              case TLS_IE_TYPE:
+                  reloc_type = BFD_RELOC_ARC_TLS_IE32;
+                  break;
+              case TLS_LE_TYPE:
+                  reloc_type = BFD_RELOC_ARC_TLS_LE32;
+                  break;
+
           default:
         break;
           }
@@ -6105,7 +6208,13 @@
     return 0;
   /* adjust_reloc_syms doesn't know about the GOT */
   if (fixP->fx_r_type == BFD_RELOC_ARC_GOTPC32
-      || fixP->fx_r_type == BFD_RELOC_ARC_PLT32)
+      || fixP->fx_r_type == BFD_RELOC_ARC_PLT32
+      /* see tc_i386_fix_adjustable() in tc-i386.c, joshua zhan 2008/09/10 */
+      || fixP->fx_r_type == BFD_RELOC_ARC_TLS_GD32
+      || fixP->fx_r_type == BFD_RELOC_ARC_TLS_LE32
+      || fixP->fx_r_type == BFD_RELOC_ARC_TLS_IE32
+      || fixP->fx_r_type == BFD_RELOC_ARC_TLS_LD32
+      || fixP->fx_r_type == BFD_RELOC_ARC_TLS_LDO32)
     return 0;
   return 1;
 }
@@ -6153,3 +6262,14 @@
     }
     }
 }
+
+arc_force_relocation (fixS *fix)
+{
+  /* Make sure some relocations get emitted.  */
+  if (fix->fx_r_type == BFD_RELOC_ARC_TLS_GD32
+      || generic_force_reloc (fix))
+    return 1;
+
+   return 0;
+}
+


diff -ruN binutils-2.17.orig/gas/configure.tgt binutils-2.17/gas/configure.tgt
--- binutils-2.17.orig/gas/configure.tgt    2008-10-11 00:36:37.000000000 +0800
+++ binutils-2.17/gas/configure.tgt    2008-12-16 15:14:10.000000000 +0800
@@ -102,6 +102,7 @@
 
   arc-*-elf*)                fmt=elf bfd_gas=yes ;;
   arc-*-linux-uclibc*)            fmt=elf bfd_gas=yes ;;
+  arc-*-linux-*)            fmt=elf bfd_gas=yes ;;
 
   arm-*-aout)                fmt=aout ;;
   arm-*-coff | thumb-*-coff)        fmt=coff ;;
diff -ruN binutils-2.17.orig/include/elf/arc.h binutils-2.17/include/elf/arc.h
--- binutils-2.17.orig/include/elf/arc.h    2008-10-11 00:36:27.000000000 +0800
+++ binutils-2.17/include/elf/arc.h    2010-04-02 16:21:49.000000000 +0800
@@ -99,6 +99,19 @@
     RELOC_NUMBER (R_ARC_GOTOFF, 0x39)
     RELOC_NUMBER (R_ARC_GOTPC, 0x3A)
     RELOC_NUMBER (R_ARC_GOT32, 0x3B)
+
+    /* joshua zhan 2008/08/18 */
+    RELOC_NUMBER (R_ARC_TLS_GD32, 0x3C)
+    RELOC_NUMBER (R_ARC_TLS_LD32, 0x3D)
+    RELOC_NUMBER (R_ARC_TLS_LDO32, 0x3E)
+    RELOC_NUMBER (R_ARC_TLS_IE32, 0x3F)
+    RELOC_NUMBER (R_ARC_TLS_LE32, 0x40)
+    RELOC_NUMBER (R_ARC_TLS_DTPMOD32, 0x41)
+    RELOC_NUMBER (R_ARC_TLS_DTPOFF32, 0x42)
+    RELOC_NUMBER (R_ARC_TLS_TPOFF32, 0x43)
+    FAKE_RELOC (FIRST_INVALID_RELOC3, 0x44)
+    FAKE_RELOC (LAST_INVALID_RELOC3, 248)
+
 END_RELOC_NUMBERS (R_ARC_max)
 
 /* Processor specific flags for the ELF header e_flags field.  */

diff -ruN binutils-2.17.orig/ld/configure.tgt binutils-2.17/ld/configure.tgt
--- binutils-2.17.orig/ld/configure.tgt    2008-10-11 00:36:16.000000000 +0800
+++ binutils-2.17/ld/configure.tgt    2008-12-16 15:13:58.000000000 +0800
@@ -41,7 +41,7 @@
 alpha*-*-netbsd*)    targ_emul=elf64alpha_nbsd ;;
 alpha*-*-openbsd*)    targ_emul=elf64alpha
             ;;
-arc-*-elf* | arc-*-linux-uclibc*)
+arc-*-elf* | arc-*-linux-uclibc* | arc-*-linux*)
             targ_emul=arcelf
             targ_extra_emuls="arcelf_prof arclinux arclinux_prof"
             ;;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值