This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH v2 12/12] Add microblaze TLS support
- From: david dot holsgrove at xilinx dot com
- To: binutils at sourceware dot org
- Cc: eager at eagercon dot com, edgar dot iglesias at gmail dot com, joseph at codesourcery dot com, john dot williams at xilinx dot com, vidhumouli dot hunsigida at xilinx dot com, nagaraju dot mekala at xilinx dot com, David Holsgrove <david dot holsgrove at xilinx dot com>
- Date: Thu, 11 Oct 2012 17:17:14 +1000
- Subject: [PATCH v2 12/12] Add microblaze TLS support
- References: <cover.1349938301.git.david.holsgrove@xilinx.com>
- References: <cover.1349938301.git.david.holsgrove@xilinx.com>
From: Gopi <gopi@linux69.(none)>
Add relocations for TLS.
Add support for handling TLS symbol suffixes and generating
TLS relocs for General Dynamic and Local Dynamic models.
Create a got_symbol even when the symbol is directly used
(not just when a GOT reloc is seen)
Checkin generated files that have changed as a result of new TLS Relocs
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
Signed-off-by: David Holsgrove <david.holsgrove@xilinx.com>
---
bfd/ChangeLog | 7 +
bfd/bfd-in2.h | 31 ++
bfd/elf32-microblaze.c | 736 +++++++++++++++++++++++++++++++++++---------
bfd/libbfd.h | 8 +
bfd/reloc.c | 39 +++
gas/ChangeLog | 4 +
gas/config/tc-microblaze.c | 193 +++++++++---
include/ChangeLog | 4 +
include/elf/microblaze.h | 8 +
9 files changed, 846 insertions(+), 184 deletions(-)
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7abb19b..0c898fd 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2012-10-10 David Holsgrove <david.holsgrove@xilinx.com>
+
+ * elf32-microblaze.c: Add TLS relocations support
+ * reloc.c: Update with microblaze relocation enums
+ * bfd-in2.h: Add microblaze TLS relocation
+ * libbfd.h: Generated file
+
2012-10-10 Edgar E. Iglesias <edgar.iglesias@gmail.com>
* elf32-microblaze.c: Add microblaze little endian support
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e496083..1e47573 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5068,6 +5068,37 @@ value in a word. The relocation is relative offset from */
the dynamic object into the runtime process image. */
BFD_RELOC_MICROBLAZE_COPY,
+/* Unused Reloc */
+ BFD_RELOC_MICROBLAZE_64_TLS,
+
+/* This is a 64 bit reloc that stores the 32 bit GOT relative value
+of the GOT TLS GD info entry in two words (with an imm instruction). The
+relocation is GOT offset. */
+ BFD_RELOC_MICROBLAZE_64_TLSGD,
+
+/* This is a 64 bit reloc that stores the 32 bit GOT relative value
+of the GOT TLS LD info entry in two words (with an imm instruction). The
+relocation is GOT offset. */
+ BFD_RELOC_MICROBLAZE_64_TLSLD,
+
+/* This is a 32 bit reloc that stores the Module ID to GOT(n). */
+ BFD_RELOC_MICROBLAZE_32_TLSDTPMOD,
+
+/* This is a 32 bit reloc that stores TLS offset to GOT(n+1). */
+ BFD_RELOC_MICROBLAZE_32_TLSDTPREL,
+
+/* This is a 32 bit reloc for storing TLS offset to two words (uses imm
+instruction) */
+ BFD_RELOC_MICROBLAZE_64_TLSDTPREL,
+
+/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset
+to two words (uses imm instruction). */
+ BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL,
+
+/* This is a 64 bit reloc that stores 32-bit thread pointer relative offset
+to two words (uses imm instruction). */
+ BFD_RELOC_MICROBLAZE_64_TLSTPREL,
+
/* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address.
Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */
BFD_RELOC_AARCH64_ADD_LO12,
diff --git a/bfd/elf32-microblaze.c b/bfd/elf32-microblaze.c
index c48bf64..7b01e81 100644
--- a/bfd/elf32-microblaze.c
+++ b/bfd/elf32-microblaze.c
@@ -370,6 +370,132 @@ static reloc_howto_type microblaze_elf_howto_raw[] =
0, /* Source Mask. */
0x0000ffff, /* Dest Mask. */
FALSE), /* PC relative offset? */
+
+ /* Marker relocs for TLS. */
+ HOWTO (R_MICROBLAZE_TLS,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLS", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MICROBLAZE_TLSGD,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSGD", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MICROBLAZE_TLSLD,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSLD", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Computes the load module index of the load module that contains the
+ definition of its TLS sym. */
+ HOWTO (R_MICROBLAZE_TLSDTPMOD32,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSDTPMOD32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Computes a dtv-relative displacement, the difference between the value
+ of sym+add and the base address of the thread-local storage block that
+ contains the definition of sym, minus 0x8000. Used for initializing GOT */
+ HOWTO (R_MICROBLAZE_TLSDTPREL32,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSDTPREL32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Computes a dtv-relative displacement, the difference between the value
+ of sym+add and the base address of the thread-local storage block that
+ contains the definition of sym, minus 0x8000. */
+ HOWTO (R_MICROBLAZE_TLSDTPREL64,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSDTPREL64", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Computes a tp-relative displacement, the difference between the value of
+ sym+add and the value of the thread pointer (r13). */
+ HOWTO (R_MICROBLAZE_TLSGOTTPREL32,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSGOTTPREL32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Computes a tp-relative displacement, the difference between the value of
+ sym+add and the value of the thread pointer (r13). */
+ HOWTO (R_MICROBLAZE_TLSTPREL32,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MICROBLAZE_TLSTPREL32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
};
#ifndef NUM_ELEM
@@ -461,6 +587,27 @@ microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_MICROBLAZE_32_GOTOFF:
microblaze_reloc = R_MICROBLAZE_GOTOFF_32;
break;
+ case BFD_RELOC_MICROBLAZE_64_TLSGD:
+ microblaze_reloc = R_MICROBLAZE_TLSGD;
+ break;
+ case BFD_RELOC_MICROBLAZE_64_TLSLD:
+ microblaze_reloc = R_MICROBLAZE_TLSLD;
+ break;
+ case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
+ microblaze_reloc = R_MICROBLAZE_TLSDTPREL32;
+ break;
+ case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
+ microblaze_reloc = R_MICROBLAZE_TLSDTPREL64;
+ break;
+ case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
+ microblaze_reloc = R_MICROBLAZE_TLSDTPMOD32;
+ break;
+ case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
+ microblaze_reloc = R_MICROBLAZE_TLSGOTTPREL32;
+ break;
+ case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
+ microblaze_reloc = R_MICROBLAZE_TLSTPREL32;
+ break;
case BFD_RELOC_MICROBLAZE_COPY:
microblaze_reloc = R_MICROBLAZE_COPY;
break;
@@ -550,8 +697,21 @@ struct elf32_mb_link_hash_entry
/* Track dynamic relocs copied for this symbol. */
struct elf32_mb_dyn_relocs *dyn_relocs;
+ /* TLS Reference Types for the symbol; Updated by check_relocs */
+#define TLS_GD 1 /* GD reloc. */
+#define TLS_LD 2 /* LD reloc. */
+#define TLS_TPREL 4 /* TPREL reloc, => IE. */
+#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */
+#define TLS_TLS 16 /* Any TLS reloc. */
+ unsigned char tls_mask;
+
};
+#define IS_TLS_GD(x) (x == (TLS_TLS | TLS_GD))
+#define IS_TLS_LD(x) (x == (TLS_TLS | TLS_LD))
+#define IS_TLS_DTPREL(x) (x == (TLS_TLS | TLS_DTPREL))
+#define IS_TLS_NONE(x) (x == 0)
+
#define elf32_mb_hash_entry(ent) ((struct elf32_mb_link_hash_entry *)(ent))
/* ELF linker hash table. */
@@ -571,8 +731,17 @@ struct elf32_mb_link_hash_table
/* Small local sym to section mapping cache. */
struct sym_cache sym_sec;
+
+ /* TLS Local Dynamic GOT Entry */
+ union {
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+ } tlsld_got;
};
+/* Nonzero if this section has TLS related relocations. */
+#define has_tls_reloc sec_flg0
+
/* Get the ELF linker hash table from a link_info structure. */
#define elf32_mb_hash_table(p) \
@@ -604,6 +773,7 @@ link_hash_newfunc (struct bfd_hash_entry *entry,
eh = (struct elf32_mb_link_hash_entry *) entry;
eh->dyn_relocs = NULL;
+ eh->tls_mask = 0;
}
return entry;
@@ -654,6 +824,79 @@ microblaze_elf_final_sdp (struct bfd_link_info *info)
+ h->u.def.section->output_offset);
}
+static bfd_vma
+dtprel_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;
+}
+
+/* The size of the thread control block. */
+#define TCB_SIZE 8
+
+#if 0
+static bfd_vma
+tprel_base (struct bfd_link_info *info)
+{
+ bfd_vma base;
+
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ if (elf_hash_table (info)->tls_sec == NULL)
+ return 0;
+ base = align_power ((bfd_vma) TCB_SIZE, elf_hash_table(info)->tls_sec->alignment_power);
+
+ return elf_hash_table (info)->tls_sec->vma - base;
+}
+#endif
+
+static void
+check_unique_offset(bfd_vma offset, int tls_type, bfd_vma v)
+{
+ static bfd_vma offsets[1000];
+ static bfd_vma values[1000];
+
+ static int noffsets = 0;
+ int scan1;
+
+ return;
+
+ for (scan1 = 0; scan1 < noffsets; scan1++)
+ {
+ if (offsets[scan1] == offset)
+ {
+ fprintf (stderr, "Duplicate Offset: %lx type: %x Old: %lx New: %lx \n", offset, tls_type, values[scan1], v);
+ }
+ }
+ fprintf (stderr, "%d Registered Offset: %lx Value: %lx type: %x\n", noffsets, offset, v, tls_type);
+ offsets[noffsets] = offset;
+ values[noffsets++] = v;
+}
+
+/* Output a simple dynamic relocation into SRELOC. */
+
+static void
+microblaze_elf_output_dynamic_relocation (bfd *output_bfd,
+ asection *sreloc,
+ unsigned long reloc_index,
+ unsigned long indx,
+ int r_type,
+ bfd_vma offset,
+ bfd_vma addend
+ )
+{
+
+ Elf_Internal_Rela rel;
+
+ rel.r_info = ELF32_R_INFO (indx, r_type);
+ rel.r_offset = offset;
+ rel.r_addend = addend;
+
+ bfd_elf32_swap_reloca_out (output_bfd, &rel,
+ (sreloc->contents + reloc_index * sizeof (Elf32_External_Rela)));
+}
+
/* This code is taken from elf32-m32r.c
There is some attempt to make this function usable for many architectures,
both USE_REL and USE_RELA ['twould be nice if such a critter existed],
@@ -707,6 +950,7 @@ microblaze_elf_relocate_section (bfd *output_bfd,
bfd_boolean ret = TRUE;
asection *sreloc;
bfd_vma *local_got_offsets;
+ unsigned int tls_type;
if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1])
microblaze_elf_howto_init ();
@@ -738,6 +982,8 @@ microblaze_elf_relocate_section (bfd *output_bfd,
h = NULL;
r_type = ELF32_R_TYPE (rel->r_info);
+ tls_type = 0;
+
if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max)
{
(*_bfd_error_handler) (_("%s: unknown relocation type %d"),
@@ -971,70 +1217,208 @@ microblaze_elf_relocate_section (bfd *output_bfd,
break;
}
+ case (int) R_MICROBLAZE_TLSGD:
+ tls_type = (TLS_TLS | TLS_GD);
+ goto dogot;
+ case (int) R_MICROBLAZE_TLSLD:
+ tls_type = (TLS_TLS | TLS_LD);
+ dogot:
case (int) R_MICROBLAZE_GOT_64:
{
+ bfd_vma *offp;
+ bfd_vma off, off2;
+ unsigned long indx;
+ bfd_vma static_value;
+
+ bfd_boolean need_relocs = FALSE;
+
if (htab->sgot == NULL)
abort ();
- if (h == NULL)
- {
- bfd_vma off;
+
+ indx = 0;
+ offp = NULL;
+
+ /* 1. Identify GOT Offset;
+ 2. Compute Static Values
+ 3. Process Module Id, Process Offset
+ 4. Fixup Relocation with GOT offset value
+ */
+
+ /* 1. Determine GOT Offset to use : TLS_LD, global, local */
+ if ( IS_TLS_LD (tls_type) )
+ offp = &htab->tlsld_got.offset;
+ else if (h != NULL)
+ {
+ if (htab->sgotplt != NULL && h->got.offset != (bfd_vma) -1)
+ offp = &h->got.offset;
+ else
+ abort ();
+ }
+ else
+ {
if (local_got_offsets == NULL)
abort ();
- off = local_got_offsets[r_symndx];
- /* The LSB indicates whether we've already
- created relocation. */
- if (off & 1)
- off &= ~1;
- else
- {
- bfd_put_32 (output_bfd, relocation + addend,
- htab->sgot->contents + off);
+ offp = &local_got_offsets[r_symndx];
+ }
+
+ if ( !offp ) abort();
+
+ off = (*offp) & ~1;
+ off2 = off;
+
+ if (IS_TLS_LD(tls_type) || IS_TLS_GD(tls_type))
+ off2 = off + 4;
+
+ /* Symbol index to use for relocs */
+ if (h != NULL)
+ {
+ bfd_boolean dyn =
+ elf_hash_table (info)->dynamic_sections_created;
+
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ && (!info->shared ||
+ !SYMBOL_REFERENCES_LOCAL (info, h)))
+ indx = h->dynindx;
+ }
+
+ /* Need to generate relocs ? */
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ need_relocs = TRUE;
+
+ /* 2. Compute/Emit Static value of r-expression */
+ static_value = relocation + addend;
+
+ /* 3. Process module-id and offset */
+ if (! ((*offp) & 1) )
+ {
+ bfd_vma got_offset;
+
+ got_offset = (htab->sgot->output_section->vma
+ + htab->sgot->output_offset
+ + off);
+
+ /* Process module-id */
+ if (IS_TLS_LD(tls_type))
+ {
+
+ if ( ! info->shared )
+ {
+ check_unique_offset( off, tls_type, 1);
+
+ bfd_put_32 (output_bfd, 1,
+ htab->sgot->contents + off);
+ }
+ else
+ {
+ check_unique_offset( off, tls_type, 0xDDDDDDDD);
+
+ microblaze_elf_output_dynamic_relocation (
+ output_bfd, htab->srelgot,
+ htab->srelgot->reloc_count++,
+ /* symindex= */ 0,
+ R_MICROBLAZE_TLSDTPMOD32,
+ got_offset, 0);
+ }
+ }
+ else if (IS_TLS_GD(tls_type))
+ {
+ if ( ! need_relocs )
+ {
+ check_unique_offset( off, tls_type, 1);
+
+ bfd_put_32 (output_bfd, 1,
+ htab->sgot->contents + off);
+ }
+ else
+ {
+ check_unique_offset( off, tls_type, 0);
+
+ microblaze_elf_output_dynamic_relocation (
+ output_bfd, htab->srelgot,
+ htab->srelgot->reloc_count++,
+ /* symindex= */ indx,
+ R_MICROBLAZE_TLSDTPMOD32,
+ got_offset, indx ? 0 : static_value);
+ }
+ }
+
+ /* Process Offset */
+ if (htab->srelgot == NULL)
+ abort ();
- if (info->shared)
- {
- Elf_Internal_Rela outrel;
- bfd_byte *loc;
- if (htab->srelgot == NULL)
- abort ();
- outrel.r_offset = (htab->sgot->output_section->vma
+ got_offset = (htab->sgot->output_section->vma
+ htab->sgot->output_offset
- + off);
- outrel.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL);
- outrel.r_addend = relocation + addend;
- loc = htab->srelgot->contents;
- loc += htab->srelgot->reloc_count++
- * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
- }
- local_got_offsets[r_symndx] |= 1;
- }
- relocation = htab->sgot->output_section->vma
- + htab->sgot->output_offset + off
- - htab->sgotplt->output_section->vma
- - htab->sgotplt->output_offset;
- unresolved_reloc = FALSE;
- }
- else
- {
- if (htab->sgotplt != NULL && h != NULL
- && h->got.offset != (bfd_vma) -1)
- {
- bfd_put_32 (output_bfd, relocation + addend,
- htab->sgot->contents + h->got.offset);
- relocation = htab->sgot->output_section->vma
- + htab->sgot->output_offset
- + h->got.offset
- - htab->sgotplt->output_section->vma
- - htab->sgotplt->output_offset;
- unresolved_reloc = FALSE;
- }
- else
- abort (); /* ??? */
- }
+ + off2);
+ if (IS_TLS_LD(tls_type))
+ {
+ /* For LD, offset should be 0 */
+ *offp |= 1;
+ bfd_put_32 (output_bfd, 0, htab->sgot->contents + off2);
+ }
+ else if (IS_TLS_GD(tls_type))
+ {
+ *offp |= 1;
+ static_value -= dtprel_base(info);
+ if (need_relocs)
+ {
+ check_unique_offset(off2, tls_type, indx ? 0 : static_value + 1);
+ microblaze_elf_output_dynamic_relocation (
+ output_bfd, htab->srelgot,
+ htab->srelgot->reloc_count++,
+ /* symindex= */ indx,
+ R_MICROBLAZE_TLSDTPREL32,
+ got_offset, indx ? 0 : static_value);
+ }
+ else
+ {
+ check_unique_offset(off2, tls_type, static_value);
+
+ bfd_put_32 (output_bfd, static_value,
+ htab->sgot->contents + off2);
+ }
+ }
+ else
+ {
+ bfd_put_32 (output_bfd, static_value,
+ htab->sgot->contents + off2);
+
+ /* Relocs for dyn symbols generated by
+ finish_dynamic_symbols */
+ if (info->shared && h == NULL)
+ {
+ *offp |= 1;
+
+ check_unique_offset(off2, tls_type, static_value);
+
+ microblaze_elf_output_dynamic_relocation (
+ output_bfd, htab->srelgot,
+ htab->srelgot->reloc_count++,
+ /* symindex= */ indx,
+ R_MICROBLAZE_REL,
+ got_offset, static_value);
+ }
+ }
+ }
+
+ /* 4. Fixup Relocation with GOT offset value */
+ /* Compute relative address of GOT entry for applying
+ the current relocation */
+ relocation = htab->sgot->output_section->vma
+ + htab->sgot->output_offset
+ + off
+ - htab->sgotplt->output_section->vma
+ - htab->sgotplt->output_offset;
+
+ /* Apply Current Relocation */
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
contents + offset + endian + INST_WORD_SIZE);
+
+ unresolved_reloc = FALSE;
break;
}
@@ -1064,6 +1448,14 @@ microblaze_elf_relocate_section (bfd *output_bfd,
break;
}
+ case (int) R_MICROBLAZE_TLSDTPREL64:
+ relocation += addend;
+ relocation -= dtprel_base(info);
+ bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
+ contents + offset + 2);
+ bfd_put_16 (input_bfd, relocation & 0xffff,
+ contents + offset + 2 + INST_WORD_SIZE);
+ break;
case (int) R_MICROBLAZE_64_PCREL :
case (int) R_MICROBLAZE_64:
case (int) R_MICROBLAZE_32:
@@ -1082,6 +1474,7 @@ microblaze_elf_relocate_section (bfd *output_bfd,
relocation -= (input_section->output_section->vma
+ input_section->output_offset
+ offset + INST_WORD_SIZE);
+
bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff,
@@ -1964,6 +2357,34 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
return TRUE;
}
+static bfd_boolean
+update_local_sym_info (bfd *abfd,
+ Elf_Internal_Shdr *symtab_hdr,
+ unsigned long r_symndx,
+ unsigned int tls_type)
+{
+ bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
+ unsigned char *local_got_tls_masks;
+
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size = symtab_hdr->sh_info;
+
+ size *= (sizeof (*local_got_refcounts)
+ + sizeof (*local_got_tls_masks));
+ local_got_refcounts = bfd_zalloc (abfd, size);
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ }
+
+ local_got_tls_masks =
+ (unsigned char *) (local_got_refcounts + symtab_hdr->sh_info);
+ local_got_tls_masks[r_symndx] |= tls_type;
+ local_got_refcounts[r_symndx] += 1;
+
+ return TRUE;
+}
/* Look through the relocs for a section during the first phase. */
static bfd_boolean
@@ -2000,6 +2421,7 @@ microblaze_elf_check_relocs (bfd * abfd,
unsigned int r_type;
struct elf_link_hash_entry * h;
unsigned long r_symndx;
+ unsigned char tls_type = 0;
r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info);
@@ -2035,6 +2457,13 @@ microblaze_elf_check_relocs (bfd * abfd,
break;
/* This relocation requires .got entry. */
+ case R_MICROBLAZE_TLSGD:
+ tls_type |= (TLS_TLS | TLS_GD);
+ goto dogottls;
+ case R_MICROBLAZE_TLSLD:
+ tls_type |= (TLS_TLS | TLS_LD);
+ dogottls:
+ sec->has_tls_reloc = 1;
case R_MICROBLAZE_GOT_64:
if (htab->sgot == NULL)
{
@@ -2046,25 +2475,12 @@ microblaze_elf_check_relocs (bfd * abfd,
if (h != NULL)
{
h->got.refcount += 1;
+ elf32_mb_hash_entry (h)->tls_mask |= tls_type;
}
else
{
- bfd_signed_vma *local_got_refcounts;
-
- /* This is a global offset table entry for a local symbol. */
- local_got_refcounts = elf_local_got_refcounts (abfd);
- if (local_got_refcounts == NULL)
- {
- bfd_size_type size;
-
- size = symtab_hdr->sh_info;
- size *= sizeof (bfd_signed_vma);
- local_got_refcounts = bfd_zalloc (abfd, size);
- if (local_got_refcounts == NULL)
- return FALSE;
- elf_local_got_refcounts (abfd) = local_got_refcounts;
- }
- local_got_refcounts[r_symndx] += 1;
+ if (! update_local_sym_info(abfd, symtab_hdr, r_symndx, tls_type) )
+ return FALSE;
}
break;
@@ -2077,7 +2493,7 @@ microblaze_elf_check_relocs (bfd * abfd,
/* we may need a copy reloc. */
h->non_got_ref = 1;
- /* we may also need a .plt entry. */
+ /* we may also need a .plt entry. */
h->plt.refcount += 1;
if (ELF32_R_TYPE (rel->r_info) != R_MICROBLAZE_64_PCREL)
h->pointer_equality_needed = 1;
@@ -2128,45 +2544,17 @@ microblaze_elf_check_relocs (bfd * abfd,
if (sreloc == NULL)
{
- const char *name;
bfd *dynobj;
- unsigned int strndx = elf_elfheader (abfd)->e_shstrndx;
- unsigned int shnam = _bfd_elf_single_rel_hdr (sec)->sh_name;
-
- name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
- if (name == NULL)
- return FALSE;
-
- if (strncmp (name, ".rela", 5) != 0
- || strcmp (bfd_get_section_name (abfd, sec),
- name + 5) != 0)
- {
- (*_bfd_error_handler)
- (_("%B: bad relocation section name `%s\'"),
- abfd, name);
- }
if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd;
+
dynobj = htab->elf.dynobj;
- sreloc = bfd_get_linker_section (dynobj, name);
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, dynobj, 2, abfd, 1);
if (sreloc == NULL)
- {
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
- sreloc = bfd_make_section_anyway_with_flags (dynobj,
- name,
- flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 2))
- return FALSE;
- }
- elf_section_data (sec)->sreloc = sreloc;
+ return FALSE;
}
/* If this is a global symbol, we count the number of
@@ -2297,6 +2685,8 @@ microblaze_elf_copy_indirect_symbol (struct bfd_link_info *info,
eind->dyn_relocs = NULL;
}
+ edir->tls_mask |= eind->tls_mask;
+
_bfd_elf_link_hash_copy_indirect (info, dir, ind);
}
@@ -2515,8 +2905,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
h->needs_plt = 0;
}
+ eh = (struct elf32_mb_link_hash_entry *) h;
if (h->got.refcount > 0)
{
+ unsigned int need;
asection *s;
/* Make sure this symbol is output as a dynamic symbol.
@@ -2527,16 +2919,43 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
-
- s = htab->sgot;
- h->got.offset = s->size;
- s->size += 4;
- htab->srelgot->size += sizeof (Elf32_External_Rela);
+ need = 0;
+ if ((eh->tls_mask & TLS_TLS) != 0)
+ {
+ /* Handle TLS Symbol */
+ if ((eh->tls_mask & TLS_LD) != 0)
+ {
+ if (!eh->elf.def_dynamic)
+ /* We'll just use htab->tlsld_got.offset. This should
+ always be the case. It's a little odd if we have
+ a local dynamic reloc against a non-local symbol. */
+ htab->tlsld_got.refcount += 1;
+ else
+ need += 8;
+ }
+ if ((eh->tls_mask & TLS_GD) != 0)
+ need += 8;
+ }
+ else
+ {
+ /* Regular (non-TLS) symbol */
+ need += 4;
+ }
+ if (need == 0)
+ {
+ h->got.offset = (bfd_vma) -1;
+ }
+ else
+ {
+ s = htab->sgot;
+ h->got.offset = s->size;
+ s->size += need;
+ htab->srelgot->size += need * (sizeof (Elf32_External_Rela) / 4);
+ }
}
else
h->got.offset = (bfd_vma) -1;
- eh = (struct elf32_mb_link_hash_entry *) h;
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -2634,6 +3053,7 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_signed_vma *end_local_got;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
+ unsigned char *lgot_masks;
asection *srel;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
@@ -2673,17 +3093,36 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
+ lgot_masks = (unsigned char *) end_local_got;
s = htab->sgot;
srel = htab->srelgot;
- for (; local_got < end_local_got; ++local_got)
+ for (; local_got < end_local_got; ++local_got, ++lgot_masks)
{
if (*local_got > 0)
{
- *local_got = s->size;
- s->size += 4;
- if (info->shared)
- srel->size += sizeof (Elf32_External_Rela);
+ unsigned int need = 0;
+ if ((*lgot_masks & TLS_TLS) != 0)
+ {
+ if ((*lgot_masks & TLS_GD) != 0)
+ need += 8;
+ if ((*lgot_masks & TLS_LD) != 0)
+ htab->tlsld_got.refcount += 1;
+ }
+ else
+ need += 4;
+
+ if (need == 0)
+ {
+ *local_got = (bfd_vma) -1;
+ }
+ else
+ {
+ *local_got = s->size;
+ s->size += need;
+ if (info->shared)
+ srel->size += need * ( sizeof (Elf32_External_Rela) / 4 );
+ }
}
else
*local_got = (bfd_vma) -1;
@@ -2694,6 +3133,16 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
sym dynamic relocs. */
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
+ if (htab->tlsld_got.refcount > 0)
+ {
+ htab->tlsld_got.offset = htab->sgot->size;
+ htab->sgot->size += 8;
+ if (info->shared)
+ htab->srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ else
+ htab->tlsld_got.offset = (bfd_vma) -1;
+
if (elf_hash_table (info)->dynamic_sections_created)
{
/* Make space for the trailing nop in .plt. */
@@ -2812,6 +3261,7 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
Elf_Internal_Sym *sym)
{
struct elf32_mb_link_hash_table *htab;
+ struct elf32_mb_link_hash_entry *eh = elf32_mb_hash_entry(h);
htab = elf32_mb_hash_table (info);
if (htab == NULL)
@@ -2883,12 +3333,14 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
}
}
- if (h->got.offset != (bfd_vma) -1)
+ /* h->got.refcount to be checked ? */
+ if (h->got.offset != (bfd_vma) -1 &&
+ ! ((h->got.offset & 1) ||
+ IS_TLS_LD(eh->tls_mask) || IS_TLS_GD(eh->tls_mask)))
{
asection *sgot;
asection *srela;
- Elf_Internal_Rela rela;
- bfd_byte *loc;
+ bfd_vma offset;
/* This symbol has an entry in the global offset table. Set it
up. */
@@ -2897,36 +3349,36 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
srela = htab->srelgot;
BFD_ASSERT (sgot != NULL && srela != NULL);
- rela.r_offset = (sgot->output_section->vma
- + sgot->output_offset
+ offset = (sgot->output_section->vma + sgot->output_offset
+ (h->got.offset &~ (bfd_vma) 1));
- /* If this is a -Bsymbolic link, and the symbol is defined
- locally, we just want to emit a RELATIVE reloc. Likewise if
- the symbol was forced to be local because of a version file.
- The entry in the global offset table will already have been
- initialized in the relocate_section function. */
- if (info->shared
- && (info->symbolic || h->dynindx == -1)
- && h->def_regular)
- {
- asection *sec = h->root.u.def.section;
- rela.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL);
- rela.r_addend = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else
- {
- rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_GLOB_DAT);
- rela.r_addend = 0;
- }
+ {
+ /* If this is a -Bsymbolic link, and the symbol is defined
+ locally, we just want to emit a RELATIVE reloc. Likewise if
+ the symbol was forced to be local because of a version file.
+ The entry in the global offset table will already have been
+ initialized in the relocate_section function. */
+ if (info->shared && (info->symbolic || h->dynindx == -1)
+ && h->def_regular)
+ {
+ asection *sec = h->root.u.def.section;
+ microblaze_elf_output_dynamic_relocation ( output_bfd,
+ srela, srela->reloc_count++, /* symindex= */ 0,
+ R_MICROBLAZE_REL, offset,
+ h->root.u.def.value + sec->output_section->vma
+ + sec->output_offset);
+ }
+ else
+ {
+ microblaze_elf_output_dynamic_relocation ( output_bfd,
+ srela, srela->reloc_count++,
+ h->dynindx, R_MICROBLAZE_GLOB_DAT, offset, 0);
+ }
+ }
- bfd_put_32 (output_bfd, (bfd_vma) 0,
+ bfd_put_32 (output_bfd, (bfd_vma) 0,
sgot->contents + (h->got.offset &~ (bfd_vma) 1));
- loc = srela->contents;
- loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+
}
if (h->needs_copy)
@@ -3096,7 +3548,7 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
#define ELF_TARGET_ID MICROBLAZE_ELF_DATA
#define ELF_MACHINE_CODE EM_MICROBLAZE
#define ELF_MACHINE_ALT1 EM_MICROBLAZE_OLD
-#define ELF_MAXPAGESIZE 0x4 /* 4k, if we ever have 'em. */
+#define ELF_MAXPAGESIZE 0x1000 /* 4k, if we ever have 'em. */
#define elf_info_to_howto microblaze_elf_info_to_howto
#define elf_info_to_howto_rel NULL
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 6c48d64..e20013a 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2418,6 +2418,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_MICROBLAZE_64_GOTOFF",
"BFD_RELOC_MICROBLAZE_32_GOTOFF",
"BFD_RELOC_MICROBLAZE_COPY",
+ "BFD_RELOC_MICROBLAZE_64_TLS",
+ "BFD_RELOC_MICROBLAZE_64_TLSGD",
+ "BFD_RELOC_MICROBLAZE_64_TLSLD",
+ "BFD_RELOC_MICROBLAZE_32_TLSDTPMOD",
+ "BFD_RELOC_MICROBLAZE_32_TLSDTPREL",
+ "BFD_RELOC_MICROBLAZE_64_TLSDTPREL",
+ "BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL",
+ "BFD_RELOC_MICROBLAZE_64_TLSTPREL",
"BFD_RELOC_AARCH64_ADD_LO12",
"BFD_RELOC_AARCH64_ADR_GOT_PAGE",
"BFD_RELOC_AARCH64_ADR_HI21_PCREL",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 47d052d..76669fa 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5882,6 +5882,45 @@ ENUM
ENUMDOC
This is used to tell the dynamic linker to copy the value out of
the dynamic object into the runtime process image.
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLS
+ENUMDOC
+ Unused Reloc
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLSGD
+ENUMDOC
+ This is a 64 bit reloc that stores the 32 bit GOT relative value
+ of the GOT TLS GD info entry in two words (with an imm instruction). The
+ relocation is GOT offset.
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLSLD
+ENUMDOC
+ This is a 64 bit reloc that stores the 32 bit GOT relative value
+ of the GOT TLS LD info entry in two words (with an imm instruction). The
+ relocation is GOT offset.
+ENUM
+ BFD_RELOC_MICROBLAZE_32_TLSDTPMOD
+ENUMDOC
+ This is a 32 bit reloc that stores the Module ID to GOT(n).
+ENUM
+ BFD_RELOC_MICROBLAZE_32_TLSDTPREL
+ENUMDOC
+ This is a 32 bit reloc that stores TLS offset to GOT(n+1).
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLSDTPREL
+ENUMDOC
+ This is a 32 bit reloc for storing TLS offset to two words (uses imm
+ instruction)
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL
+ENUMDOC
+ This is a 64 bit reloc that stores 32-bit thread pointer relative offset
+ to two words (uses imm instruction).
+ENUM
+ BFD_RELOC_MICROBLAZE_64_TLSTPREL
+ENUMDOC
+ This is a 64 bit reloc that stores 32-bit thread pointer relative offset
+ to two words (uses imm instruction).
ENUM
BFD_RELOC_AARCH64_ADD_LO12
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 29daf78..4aed1c5 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,9 @@
2012-10-10 David Holsgrove <david.holsgrove@xilinx.com>
+ * config/tc-microblaze.c: Add microblaze TLS support
+
+2012-10-10 David Holsgrove <david.holsgrove@xilinx.com>
+
* config/tc-microblaze.c: Add support for slr and shr insns
2012-10-10 Nagaraju Mekala <nagaraju.mekala@xilinx.com>
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c
index e9c7846..d77c0c0 100644
--- a/gas/config/tc-microblaze.c
+++ b/gas/config/tc-microblaze.c
@@ -81,6 +81,11 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
#define GOT_OFFSET 8
#define PLT_OFFSET 9
#define GOTOFF_OFFSET 10
+#define TLSGD_OFFSET 11
+#define TLSLD_OFFSET 12
+#define TLSDTPMOD_OFFSET 13
+#define TLSDTPREL_OFFSET 14
+#define TLSTPREL_OFFSET 15
/* Initialize the relax table. */
@@ -97,6 +102,12 @@ const relax_typeS md_relax_table[] =
{ 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 8: GOT_OFFSET. */
{ 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 9: PLT_OFFSET. */
{ 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 10: GOTOFF_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 11: TLSGD_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 12: TLSLD_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*1, 0 }, /* 13: TLSDTPMOD_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 14: TLSDTPREL_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 15: TLSGOTTPREL_OFFSET. */
+ { 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 } /* 16: TLSTPREL_OFFSET. */
};
static struct hash_control * opcode_hash_control; /* Opcode mnemonics. */
@@ -599,9 +610,73 @@ parse_exp (char *s, expressionS *e)
}
/* Symbol modifiers (@GOT, @PLT, @GOTOFF). */
+
+#define IMM_NONE 0
#define IMM_GOT 1
#define IMM_PLT 2
#define IMM_GOTOFF 3
+#define IMM_TLSGD 4
+#define IMM_TLSLD 5
+#define IMM_TLSDTPMOD 6
+#define IMM_TLSDTPREL 7
+#define IMM_TLSTPREL 8
+#define IMM_MAX 9
+
+struct imm_type {
+ char *isuffix; /* Suffix String */
+ int itype; /* Suffix Type */
+ int otype; /* Offset Type */
+};
+
+/* These are NOT in assending order of type, GOTOFF is ahead to make
+ sure @GOTOFF does not get matched with @GOT */
+static struct imm_type imm_types[] = {
+ { "NONE", IMM_NONE , 0 },
+ { "GOTOFF", IMM_GOTOFF , GOTOFF_OFFSET },
+ { "GOT", IMM_GOT , GOT_OFFSET },
+ { "PLT", IMM_PLT , PLT_OFFSET },
+ { "TLSGD", IMM_TLSGD , TLSGD_OFFSET },
+ { "TLSLDM", IMM_TLSLD, TLSLD_OFFSET },
+ { "TLSDTPMOD", IMM_TLSDTPMOD, TLSDTPMOD_OFFSET },
+ { "TLSDTPREL", IMM_TLSDTPREL, TLSDTPREL_OFFSET },
+ { "TLSTPREL", IMM_TLSTPREL, TLSTPREL_OFFSET }
+};
+
+static int
+match_imm (const char *s, int *ilen)
+{
+ int i;
+ int slen;
+
+ /* Check for matching suffix */
+ for (i = 1; i < IMM_MAX; i++) {
+ slen = strlen (imm_types[i].isuffix);
+
+ if (strncmp (imm_types[i].isuffix, s, slen) == 0)
+ {
+ *ilen = slen;
+ return imm_types[i].itype;
+ }
+ } /* for */
+ *ilen = 0;
+ return 0;
+}
+
+static int
+get_imm_otype (int itype)
+{
+ int i, otype;
+
+ otype = 0;
+ /* Check for matching itype */
+ for (i = 1; i < IMM_MAX; i++) {
+ if (imm_types[i].itype == itype) {
+ otype = imm_types[i].otype;
+ break;
+ }
+ }
+ return otype;
+}
static symbolS * GOT_symbol;
@@ -612,6 +687,9 @@ parse_imm (char * s, expressionS * e, int min, int max)
{
char *new_pointer;
char *atp;
+ int itype, ilen;
+
+ ilen = 0;
/* Find the start of "@GOT" or "@PLT" suffix (if any) */
for (atp = s; *atp != '@'; atp++)
@@ -620,25 +698,17 @@ parse_imm (char * s, expressionS * e, int min, int max)
if (*atp == '@')
{
- if (strncmp (atp + 1, "GOTOFF", 5) == 0)
- {
- *atp = 0;
- e->X_md = IMM_GOTOFF;
- }
- else if (strncmp (atp + 1, "GOT", 3) == 0)
- {
- *atp = 0;
- e->X_md = IMM_GOT;
- }
- else if (strncmp (atp + 1, "PLT", 3) == 0)
- {
- *atp = 0;
- e->X_md = IMM_PLT;
+ itype = match_imm (atp + 1, &ilen);
+ if (itype != 0)
+ {
+ *atp = 0;
+ e->X_md = itype;
}
else
{
atp = NULL;
e->X_md = 0;
+ ilen = 0;
}
*atp = 0;
}
@@ -655,6 +725,11 @@ parse_imm (char * s, expressionS * e, int min, int max)
new_pointer = parse_exp (s, e);
+ if (!GOT_symbol && ! strncmp (s, GOT_SYMBOL_NAME, 20))
+ {
+ GOT_symbol = symbol_find_or_make (GOT_SYMBOL_NAME);
+ }
+
if (e->X_op == O_absent)
; /* An error message has already been emitted. */
else if ((e->X_op != O_constant && e->X_op != O_symbol) )
@@ -670,9 +745,7 @@ parse_imm (char * s, expressionS * e, int min, int max)
{
*atp = '@'; /* restore back (needed?) */
if (new_pointer >= atp)
- new_pointer += (e->X_md == IMM_GOTOFF)?7:4;
- /* sizeof("@GOTOFF", "@GOT" or "@PLT") */
-
+ new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */
}
return new_pointer;
}
@@ -792,7 +865,14 @@ tc_microblaze_fix_adjustable (struct fix *fixP)
if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT
- || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT)
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_PLT
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGD
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSLD
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPMOD
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_32_TLSDTPREL
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSDTPREL
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL
+ || fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_TLSTPREL)
return 0;
return 1;
@@ -940,15 +1020,12 @@ md_assemble (char * str)
opc = str_microblaze_rw_anchor;
else
opc = NULL;
- if (exp.X_md == IMM_GOT)
- subtype = GOT_OFFSET;
- else if (exp.X_md == IMM_PLT)
- subtype = PLT_OFFSET;
- else if (exp.X_md == IMM_GOTOFF)
- subtype = GOTOFF_OFFSET;
- else
- subtype = opcode->inst_offset_type;
+ if (exp.X_md != 0) {
+ subtype = get_imm_otype(exp.X_md);
+ } else {
+ subtype = opcode->inst_offset_type;
+ }
output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */
@@ -1436,12 +1513,11 @@ md_assemble (char * str)
char *opc = NULL;
relax_substateT subtype;
- if (exp.X_md == IMM_GOT)
- subtype = GOT_OFFSET;
- else if (exp.X_md == IMM_PLT)
- subtype = PLT_OFFSET;
- else
+ if (exp.X_md != 0) {
+ subtype = get_imm_otype(exp.X_md);
+ } else {
subtype = opcode->inst_offset_type;
+ }
output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */
@@ -1503,12 +1579,11 @@ md_assemble (char * str)
char *opc = NULL;
relax_substateT subtype;
- if (exp.X_md == IMM_GOT)
- subtype = GOT_OFFSET;
- else if (exp.X_md == IMM_PLT)
- subtype = PLT_OFFSET;
- else
+ if (exp.X_md != 0) {
+ subtype = get_imm_otype(exp.X_md);
+ } else {
subtype = opcode->inst_offset_type;
+ }
output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */
@@ -1576,12 +1651,11 @@ md_assemble (char * str)
char *opc = NULL;
relax_substateT subtype;
- if (exp.X_md == IMM_GOT)
- subtype = GOT_OFFSET;
- else if (exp.X_md == IMM_PLT)
- subtype = PLT_OFFSET;
- else
- subtype = opcode->inst_offset_type;
+ if (exp.X_md != 0) {
+ subtype = get_imm_otype(exp.X_md);
+ } else {
+ subtype = opcode->inst_offset_type;
+ }
output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */
@@ -1847,6 +1921,24 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
fragP->fr_fix += INST_WORD_SIZE * 2;
fragP->fr_var = 0;
break;
+ case TLSGD_OFFSET:
+ fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+ fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSGD);
+ fragP->fr_fix += INST_WORD_SIZE * 2;
+ fragP->fr_var = 0;
+ break;
+ case TLSLD_OFFSET:
+ fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+ fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSLD);
+ fragP->fr_fix += INST_WORD_SIZE * 2;
+ fragP->fr_var = 0;
+ break;
+ case TLSDTPREL_OFFSET:
+ fix_new (fragP, fragP->fr_fix, INST_WORD_SIZE * 2, fragP->fr_symbol,
+ fragP->fr_offset, FALSE, BFD_RELOC_MICROBLAZE_64_TLSDTPREL);
+ fragP->fr_fix += INST_WORD_SIZE * 2;
+ fragP->fr_var = 0;
+ break;
default:
abort ();
@@ -2028,6 +2120,11 @@ md_apply_fix (fixS * fixP,
}
break;
+ case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
+ case BFD_RELOC_MICROBLAZE_64_TLSGD:
+ case BFD_RELOC_MICROBLAZE_64_TLSLD:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+
case BFD_RELOC_MICROBLAZE_64_GOTPC:
case BFD_RELOC_MICROBLAZE_64_GOT:
case BFD_RELOC_MICROBLAZE_64_PLT:
@@ -2206,11 +2303,16 @@ md_estimate_size_before_relax (fragS * fragP,
case GOT_OFFSET:
case PLT_OFFSET:
case GOTOFF_OFFSET:
+ case TLSGD_OFFSET:
+ case TLSLD_OFFSET:
+ case TLSTPREL_OFFSET:
+ case TLSDTPREL_OFFSET:
fragP->fr_var = INST_WORD_SIZE*2;
break;
case DEFINED_RO_SEGMENT:
case DEFINED_RW_SEGMENT:
case DEFINED_PC_OFFSET:
+ case TLSDTPMOD_OFFSET:
fragP->fr_var = INST_WORD_SIZE;
break;
default:
@@ -2294,6 +2396,13 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
case BFD_RELOC_MICROBLAZE_64_PLT:
case BFD_RELOC_MICROBLAZE_64_GOTOFF:
case BFD_RELOC_MICROBLAZE_32_GOTOFF:
+ case BFD_RELOC_MICROBLAZE_64_TLSGD:
+ case BFD_RELOC_MICROBLAZE_64_TLSLD:
+ case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
+ case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
+ case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
+ case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
+ case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
code = fixp->fx_r_type;
break;
diff --git a/include/ChangeLog b/include/ChangeLog
index 7b24264..51c446a 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2012-10-10 David Holsgrove <david.holsgrove@xilinx.com>
+
+ * elf/microblaze.h: Define microblaze TLS RELOC_NUMBER
+
2012-08-28 Matthew Gretton-Dann <matthew.gretton-dann@arm.com>
Apply mainline patches
diff --git a/include/elf/microblaze.h b/include/elf/microblaze.h
index d392231..0f73809 100644
--- a/include/elf/microblaze.h
+++ b/include/elf/microblaze.h
@@ -50,6 +50,14 @@ START_RELOC_NUMBERS (elf_microblaze_reloc_type)
RELOC_NUMBER (R_MICROBLAZE_GOTOFF_64, 19) /* Offset relative to GOT. */
RELOC_NUMBER (R_MICROBLAZE_GOTOFF_32, 20) /* Offset relative to GOT. */
RELOC_NUMBER (R_MICROBLAZE_COPY, 21) /* Runtime copy. */
+ RELOC_NUMBER (R_MICROBLAZE_TLS, 22) /* TLS Reloc */
+ RELOC_NUMBER (R_MICROBLAZE_TLSGD, 23) /* TLS General Dynamic */
+ RELOC_NUMBER (R_MICROBLAZE_TLSLD, 24) /* TLS Local Dynamic */
+ RELOC_NUMBER (R_MICROBLAZE_TLSDTPMOD32, 25) /* TLS Module ID */
+ RELOC_NUMBER (R_MICROBLAZE_TLSDTPREL32, 26) /* TLS Offset Within TLS Block */
+ RELOC_NUMBER (R_MICROBLAZE_TLSDTPREL64, 27) /* TLS Offset Within TLS Block */
+ RELOC_NUMBER (R_MICROBLAZE_TLSGOTTPREL32, 28) /* TLS Offset From Thread Pointer */
+ RELOC_NUMBER (R_MICROBLAZE_TLSTPREL32, 29) /* TLS Offset From Thread Pointer */
END_RELOC_NUMBERS (R_MICROBLAZE_max)
--
1.7.0.4