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:
parent
3e3420f6a1
commit
69b06cc85f
@ -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>
|
||||
|
||||
PR binutils/14933
|
||||
|
@ -5071,6 +5071,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,
|
||||
|
@ -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,40 @@ 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
|
||||
|
||||
/* 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 +911,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 +943,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 +1178,182 @@ 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;
|
||||
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)
|
||||
{
|
||||
Elf_Internal_Rela outrel;
|
||||
bfd_byte *loc;
|
||||
if (htab->srelgot == NULL)
|
||||
abort ();
|
||||
outrel.r_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;
|
||||
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 (htab->sgotplt != NULL && h != NULL
|
||||
&& h->got.offset != (bfd_vma) -1)
|
||||
if (local_got_offsets == NULL)
|
||||
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,
|
||||
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;
|
||||
if (! info->shared)
|
||||
{
|
||||
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= */ 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
|
||||
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,
|
||||
contents + offset + endian);
|
||||
bfd_put_16 (input_bfd, relocation & 0xffff,
|
||||
contents + offset + endian + INST_WORD_SIZE);
|
||||
|
||||
unresolved_reloc = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1064,6 +1383,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:
|
||||
@ -1941,6 +2268,33 @@ 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
|
||||
@ -1977,6 +2331,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);
|
||||
@ -2012,6 +2367,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)
|
||||
{
|
||||
@ -2023,25 +2385,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;
|
||||
|
||||
@ -2105,45 +2454,16 @@ 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
|
||||
@ -2274,6 +2594,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);
|
||||
}
|
||||
|
||||
@ -2492,8 +2814,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.
|
||||
@ -2505,15 +2829,43 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
|
||||
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;
|
||||
|
||||
@ -2611,6 +2963,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)
|
||||
@ -2650,17 +3003,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)
|
||||
{
|
||||
if (*local_got > 0)
|
||||
{
|
||||
*local_got = s->size;
|
||||
s->size += 4;
|
||||
if (info->shared)
|
||||
srel->size += sizeof (Elf32_External_Rela);
|
||||
for (; local_got < end_local_got; ++local_got, ++lgot_masks)
|
||||
{
|
||||
if (*local_got > 0)
|
||||
{
|
||||
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;
|
||||
@ -2671,6 +3043,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. */
|
||||
@ -2789,6 +3171,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)
|
||||
@ -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 *srela;
|
||||
Elf_Internal_Rela rela;
|
||||
bfd_byte *loc;
|
||||
bfd_vma offset;
|
||||
|
||||
/* This symbol has an entry in the global offset table. Set it
|
||||
up. */
|
||||
@ -2874,8 +3259,7 @@ 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
|
||||
@ -2888,22 +3272,25 @@ microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
|
||||
&& 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);
|
||||
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
|
||||
{
|
||||
rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_GLOB_DAT);
|
||||
rela.r_addend = 0;
|
||||
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,
|
||||
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)
|
||||
@ -3073,7 +3460,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
|
||||
#define elf_info_to_howto microblaze_elf_info_to_howto
|
||||
#define elf_info_to_howto_rel NULL
|
||||
|
||||
|
@ -2420,6 +2420,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_GOT_LD_PREL19",
|
||||
"BFD_RELOC_AARCH64_ADR_GOT_PAGE",
|
||||
|
39
bfd/reloc.c
39
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
|
||||
|
@ -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>
|
||||
|
||||
* config/tc-aarch64.c (exp_has_bignum_p): Remove.
|
||||
|
@ -81,7 +81,12 @@ 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 TLSGOTTPREL_OFFSET 15
|
||||
#define TLSTPREL_OFFSET 16
|
||||
|
||||
/* Initialize the 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 }, /* 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,75 @@ 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 +689,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,26 +700,18 @@ 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;
|
||||
}
|
||||
{
|
||||
atp = NULL;
|
||||
e->X_md = 0;
|
||||
ilen = 0;
|
||||
}
|
||||
*atp = 0;
|
||||
}
|
||||
else
|
||||
@ -655,6 +727,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 +747,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 +867,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,12 +1022,8 @@ 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;
|
||||
if (exp.X_md != 0)
|
||||
subtype = get_imm_otype(exp.X_md);
|
||||
else
|
||||
subtype = opcode->inst_offset_type;
|
||||
|
||||
@ -1436,12 +1514,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;
|
||||
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 +1580,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 +1652,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 +1922,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 +2121,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 +2304,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 +2397,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;
|
||||
|
||||
|
@ -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>
|
||||
|
||||
* demangle.h (enum demangle_component_type): Add
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user