Microblaze: Add support for handling TLS symbol suffixes and generating

TLS relocs for General Dynamic and Local Dynamic models.

bfd/Changelog
          * reloc.c: Add new relocations
          * bfd-in2.h: Regenerated
          * libbfd.h: Regenerated
          * elf32-microblaze.c (microblaze_elf_howto_raw):
            Add TLS relocations
            (microblaze_elf_reloc_type_lookup): Likewise
            (elf32_mb_link_hash_entry): define TLS reference types
            (elf32_mb_link_hash_table): add TLS Local dynamic GOT entry
            #define has_tls_reloc if section has TLS relocs
            (dtprel_base), (check_unique_offset): New
            (microblaze_elf_output_dynamic_relocation): output simple
            dynamic relocation into SRELOC.
            (microblaze_elf_relocate_section): Accommodate TLS relocations.
            (microblaze_elf_check_relocs): Likewise
            (update_local_sym_info): New
            (microblaze_elf_copy_indirect_symbol): Add tls_mask.
            (allocate_dynrelocs): Handle TLS symbol
            (microblaze_elf_size_dynamic_sections): Set size and offset
            (microblaze_elf_finish_dynamic_symbol): Use
             microblaze_elf_output_dynamic_relocation

gas/Changelog
          * config/tc-microblaze.c: Define TLS offsets
            (md_relax_table): Add TLS offsets
            (imm_types), (match_imm), (get_imm_otype): New to support
            TLS offsets.
            (tc_microblaze_fix_adjustable): Add TLS relocs.
            (md_convert_frag): Support TLS offsets.
            (md_apply_fix), (md_estimate_size_before_relax), (tc_gen_reloc):
            Add TLS relocs

include/Changelog
          * elf/microblaze.h: Add TLS relocs to START_RELOC_NUMBERS
This commit is contained in:
Michael Eager 2012-12-11 16:56:53 +00:00
parent 3e3420f6a1
commit 69b06cc85f
9 changed files with 788 additions and 169 deletions

View File

@ -1,3 +1,25 @@
2012-12-10 Edgar E. Iglesias <edgar.iglesias@gmail.com>
* reloc.c (MICROBLAZE): Document new relocations
* bfd-in2.h: Regenerated
* libbfd.h: Regenerated
* elf32-microblaze.c (microblaze_elf_howto_raw): Add TLS relocations
(microblaze_elf_reloc_type_lookup): Likewise
(elf32_mb_link_hash_entry): define TLS reference types
(elf32_mb_link_hash_table): add TLS Local dynamic GOT entry
#define has_tls_reloc if section has TLS relocs
(dtprel_base), (check_unique_offset): New
(microblaze_elf_output_dynamic_relocation): output simple
dynamic relocation into SRELOC.
(microblaze_elf_relocate_section): Accommodate TLS relocations.
(microblaze_elf_check_relocs): Likewise
(update_local_sym_info): New
(microblaze_elf_copy_indirect_symbol): Add tls_mask.
(allocate_dynrelocs): Handle TLS symbol
(microblaze_elf_size_dynamic_sections): Set size and offset
(microblaze_elf_finish_dynamic_symbol): Use
microblaze_elf_output_dynamic_relocation
2012-12-09 H.J. Lu <hongjiu.lu@intel.com> 2012-12-09 H.J. Lu <hongjiu.lu@intel.com>
PR binutils/14933 PR binutils/14933

View File

@ -5071,6 +5071,37 @@ value in a word. The relocation is relative offset from */
the dynamic object into the runtime process image. */ the dynamic object into the runtime process image. */
BFD_RELOC_MICROBLAZE_COPY, 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. /* AArch64 ADD immediate instruction, holding bits 0 to 11 of the address.
Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */ Used in conjunction with BFD_RELOC_AARCH64_ADR_HI21_PCREL. */
BFD_RELOC_AARCH64_ADD_LO12, BFD_RELOC_AARCH64_ADD_LO12,

View File

@ -370,6 +370,132 @@ static reloc_howto_type microblaze_elf_howto_raw[] =
0, /* Source Mask. */ 0, /* Source Mask. */
0x0000ffff, /* Dest Mask. */ 0x0000ffff, /* Dest Mask. */
FALSE), /* PC relative offset? */ 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 #ifndef NUM_ELEM
@ -461,6 +587,27 @@ microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
case BFD_RELOC_MICROBLAZE_32_GOTOFF: case BFD_RELOC_MICROBLAZE_32_GOTOFF:
microblaze_reloc = R_MICROBLAZE_GOTOFF_32; microblaze_reloc = R_MICROBLAZE_GOTOFF_32;
break; 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: case BFD_RELOC_MICROBLAZE_COPY:
microblaze_reloc = R_MICROBLAZE_COPY; microblaze_reloc = R_MICROBLAZE_COPY;
break; break;
@ -550,8 +697,21 @@ struct elf32_mb_link_hash_entry
/* Track dynamic relocs copied for this symbol. */ /* Track dynamic relocs copied for this symbol. */
struct elf32_mb_dyn_relocs *dyn_relocs; 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)) #define elf32_mb_hash_entry(ent) ((struct elf32_mb_link_hash_entry *)(ent))
/* ELF linker hash table. */ /* ELF linker hash table. */
@ -571,8 +731,17 @@ struct elf32_mb_link_hash_table
/* Small local sym to section mapping cache. */ /* Small local sym to section mapping cache. */
struct sym_cache sym_sec; 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. */ /* Get the ELF linker hash table from a link_info structure. */
#define elf32_mb_hash_table(p) \ #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 = (struct elf32_mb_link_hash_entry *) entry;
eh->dyn_relocs = NULL; eh->dyn_relocs = NULL;
eh->tls_mask = 0;
} }
return entry; return entry;
@ -654,6 +824,40 @@ microblaze_elf_final_sdp (struct bfd_link_info *info)
+ h->u.def.section->output_offset); + 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
/* 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 /* This code is taken from elf32-m32r.c
There is some attempt to make this function usable for many architectures, 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], both USE_REL and USE_RELA ['twould be nice if such a critter existed],
@ -707,6 +911,7 @@ microblaze_elf_relocate_section (bfd *output_bfd,
bfd_boolean ret = TRUE; bfd_boolean ret = TRUE;
asection *sreloc; asection *sreloc;
bfd_vma *local_got_offsets; bfd_vma *local_got_offsets;
unsigned int tls_type;
if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1]) if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1])
microblaze_elf_howto_init (); microblaze_elf_howto_init ();
@ -738,6 +943,8 @@ microblaze_elf_relocate_section (bfd *output_bfd,
h = NULL; h = NULL;
r_type = ELF32_R_TYPE (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info);
tls_type = 0;
if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max) if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max)
{ {
(*_bfd_error_handler) (_("%s: unknown relocation type %d"), (*_bfd_error_handler) (_("%s: unknown relocation type %d"),
@ -971,70 +1178,182 @@ microblaze_elf_relocate_section (bfd *output_bfd,
break; 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: 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) if (htab->sgot == NULL)
abort (); abort ();
if (h == NULL)
{
bfd_vma off;
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);
if (info->shared) indx = 0;
{ offp = NULL;
Elf_Internal_Rela outrel;
bfd_byte *loc; /* 1. Identify GOT Offset;
if (htab->srelgot == NULL) 2. Compute Static Values
abort (); 3. Process Module Id, Process Offset
outrel.r_offset = (htab->sgot->output_section->vma 4. Fixup Relocation with GOT offset value. */
+ htab->sgot->output_offset
+ off); /* 1. Determine GOT Offset to use : TLS_LD, global, local */
outrel.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL); if (IS_TLS_LD (tls_type))
outrel.r_addend = relocation + addend; offp = &htab->tlsld_got.offset;
loc = htab->srelgot->contents; else if (h != NULL)
loc += htab->srelgot->reloc_count++ {
* sizeof (Elf32_External_Rela); if (htab->sgotplt != NULL && h->got.offset != (bfd_vma) -1)
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); offp = &h->got.offset;
} else
local_got_offsets[r_symndx] |= 1; abort ();
}
relocation = htab->sgot->output_section->vma
+ htab->sgot->output_offset + off
- htab->sgotplt->output_section->vma
- htab->sgotplt->output_offset;
unresolved_reloc = FALSE;
} }
else else
{ {
if (htab->sgotplt != NULL && h != NULL if (local_got_offsets == NULL)
&& h->got.offset != (bfd_vma) -1) abort ();
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))
{ {
bfd_put_32 (output_bfd, relocation + addend, if (! info->shared)
htab->sgot->contents + h->got.offset); {
relocation = htab->sgot->output_section->vma bfd_put_32 (output_bfd, 1, htab->sgot->contents + off);
+ htab->sgot->output_offset }
+ h->got.offset else
- htab->sgotplt->output_section->vma {
- htab->sgotplt->output_offset; microblaze_elf_output_dynamic_relocation (output_bfd,
unresolved_reloc = FALSE; htab->srelgot, htab->srelgot->reloc_count++,
/* symindex= */ 0, R_MICROBLAZE_TLSDTPMOD32,
got_offset, 0);
}
}
else if (IS_TLS_GD(tls_type))
{
if (! need_relocs)
{
bfd_put_32 (output_bfd, 1, htab->sgot->contents + off);
}
else
{
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 ();
got_offset = (htab->sgot->output_section->vma
+ htab->sgot->output_offset
+ 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)
{
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
{
bfd_put_32 (output_bfd, static_value,
htab->sgot->contents + off2);
}
} }
else else
abort (); /* ??? */ {
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;
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, bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
contents + offset + endian); contents + offset + endian);
bfd_put_16 (input_bfd, relocation & 0xffff, bfd_put_16 (input_bfd, relocation & 0xffff,
contents + offset + endian + INST_WORD_SIZE); contents + offset + endian + INST_WORD_SIZE);
unresolved_reloc = FALSE;
break; break;
} }
@ -1064,6 +1383,14 @@ microblaze_elf_relocate_section (bfd *output_bfd,
break; 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_PCREL :
case (int) R_MICROBLAZE_64: case (int) R_MICROBLAZE_64:
case (int) R_MICROBLAZE_32: case (int) R_MICROBLAZE_32:
@ -1941,6 +2268,33 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
return TRUE; 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. */ /* Look through the relocs for a section during the first phase. */
static bfd_boolean static bfd_boolean
@ -1977,6 +2331,7 @@ microblaze_elf_check_relocs (bfd * abfd,
unsigned int r_type; unsigned int r_type;
struct elf_link_hash_entry * h; struct elf_link_hash_entry * h;
unsigned long r_symndx; unsigned long r_symndx;
unsigned char tls_type = 0;
r_symndx = ELF32_R_SYM (rel->r_info); r_symndx = ELF32_R_SYM (rel->r_info);
r_type = ELF32_R_TYPE (rel->r_info); r_type = ELF32_R_TYPE (rel->r_info);
@ -2012,6 +2367,13 @@ microblaze_elf_check_relocs (bfd * abfd,
break; break;
/* This relocation requires .got entry. */ /* 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: case R_MICROBLAZE_GOT_64:
if (htab->sgot == NULL) if (htab->sgot == NULL)
{ {
@ -2023,25 +2385,12 @@ microblaze_elf_check_relocs (bfd * abfd,
if (h != NULL) if (h != NULL)
{ {
h->got.refcount += 1; h->got.refcount += 1;
elf32_mb_hash_entry (h)->tls_mask |= tls_type;
} }
else else
{ {
bfd_signed_vma *local_got_refcounts; if (! update_local_sym_info(abfd, symtab_hdr, r_symndx, tls_type) )
return FALSE;
/* 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;
} }
break; break;
@ -2105,45 +2454,16 @@ microblaze_elf_check_relocs (bfd * abfd,
if (sreloc == NULL) if (sreloc == NULL)
{ {
const char *name;
bfd *dynobj; 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) if (htab->elf.dynobj == NULL)
htab->elf.dynobj = abfd; htab->elf.dynobj = abfd;
dynobj = htab->elf.dynobj; 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) if (sreloc == NULL)
{ return FALSE;
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;
} }
/* If this is a global symbol, we count the number of /* If this is a global symbol, we count the number of
@ -2274,6 +2594,8 @@ microblaze_elf_copy_indirect_symbol (struct bfd_link_info *info,
eind->dyn_relocs = NULL; eind->dyn_relocs = NULL;
} }
edir->tls_mask |= eind->tls_mask;
_bfd_elf_link_hash_copy_indirect (info, dir, ind); _bfd_elf_link_hash_copy_indirect (info, dir, ind);
} }
@ -2492,8 +2814,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
h->needs_plt = 0; h->needs_plt = 0;
} }
eh = (struct elf32_mb_link_hash_entry *) h;
if (h->got.refcount > 0) if (h->got.refcount > 0)
{ {
unsigned int need;
asection *s; asection *s;
/* Make sure this symbol is output as a dynamic symbol. /* Make sure this symbol is output as a dynamic symbol.
@ -2505,15 +2829,43 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
return FALSE; return FALSE;
} }
s = htab->sgot; need = 0;
h->got.offset = s->size; if ((eh->tls_mask & TLS_TLS) != 0)
s->size += 4; {
htab->srelgot->size += sizeof (Elf32_External_Rela); /* 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 else
h->got.offset = (bfd_vma) -1; h->got.offset = (bfd_vma) -1;
eh = (struct elf32_mb_link_hash_entry *) h;
if (eh->dyn_relocs == NULL) if (eh->dyn_relocs == NULL)
return TRUE; return TRUE;
@ -2611,6 +2963,7 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
bfd_signed_vma *end_local_got; bfd_signed_vma *end_local_got;
bfd_size_type locsymcount; bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_hdr;
unsigned char *lgot_masks;
asection *srel; asection *srel;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
@ -2650,17 +3003,36 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
locsymcount = symtab_hdr->sh_info; locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount; end_local_got = local_got + locsymcount;
lgot_masks = (unsigned char *) end_local_got;
s = htab->sgot; s = htab->sgot;
srel = htab->srelgot; 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) if (*local_got > 0)
{ {
*local_got = s->size; unsigned int need = 0;
s->size += 4; if ((*lgot_masks & TLS_TLS) != 0)
if (info->shared) {
srel->size += sizeof (Elf32_External_Rela); 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 else
*local_got = (bfd_vma) -1; *local_got = (bfd_vma) -1;
@ -2671,6 +3043,16 @@ microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
sym dynamic relocs. */ sym dynamic relocs. */
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); 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) if (elf_hash_table (info)->dynamic_sections_created)
{ {
/* Make space for the trailing nop in .plt. */ /* Make space for the trailing nop in .plt. */
@ -2789,6 +3171,7 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
Elf_Internal_Sym *sym) Elf_Internal_Sym *sym)
{ {
struct elf32_mb_link_hash_table *htab; 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); htab = elf32_mb_hash_table (info);
if (htab == NULL) if (htab == NULL)
@ -2860,12 +3243,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 *sgot;
asection *srela; asection *srela;
Elf_Internal_Rela rela; bfd_vma offset;
bfd_byte *loc;
/* This symbol has an entry in the global offset table. Set it /* This symbol has an entry in the global offset table. Set it
up. */ up. */
@ -2874,8 +3259,7 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
srela = htab->srelgot; srela = htab->srelgot;
BFD_ASSERT (sgot != NULL && srela != NULL); BFD_ASSERT (sgot != NULL && srela != NULL);
rela.r_offset = (sgot->output_section->vma offset = (sgot->output_section->vma + sgot->output_offset
+ sgot->output_offset
+ (h->got.offset &~ (bfd_vma) 1)); + (h->got.offset &~ (bfd_vma) 1));
/* If this is a -Bsymbolic link, and the symbol is defined /* If this is a -Bsymbolic link, and the symbol is defined
@ -2888,22 +3272,25 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
&& h->def_regular) && h->def_regular)
{ {
asection *sec = h->root.u.def.section; asection *sec = h->root.u.def.section;
rela.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL); microblaze_elf_output_dynamic_relocation (output_bfd,
rela.r_addend = (h->root.u.def.value srela, srela->reloc_count++,
+ sec->output_section->vma /* symindex= */ 0,
+ sec->output_offset); R_MICROBLAZE_REL, offset,
h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
} }
else else
{ {
rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_GLOB_DAT); microblaze_elf_output_dynamic_relocation (output_bfd,
rela.r_addend = 0; 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)); 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) if (h->needs_copy)
@ -3073,7 +3460,7 @@ microblaze_elf_add_symbol_hook (bfd *abfd,
#define ELF_TARGET_ID MICROBLAZE_ELF_DATA #define ELF_TARGET_ID MICROBLAZE_ELF_DATA
#define ELF_MACHINE_CODE EM_MICROBLAZE #define ELF_MACHINE_CODE EM_MICROBLAZE
#define ELF_MACHINE_ALT1 EM_MICROBLAZE_OLD #define ELF_MACHINE_ALT1 EM_MICROBLAZE_OLD
#define ELF_MAXPAGESIZE 0x4 /* 4k, if we ever have 'em. */ #define ELF_MAXPAGESIZE 0x1000
#define elf_info_to_howto microblaze_elf_info_to_howto #define elf_info_to_howto microblaze_elf_info_to_howto
#define elf_info_to_howto_rel NULL #define elf_info_to_howto_rel NULL

View File

@ -2420,6 +2420,14 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_MICROBLAZE_64_GOTOFF", "BFD_RELOC_MICROBLAZE_64_GOTOFF",
"BFD_RELOC_MICROBLAZE_32_GOTOFF", "BFD_RELOC_MICROBLAZE_32_GOTOFF",
"BFD_RELOC_MICROBLAZE_COPY", "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_ADD_LO12",
"BFD_RELOC_AARCH64_GOT_LD_PREL19", "BFD_RELOC_AARCH64_GOT_LD_PREL19",
"BFD_RELOC_AARCH64_ADR_GOT_PAGE", "BFD_RELOC_AARCH64_ADR_GOT_PAGE",

View File

@ -5882,6 +5882,45 @@ ENUM
ENUMDOC ENUMDOC
This is used to tell the dynamic linker to copy the value out of This is used to tell the dynamic linker to copy the value out of
the dynamic object into the runtime process image. 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 ENUM
BFD_RELOC_AARCH64_ADD_LO12 BFD_RELOC_AARCH64_ADD_LO12

View File

@ -1,3 +1,13 @@
2012-12-11 Edgar E. Iglesias <edgar.iglesias@gmail.com>
* config/tc-microblaze.c: Define TLS offsets
(md_relax_table): Add TLS offsets
(imm_types), (match_imm), (get_imm_otype): New to support TLS offsets.
(tc_microblaze_fix_adjustable): Add TLS relocs.
(md_convert_frag): Support TLS offsets.
(md_apply_fix), (md_estimate_size_before_relax), (tc_gen_reloc):
Add TLS relocs
2012-12-06 Yufeng Zhang <yufeng.zhang@arm.com> 2012-12-06 Yufeng Zhang <yufeng.zhang@arm.com>
* config/tc-aarch64.c (exp_has_bignum_p): Remove. * config/tc-aarch64.c (exp_has_bignum_p): Remove.

View File

@ -81,7 +81,12 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
#define GOT_OFFSET 8 #define GOT_OFFSET 8
#define PLT_OFFSET 9 #define PLT_OFFSET 9
#define GOTOFF_OFFSET 10 #define GOTOFF_OFFSET 10
#define TLSGD_OFFSET 11
#define TLSLD_OFFSET 12
#define TLSDTPMOD_OFFSET 13
#define TLSDTPREL_OFFSET 14
#define TLSGOTTPREL_OFFSET 15
#define TLSTPREL_OFFSET 16
/* Initialize the relax table. */ /* Initialize the relax table. */
const relax_typeS md_relax_table[] = const relax_typeS md_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 }, /* 8: GOT_OFFSET. */
{ 0x7fffffff, 0x80000000, INST_WORD_SIZE*2, 0 }, /* 9: PLT_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 }, /* 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. */ static struct hash_control * opcode_hash_control; /* Opcode mnemonics. */
@ -599,9 +610,75 @@ parse_exp (char *s, expressionS *e)
} }
/* Symbol modifiers (@GOT, @PLT, @GOTOFF). */ /* Symbol modifiers (@GOT, @PLT, @GOTOFF). */
#define IMM_NONE 0
#define IMM_GOT 1 #define IMM_GOT 1
#define IMM_PLT 2 #define IMM_PLT 2
#define IMM_GOTOFF 3 #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; static symbolS * GOT_symbol;
@ -612,6 +689,9 @@ parse_imm (char * s, expressionS * e, int min, int max)
{ {
char *new_pointer; char *new_pointer;
char *atp; char *atp;
int itype, ilen;
ilen = 0;
/* Find the start of "@GOT" or "@PLT" suffix (if any) */ /* Find the start of "@GOT" or "@PLT" suffix (if any) */
for (atp = s; *atp != '@'; atp++) for (atp = s; *atp != '@'; atp++)
@ -620,26 +700,18 @@ parse_imm (char * s, expressionS * e, int min, int max)
if (*atp == '@') if (*atp == '@')
{ {
if (strncmp (atp + 1, "GOTOFF", 5) == 0) itype = match_imm (atp + 1, &ilen);
{ if (itype != 0)
*atp = 0; {
e->X_md = IMM_GOTOFF; *atp = 0;
} e->X_md = itype;
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;
}
else else
{ {
atp = NULL; atp = NULL;
e->X_md = 0; e->X_md = 0;
} ilen = 0;
}
*atp = 0; *atp = 0;
} }
else else
@ -655,6 +727,11 @@ parse_imm (char * s, expressionS * e, int min, int max)
new_pointer = parse_exp (s, e); 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) if (e->X_op == O_absent)
; /* An error message has already been emitted. */ ; /* An error message has already been emitted. */
else if ((e->X_op != O_constant && e->X_op != O_symbol) ) else if ((e->X_op != O_constant && e->X_op != O_symbol) )
@ -670,9 +747,7 @@ parse_imm (char * s, expressionS * e, int min, int max)
{ {
*atp = '@'; /* restore back (needed?) */ *atp = '@'; /* restore back (needed?) */
if (new_pointer >= atp) if (new_pointer >= atp)
new_pointer += (e->X_md == IMM_GOTOFF)?7:4; new_pointer += ilen + 1; /* sizeof (imm_suffix) + 1 for '@' */
/* sizeof("@GOTOFF", "@GOT" or "@PLT") */
} }
return new_pointer; return new_pointer;
} }
@ -792,7 +867,14 @@ tc_microblaze_fix_adjustable (struct fix *fixP)
if (fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOTOFF 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_32_GOTOFF
|| fixP->fx_r_type == BFD_RELOC_MICROBLAZE_64_GOT || 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 0;
return 1; return 1;
@ -940,12 +1022,8 @@ md_assemble (char * str)
opc = str_microblaze_rw_anchor; opc = str_microblaze_rw_anchor;
else else
opc = NULL; opc = NULL;
if (exp.X_md == IMM_GOT) if (exp.X_md != 0)
subtype = GOT_OFFSET; subtype = get_imm_otype(exp.X_md);
else if (exp.X_md == IMM_PLT)
subtype = PLT_OFFSET;
else if (exp.X_md == IMM_GOTOFF)
subtype = GOTOFF_OFFSET;
else else
subtype = opcode->inst_offset_type; subtype = opcode->inst_offset_type;
@ -1436,12 +1514,11 @@ md_assemble (char * str)
char *opc = NULL; char *opc = NULL;
relax_substateT subtype; relax_substateT subtype;
if (exp.X_md == IMM_GOT) if (exp.X_md != 0)
subtype = GOT_OFFSET; subtype = get_imm_otype(exp.X_md);
else if (exp.X_md == IMM_PLT)
subtype = PLT_OFFSET;
else else
subtype = opcode->inst_offset_type; subtype = opcode->inst_offset_type;
output = frag_var (rs_machine_dependent, output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */ isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */ isize, /* minm of 1 word. */
@ -1503,12 +1580,11 @@ md_assemble (char * str)
char *opc = NULL; char *opc = NULL;
relax_substateT subtype; relax_substateT subtype;
if (exp.X_md == IMM_GOT) if (exp.X_md != 0)
subtype = GOT_OFFSET; subtype = get_imm_otype(exp.X_md);
else if (exp.X_md == IMM_PLT) else
subtype = PLT_OFFSET;
else
subtype = opcode->inst_offset_type; subtype = opcode->inst_offset_type;
output = frag_var (rs_machine_dependent, output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */ isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */ isize, /* minm of 1 word. */
@ -1576,12 +1652,11 @@ md_assemble (char * str)
char *opc = NULL; char *opc = NULL;
relax_substateT subtype; relax_substateT subtype;
if (exp.X_md == IMM_GOT) if (exp.X_md != 0)
subtype = GOT_OFFSET; subtype = get_imm_otype(exp.X_md);
else if (exp.X_md == IMM_PLT) else
subtype = PLT_OFFSET; subtype = opcode->inst_offset_type;
else
subtype = opcode->inst_offset_type;
output = frag_var (rs_machine_dependent, output = frag_var (rs_machine_dependent,
isize * 2, /* maxm of 2 words. */ isize * 2, /* maxm of 2 words. */
isize, /* minm of 1 word. */ isize, /* minm of 1 word. */
@ -1847,6 +1922,24 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
fragP->fr_fix += INST_WORD_SIZE * 2; fragP->fr_fix += INST_WORD_SIZE * 2;
fragP->fr_var = 0; fragP->fr_var = 0;
break; 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: default:
abort (); abort ();
@ -2028,6 +2121,11 @@ md_apply_fix (fixS * fixP,
} }
break; 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_GOTPC:
case BFD_RELOC_MICROBLAZE_64_GOT: case BFD_RELOC_MICROBLAZE_64_GOT:
case BFD_RELOC_MICROBLAZE_64_PLT: case BFD_RELOC_MICROBLAZE_64_PLT:
@ -2206,11 +2304,16 @@ md_estimate_size_before_relax (fragS * fragP,
case GOT_OFFSET: case GOT_OFFSET:
case PLT_OFFSET: case PLT_OFFSET:
case GOTOFF_OFFSET: case GOTOFF_OFFSET:
case TLSGD_OFFSET:
case TLSLD_OFFSET:
case TLSTPREL_OFFSET:
case TLSDTPREL_OFFSET:
fragP->fr_var = INST_WORD_SIZE*2; fragP->fr_var = INST_WORD_SIZE*2;
break; break;
case DEFINED_RO_SEGMENT: case DEFINED_RO_SEGMENT:
case DEFINED_RW_SEGMENT: case DEFINED_RW_SEGMENT:
case DEFINED_PC_OFFSET: case DEFINED_PC_OFFSET:
case TLSDTPMOD_OFFSET:
fragP->fr_var = INST_WORD_SIZE; fragP->fr_var = INST_WORD_SIZE;
break; break;
default: default:
@ -2294,6 +2397,13 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp)
case BFD_RELOC_MICROBLAZE_64_PLT: case BFD_RELOC_MICROBLAZE_64_PLT:
case BFD_RELOC_MICROBLAZE_64_GOTOFF: case BFD_RELOC_MICROBLAZE_64_GOTOFF:
case BFD_RELOC_MICROBLAZE_32_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; code = fixp->fx_r_type;
break; break;

View File

@ -1,3 +1,7 @@
2012-12-11 Edgar E. Iglesias <edgar.iglesias@gmail.com>
* elf/microblaze.h: Add TLS relocs to START_RELOC_NUMBERS
2012-11-09 Jason Merrill <jason@redhat.com> 2012-11-09 Jason Merrill <jason@redhat.com>
* demangle.h (enum demangle_component_type): Add * demangle.h (enum demangle_component_type): Add

View File

@ -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_64, 19) /* Offset relative to GOT. */
RELOC_NUMBER (R_MICROBLAZE_GOTOFF_32, 20) /* 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_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) END_RELOC_NUMBERS (R_MICROBLAZE_max)