diff options
author | Bob Wilson <bob.wilson@acm.org> | 2008-08-20 23:28:59 +0000 |
---|---|---|
committer | Bob Wilson <bob.wilson@acm.org> | 2008-08-20 23:28:59 +0000 |
commit | 28dbbc02031be5f7192eeaa31d2c59c220299b47 (patch) | |
tree | 037084a86719bba0b1cd5e858453c04280c760e9 /gas/config | |
parent | f2f0e013fcee59c041f9018523a20729f4ae212e (diff) | |
download | gdb-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')
-rw-r--r-- | gas/config/tc-xtensa.c | 126 | ||||
-rw-r--r-- | gas/config/xtensa-istack.h | 4 | ||||
-rw-r--r-- | gas/config/xtensa-relax.c | 17 | ||||
-rw-r--r-- | gas/config/xtensa-relax.h | 6 |
4 files changed, 141 insertions, 12 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; diff --git a/gas/config/xtensa-istack.h b/gas/config/xtensa-istack.h index 0bd0974..ebbb4f0 100644 --- a/gas/config/xtensa-istack.h +++ b/gas/config/xtensa-istack.h @@ -1,5 +1,5 @@ /* Declarations for stacks of tokenized Xtensa instructions. - Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -49,6 +49,8 @@ typedef struct tinsn_struct bfd_boolean loc_directive_seen; struct dwarf2_line_info debug_line; + expressionS tls_reloc; + /* Filled out by relaxation_requirements: */ enum xtensa_relax_statesE subtype; int literal_space; diff --git a/gas/config/xtensa-relax.c b/gas/config/xtensa-relax.c index 89a53d3..8f49afa 100644 --- a/gas/config/xtensa-relax.c +++ b/gas/config/xtensa-relax.c @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -645,13 +645,13 @@ append_op (BuildInstr *bi, BuildOp *b_op) static void -append_literal_op (BuildInstr *bi, unsigned op1) +append_literal_op (BuildInstr *bi, unsigned op1, unsigned src_op) { BuildOp *b_op = (BuildOp *) xmalloc (sizeof (BuildOp)); b_op->op_num = op1; b_op->typ = OP_LITERAL; - b_op->op_data = 0; + b_op->op_data = src_op; b_op->next = NULL; append_op (bi, b_op); } @@ -1594,6 +1594,7 @@ build_transition (insn_pattern *initial_insn, TransitionRule *tr = NULL; xtensa_opcode opcode; xtensa_isa isa = xtensa_default_isa; + BuildInstr *literal_bi; opname_map_e *op1; opname_map_e *op2; @@ -1706,6 +1707,7 @@ build_transition (insn_pattern *initial_insn, can be used before they are defined. Also there are a number of special operands (e.g., HI24S). */ + literal_bi = NULL; for (r = replace_insns->head; r != NULL; r = r->next) { BuildInstr *bi; @@ -1730,6 +1732,7 @@ build_transition (insn_pattern *initial_insn, bi->typ = INSTR_LITERAL_DEF; if (operand_count != 1) as_fatal (_("expected one operand for generated literal")); + literal_bi = bi; } else if (strcmp (opcode_name, "LABEL") == 0) { @@ -1768,7 +1771,13 @@ build_transition (insn_pattern *initial_insn, if (op_is_constant (op)) append_constant_op (bi, op->operand_num, op_get_constant (op)); else if (strcmp (op->operand_name, "%LITERAL") == 0) - append_literal_op (bi, op->operand_num); + { + if (! literal_bi || ! literal_bi->ops || literal_bi->ops->next) + as_fatal (_("opcode '%s': cannot find literal definition"), + opcode_name); + append_literal_op (bi, op->operand_num, + literal_bi->ops->op_data); + } else if (strcmp (op->operand_name, "%LABEL") == 0) append_label_op (bi, op->operand_num); else if (op->operand_name[0] == 'a' diff --git a/gas/config/xtensa-relax.h b/gas/config/xtensa-relax.h index 74b4ae8..14898c9 100644 --- a/gas/config/xtensa-relax.h +++ b/gas/config/xtensa-relax.h @@ -1,5 +1,5 @@ /* Table of relaxations for Xtensa assembly. - Copyright 2003, 2004, 2007 Free Software Foundation, Inc. + Copyright 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -135,7 +135,9 @@ struct build_op OPERAND: op_data is the field in the source instruction to take the value from and encode in the op_num field here. - LITERAL or LABEL: unused. */ + LITERAL: op_data is field in the source + instruction that is stored in the literal. + LABEL: unused. */ BuildOp *next; }; |