aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-xtensa.c
diff options
context:
space:
mode:
authorBob Wilson <bob.wilson@acm.org>2008-08-20 23:28:59 +0000
committerBob Wilson <bob.wilson@acm.org>2008-08-20 23:28:59 +0000
commit28dbbc02031be5f7192eeaa31d2c59c220299b47 (patch)
tree037084a86719bba0b1cd5e858453c04280c760e9 /gas/config/tc-xtensa.c
parentf2f0e013fcee59c041f9018523a20729f4ae212e (diff)
downloadgdb-28dbbc02031be5f7192eeaa31d2c59c220299b47.zip
gdb-28dbbc02031be5f7192eeaa31d2c59c220299b47.tar.gz
gdb-28dbbc02031be5f7192eeaa31d2c59c220299b47.tar.bz2
2008-08-20 Bob Wilson <bob.wilson@acm.org>
bfd/ * elf-bfd.h (elf_object_id): Add XTENSA_ELF_TDATA. * elf32-xtensa.c (elf_howto_table): Add TLS relocations. (elf_xtensa_reloc_type_lookup): Likewise. (TCB_SIZE): Define. (elf_xtensa_link_hash_entry): New. (GOT_UNKNOWN, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE, GOT_TLS_ANY): Define. (elf_xtensa_hash_entry): Define. (elf_xtensa_obj_tdata): New. (elf_xtensa_tdata): Define. (elf_xtensa_local_got_tls_type): Define. (elf_xtensa_local_tlsfunc_refcounts): Define. (is_xtensa_elf): Define. (elf_xtensa_mkobject): New. (elf_xtensa_link_hash_table): Add tlsbase field. (elf_xtensa_link_hash_newfunc): New. (elf_xtensa_link_hash_table_create): Use elf_xtensa_link_hash_newfunc. Create an entry for "_TLS_MODULE_BASE_" and save it in tlsbase field. (elf_xtensa_copy_indirect_symbol): New. (elf_xtensa_check_relocs): Rewrite to handle TLS relocations. (elf_xtensa_gc_sweep_hook): Likewise. (elf_xtensa_allocate_dynrelocs): Optimize away GOT entries for TLSDESC_FN relocations when an IE reference is seen. (elf_xtensa_allocate_local_got_size): Likewise. (elf_xtensa_always_size_sections): New. (dtpoff_base, tpoff): New. (elf_xtensa_do_reloc): Handle TLS relocations. (replace_tls_insn): New. (IS_XTENSA_TLS_RELOC): Define. (elf_xtensa_relocate_section): Handle TLS relocations. (get_indirect_call_dest_reg): New. (bfd_elf32_mkobject): Define. (elf_backend_always_size_sections): New. (elf_backend_copy_indirect_symbol): New. * reloc.c (BFD_RELOC_XTENSA_TLSDESC_FN, BFD_RELOC_XTENSA_TLSDESC_ARG) (BFD_RELOC_XTENSA_TLS_DTPOFF, BFD_RELOC_XTENSA_TLS_TPOFF) (BFD_RELOC_XTENSA_TLS_FUNC, BFD_RELOC_XTENSA_TLS_ARG) (BFD_RELOC_XTENSA_TLS_CALL): New. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. gas/ * config/tc-xtensa.c (O_tlsfunc, O_tlsarg, O_tlscall): Define. (O_tpoff, O_dtpoff): Define. (suffix_relocs): Add entries for TLS suffixes. (xtensa_elf_cons): Check for invalid use of TLS relocations. (map_operator_to_reloc): Add is_literal parameter and use it to control translating TLS instruction relocations to the corresponding literal relocations. (xg_valid_literal_expression): Allow TLS operators. (xg_build_to_insn): Copy TLS operators from pseudo-instruction operands to generated literals. (xg_assemble_literal): Handle TLS operators. Update call to map_operator_to_reloc. (md_assemble): Handle CALLXn.TLS pseudo-instruction. (md_apply_fix): Handle TLS relocations. (emit_single_op): Handle TLS operators. (convert_frag_immed): Update call to map_operator_to_reloc. (vinsn_to_insnbuf): Emit relocations for TLS-related instructions. * config/xtensa-istack.h (tinsn_struct): Add tls_reloc field. * config/xtensa-relax.c (append_literal_op): Add src_op parameter to initialize the op_data field of the BuildOp. (build_transition): Use it here to record the source operand corresponding to a generated literal. * config/xtensa-relax.h (build_op): Comment op_data use for literals. include/elf/ * xtensa.h (R_XTENSA_TLSDESC_FN, R_XTENSA_TLSDESC_ARG) (R_XTENSA_TLS_DTPOFF, R_XTENSA_TLS_TPOFF, R_XTENSA_TLS_FUNC) (R_XTENSA_TLS_ARG, R_XTENSA_TLS_CALL): New. ld/testsuite/ * ld-xtensa/tlsbin.dd, ld-xtensa/tlsbin.rd, ld-xtensa/tlsbin.s, ld-xtensa/tlsbin.sd, ld-xtensa/tlsbin.td, ld-xtensa/tlslib.s, ld-xtensa/tlspic.dd, ld-xtensa/tlspic.rd, ld-xtensa/tlspic.sd, ld-xtensa/tlspic.td, ld-xtensa/tlspic1.s, ld-xtensa/tlspic2.s: New. * ld-xtensa/xtensa.exp: Run them.
Diffstat (limited to 'gas/config/tc-xtensa.c')
-rw-r--r--gas/config/tc-xtensa.c126
1 files changed, 121 insertions, 5 deletions
diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
index d2753bb..b893cef 100644
--- a/gas/config/tc-xtensa.c
+++ b/gas/config/tc-xtensa.c
@@ -356,6 +356,11 @@ op_placement_info_table op_placement_table;
#define O_hi16 O_md2 /* use high 16 bits of symbolic value */
#define O_lo16 O_md3 /* use low 16 bits of symbolic value */
#define O_pcrel O_md4 /* value is a PC-relative offset */
+#define O_tlsfunc O_md5 /* TLS_FUNC/TLSDESC_FN relocation */
+#define O_tlsarg O_md6 /* TLS_ARG/TLSDESC_ARG relocation */
+#define O_tlscall O_md7 /* TLS_CALL relocation */
+#define O_tpoff O_md8 /* TPOFF relocation */
+#define O_dtpoff O_md9 /* DTPOFF relocation */
struct suffix_reloc_map
{
@@ -373,6 +378,11 @@ static struct suffix_reloc_map suffix_relocs[] =
SUFFIX_MAP ("h", BFD_RELOC_HI16, O_hi16),
SUFFIX_MAP ("plt", BFD_RELOC_XTENSA_PLT, O_pltrel),
SUFFIX_MAP ("pcrel", BFD_RELOC_32_PCREL, O_pcrel),
+ SUFFIX_MAP ("tlsfunc", BFD_RELOC_XTENSA_TLS_FUNC, O_tlsfunc),
+ SUFFIX_MAP ("tlsarg", BFD_RELOC_XTENSA_TLS_ARG, O_tlsarg),
+ SUFFIX_MAP ("tlscall", BFD_RELOC_XTENSA_TLS_CALL, O_tlscall),
+ SUFFIX_MAP ("tpoff", BFD_RELOC_XTENSA_TLS_TPOFF, O_tpoff),
+ SUFFIX_MAP ("dtpoff", BFD_RELOC_XTENSA_TLS_DTPOFF, O_dtpoff),
{ (char *) 0, 0, BFD_RELOC_UNUSED, 0 }
};
@@ -1553,6 +1563,10 @@ xtensa_elf_cons (int nbytes)
else if (nbytes != (int) bfd_get_reloc_size (reloc_howto))
as_bad (_("%s relocations do not fit in %d bytes"),
reloc_howto->name, nbytes);
+ else if (reloc == BFD_RELOC_XTENSA_TLS_FUNC
+ || reloc == BFD_RELOC_XTENSA_TLS_ARG
+ || reloc == BFD_RELOC_XTENSA_TLS_CALL)
+ as_bad (_("invalid use of %s relocation"), reloc_howto->name);
else
{
char *p = frag_more ((int) nbytes);
@@ -1665,7 +1679,7 @@ map_suffix_reloc_to_operator (bfd_reloc_code_real_type reloc)
/* Find the matching reloc type. */
static bfd_reloc_code_real_type
-map_operator_to_reloc (unsigned char operator)
+map_operator_to_reloc (unsigned char operator, bfd_boolean is_literal)
{
struct suffix_reloc_map *sfx;
bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
@@ -1679,6 +1693,14 @@ map_operator_to_reloc (unsigned char operator)
}
}
+ if (is_literal)
+ {
+ if (reloc == BFD_RELOC_XTENSA_TLS_FUNC)
+ return BFD_RELOC_XTENSA_TLSDESC_FN;
+ else if (reloc == BFD_RELOC_XTENSA_TLS_ARG)
+ return BFD_RELOC_XTENSA_TLSDESC_ARG;
+ }
+
if (reloc == BFD_RELOC_UNUSED)
return BFD_RELOC_32;
@@ -3149,6 +3171,10 @@ xg_valid_literal_expression (const expressionS *exp)
case O_subtract:
case O_pltrel:
case O_pcrel:
+ case O_tlsfunc:
+ case O_tlsarg:
+ case O_tpoff:
+ case O_dtpoff:
return TRUE;
default:
return FALSE;
@@ -3347,6 +3373,9 @@ xg_build_to_insn (TInsn *targ, TInsn *insn, BuildInstr *bi)
case OP_LITERAL:
sym = get_special_literal_symbol ();
set_expr_symbol_offset (&targ->tok[op_num], sym, 0);
+ if (insn->tok[op_data].X_op == O_tlsfunc
+ || insn->tok[op_data].X_op == O_tlsarg)
+ copy_expr (&targ->tls_reloc, &insn->tok[op_data]);
break;
case OP_LABEL:
sym = get_special_label_symbol ();
@@ -4062,9 +4091,13 @@ xg_assemble_literal (/* const */ TInsn *insn)
pcrel = TRUE;
/* fall through */
case O_pltrel:
+ case O_tlsfunc:
+ case O_tlsarg:
+ case O_tpoff:
+ case O_dtpoff:
p = frag_more (litsize);
xtensa_set_frag_assembly_state (frag_now);
- reloc = map_operator_to_reloc (emit_val->X_op);
+ reloc = map_operator_to_reloc (emit_val->X_op, TRUE);
if (emit_val->X_add_symbol)
emit_val->X_op = O_symbol;
else
@@ -5310,8 +5343,58 @@ md_assemble (char *str)
orig_insn.insn_type = ITYPE_INSN;
orig_insn.ntok = 0;
orig_insn.is_specific_opcode = (has_underbar || !use_transform ());
-
orig_insn.opcode = xtensa_opcode_lookup (isa, opname);
+
+ /* Special case: Check for "CALLXn.TLS" psuedo op. If found, grab its
+ extra argument and set the opcode to "CALLXn". */
+ if (orig_insn.opcode == XTENSA_UNDEFINED
+ && strncasecmp (opname, "callx", 5) == 0)
+ {
+ unsigned long window_size;
+ char *suffix;
+
+ window_size = strtoul (opname + 5, &suffix, 10);
+ if (suffix != opname + 5
+ && (window_size == 0
+ || window_size == 4
+ || window_size == 8
+ || window_size == 12)
+ && strcasecmp (suffix, ".tls") == 0)
+ {
+ switch (window_size)
+ {
+ case 0: orig_insn.opcode = xtensa_callx0_opcode; break;
+ case 4: orig_insn.opcode = xtensa_callx4_opcode; break;
+ case 8: orig_insn.opcode = xtensa_callx8_opcode; break;
+ case 12: orig_insn.opcode = xtensa_callx12_opcode; break;
+ }
+
+ if (num_args != 2)
+ as_bad (_("wrong number of operands for '%s'"), opname);
+ else
+ {
+ bfd_reloc_code_real_type reloc;
+ char *old_input_line_pointer;
+ expressionS *tok = &orig_insn.tls_reloc;
+ segT t;
+
+ old_input_line_pointer = input_line_pointer;
+ input_line_pointer = arg_strings[num_args - 1];
+
+ t = expression (tok);
+ if (tok->X_op == O_symbol
+ && ((reloc = xtensa_elf_suffix (&input_line_pointer, tok))
+ == BFD_RELOC_XTENSA_TLS_CALL))
+ tok->X_op = map_suffix_reloc_to_operator (reloc);
+ else
+ as_bad (_("bad relocation expression for '%s'"), opname);
+
+ input_line_pointer = old_input_line_pointer;
+ num_args -= 1;
+ }
+ }
+ }
+
if (orig_insn.opcode == XTENSA_UNDEFINED)
{
xtensa_format fmt = xtensa_format_lookup (isa, opname);
@@ -5726,6 +5809,15 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
break;
+ case BFD_RELOC_XTENSA_TLSDESC_FN:
+ case BFD_RELOC_XTENSA_TLSDESC_ARG:
+ case BFD_RELOC_XTENSA_TLS_TPOFF:
+ case BFD_RELOC_XTENSA_TLS_DTPOFF:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ md_number_to_chars (fixpos, 0, fixP->fx_size);
+ fixP->fx_no_overflow = 0; /* Use the standard overflow check. */
+ break;
+
case BFD_RELOC_XTENSA_SLOT0_OP:
case BFD_RELOC_XTENSA_SLOT1_OP:
case BFD_RELOC_XTENSA_SLOT2_OP:
@@ -5766,6 +5858,9 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
break;
case BFD_RELOC_XTENSA_ASM_EXPAND:
+ case BFD_RELOC_XTENSA_TLS_FUNC:
+ case BFD_RELOC_XTENSA_TLS_ARG:
+ case BFD_RELOC_XTENSA_TLS_CALL:
case BFD_RELOC_XTENSA_SLOT0_ALT:
case BFD_RELOC_XTENSA_SLOT1_ALT:
case BFD_RELOC_XTENSA_SLOT2_ALT:
@@ -6663,7 +6758,11 @@ emit_single_op (TInsn *orig_insn)
|| orig_insn->opcode == xtensa_movi_n_opcode)
&& !cur_vinsn.inside_bundle
&& (orig_insn->tok[1].X_op == O_symbol
- || orig_insn->tok[1].X_op == O_pltrel)
+ || orig_insn->tok[1].X_op == O_pltrel
+ || orig_insn->tok[1].X_op == O_tlsfunc
+ || orig_insn->tok[1].X_op == O_tlsarg
+ || orig_insn->tok[1].X_op == O_tpoff
+ || orig_insn->tok[1].X_op == O_dtpoff)
&& !orig_insn->is_specific_opcode && use_transform ())
xg_assembly_relax (&istack, orig_insn, now_seg, frag_now, 0, 1, 0);
else
@@ -9527,7 +9626,7 @@ convert_frag_immed (segT segP,
/* Add a fixup. */
target_seg = S_GET_SEGMENT (lit_sym);
assert (target_seg);
- reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op);
+ reloc_type = map_operator_to_reloc (tinsn->tok[0].X_op, TRUE);
fix_new_exp_in_seg (target_seg, 0, lit_frag, 0, 4,
&tinsn->tok[0], FALSE, reloc_type);
break;
@@ -11527,12 +11626,29 @@ vinsn_to_insnbuf (vliw_insn *vinsn,
for (slot = 0; slot < vinsn->num_slots; slot++)
{
TInsn *tinsn = &vinsn->slots[slot];
+ expressionS *tls_reloc = &tinsn->tls_reloc;
bfd_boolean tinsn_has_fixup =
tinsn_to_slotbuf (vinsn->format, slot, tinsn,
vinsn->slotbuf[slot]);
xtensa_format_set_slot (isa, fmt, slot,
insnbuf, vinsn->slotbuf[slot]);
+ if (tls_reloc->X_op != O_illegal)
+ {
+ if (vinsn->num_slots != 1)
+ as_bad (_("TLS relocation not allowed in FLIX bundle"));
+ else if (record_fixup)
+ /* Instructions that generate TLS relocations should always be
+ relaxed in the front-end. If "record_fixup" is set, then this
+ function is being called during back-end relaxation, so flag
+ the unexpected behavior as an error. */
+ as_bad (_("unexpected TLS relocation"));
+ else
+ fix_new (fragP, frag_offset - fragP->fr_literal,
+ xtensa_format_length (isa, fmt),
+ tls_reloc->X_add_symbol, tls_reloc->X_add_number,
+ FALSE, map_operator_to_reloc (tls_reloc->X_op, FALSE));
+ }
if (tinsn_has_fixup)
{
int i;