以下是我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"
;;