diff options
Diffstat (limited to 'binutils-2.24/gas/config/tc-tilegx.c')
-rw-r--r-- | binutils-2.24/gas/config/tc-tilegx.c | 1895 |
1 files changed, 0 insertions, 1895 deletions
diff --git a/binutils-2.24/gas/config/tc-tilegx.c b/binutils-2.24/gas/config/tc-tilegx.c deleted file mode 100644 index 19a04c27..00000000 --- a/binutils-2.24/gas/config/tc-tilegx.c +++ /dev/null @@ -1,1895 +0,0 @@ -/* tc-tilegx.c -- Assemble for a Tile-Gx chip. - Copyright 2011 Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include "as.h" -#include "struc-symbol.h" -#include "subsegs.h" - -#include "elf/tilegx.h" -#include "opcode/tilegx.h" - -#include "dwarf2dbg.h" -#include "dw2gencfi.h" - -#include "safe-ctype.h" - - -/* Special registers. */ -#define TREG_IDN0 57 -#define TREG_IDN1 58 -#define TREG_UDN0 59 -#define TREG_UDN1 60 -#define TREG_UDN2 61 -#define TREG_UDN3 62 -#define TREG_ZERO 63 - - -/* Generic assembler global variables which must be defined by all - targets. */ - -/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ -int tilegx_cie_data_alignment; - -/* Characters which always start a comment. */ -const char comment_chars[] = "#"; - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = "#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -const char FLT_CHARS[] = "rRsSfFdDxXpP"; - -/* Either 32 or 64. */ -static int tilegx_arch_size = 64; - - -const char * -tilegx_target_format (void) -{ - if (target_big_endian) { - return tilegx_arch_size == 64 ? "elf64-tilegx-be" : "elf32-tilegx-be"; - } else { - return tilegx_arch_size == 64 ? "elf64-tilegx-le" : "elf32-tilegx-le"; - } -} - - -#define OPTION_32 (OPTION_MD_BASE + 0) -#define OPTION_64 (OPTION_MD_BASE + 1) -#define OPTION_EB (OPTION_MD_BASE + 2) -#define OPTION_EL (OPTION_MD_BASE + 3) - -const char *md_shortopts = "VQ:"; - -struct option md_longopts[] = -{ - {"32", no_argument, NULL, OPTION_32}, - {"64", no_argument, NULL, OPTION_64}, - {"EB", no_argument, NULL, OPTION_EB }, - {"EL", no_argument, NULL, OPTION_EL }, - {NULL, no_argument, NULL, 0} -}; - -size_t md_longopts_size = sizeof (md_longopts); - -int -md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) -{ - switch (c) - { - /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section - should be emitted or not. FIXME: Not implemented. */ - case 'Q': - break; - - /* -V: SVR4 argument to print version ID. */ - case 'V': - print_version_id (); - break; - - case OPTION_32: - tilegx_arch_size = 32; - break; - - case OPTION_64: - tilegx_arch_size = 64; - break; - - case OPTION_EB: - target_big_endian = 1; - break; - - case OPTION_EL: - target_big_endian = 0; - break; - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (FILE *stream) -{ - fprintf (stream, _("\ - -Q ignored\n\ - -V print assembler version number\n\ - -EB/-EL generate big-endian/little-endian code\n\ - --32/--64 generate 32bit/64bit code\n")); -} - - -/* Extra expression types. */ - -#define O_hw0 O_md1 -#define O_hw1 O_md2 -#define O_hw2 O_md3 -#define O_hw3 O_md4 -#define O_hw0_last O_md5 -#define O_hw1_last O_md6 -#define O_hw2_last O_md7 -#define O_hw0_got O_md8 -#define O_hw0_last_got O_md9 -#define O_hw1_last_got O_md10 -#define O_plt O_md11 -#define O_hw0_tls_gd O_md12 -#define O_hw0_last_tls_gd O_md13 -#define O_hw1_last_tls_gd O_md14 -#define O_hw0_tls_ie O_md15 -#define O_hw0_last_tls_ie O_md16 -#define O_hw1_last_tls_ie O_md17 -#define O_hw0_tls_le O_md18 -#define O_hw0_last_tls_le O_md19 -#define O_hw1_last_tls_le O_md20 -#define O_tls_gd_call O_md21 -#define O_tls_gd_add O_md22 -#define O_tls_ie_load O_md23 -#define O_tls_add O_md24 -#define O_hw0_plt O_md25 -#define O_hw1_plt O_md26 -#define O_hw1_last_plt O_md27 -#define O_hw2_last_plt O_md28 - -static struct hash_control *special_operator_hash; - -/* Hash tables for instruction mnemonic lookup. */ -static struct hash_control *op_hash; - -/* Hash table for spr lookup. */ -static struct hash_control *spr_hash; - -/* True temporarily while parsing an SPR expression. This changes the - * namespace to include SPR names. */ -static int parsing_spr; - -/* Are we currently inside `{ ... }'? */ -static int inside_bundle; - -struct tilegx_instruction -{ - const struct tilegx_opcode *opcode; - tilegx_pipeline pipe; - expressionS operand_values[TILEGX_MAX_OPERANDS]; -}; - -/* This keeps track of the current bundle being built up. */ -static struct tilegx_instruction current_bundle[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; - -/* Index in current_bundle for the next instruction to parse. */ -static int current_bundle_index; - -/* Allow 'r63' in addition to 'zero', etc. Normally we disallow this as - 'zero' is not a real register, so using it accidentally would be a - nasty bug. For other registers, such as 'sp', code using multiple names - for the same physical register is excessively confusing. - - The '.require_canonical_reg_names' pseudo-op turns this error on, - and the '.no_require_canonical_reg_names' pseudo-op turns this off. - By default the error is on. */ -static int require_canonical_reg_names; - -/* Allow bundles that do undefined or suspicious things like write - two different values to the same register at the same time. - - The '.no_allow_suspicious_bundles' pseudo-op turns this error on, - and the '.allow_suspicious_bundles' pseudo-op turns this off. */ -static int allow_suspicious_bundles; - - -/* A hash table of main processor registers, mapping each register name - to its index. - - Furthermore, if the register number is greater than the number - of registers for that processor, the user used an illegal alias - for that register (e.g. r63 instead of zero), so we should generate - a warning. The attempted register number can be found by clearing - NONCANONICAL_REG_NAME_FLAG. */ -static struct hash_control *main_reg_hash; - - -/* We cannot unambiguously store a 0 in a hash table and look it up, - so we OR in this flag to every canonical register. */ -#define CANONICAL_REG_NAME_FLAG 0x1000 - -/* By default we disallow register aliases like r63, but we record - them in the hash table in case the .no_require_canonical_reg_names - directive is used. Noncanonical names have this value added to them. */ -#define NONCANONICAL_REG_NAME_FLAG 0x2000 - -/* Discards flags for register hash table entries and returns the - reg number. */ -#define EXTRACT_REGNO(p) ((p) & 63) - -/* This function is called once, at assembler startup time. It should - set up all the tables, etc., that the MD part of the assembler will - need. */ - -void -md_begin (void) -{ - const struct tilegx_opcode *op; - int i; - int mach = (tilegx_arch_size == 64) ? bfd_mach_tilegx : bfd_mach_tilegx32; - - if (! bfd_set_arch_mach (stdoutput, bfd_arch_tilegx, mach)) - as_warn (_("Could not set architecture and machine")); - - /* Guarantee text section is aligned. */ - bfd_set_section_alignment (stdoutput, text_section, - TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); - - require_canonical_reg_names = 1; - allow_suspicious_bundles = 0; - current_bundle_index = 0; - inside_bundle = 0; - - tilegx_cie_data_alignment = (tilegx_arch_size == 64 ? -8 : -4); - - /* Initialize special operator hash table. */ - special_operator_hash = hash_new (); -#define INSERT_SPECIAL_OP(name) \ - hash_insert (special_operator_hash, #name, (void *)O_##name) - - INSERT_SPECIAL_OP (hw0); - INSERT_SPECIAL_OP (hw1); - INSERT_SPECIAL_OP (hw2); - INSERT_SPECIAL_OP (hw3); - INSERT_SPECIAL_OP (hw0_last); - INSERT_SPECIAL_OP (hw1_last); - INSERT_SPECIAL_OP (hw2_last); - /* hw3_last is a convenience alias for the equivalent hw3. */ - hash_insert (special_operator_hash, "hw3_last", (void*)O_hw3); - INSERT_SPECIAL_OP (hw0_got); - INSERT_SPECIAL_OP (hw0_last_got); - INSERT_SPECIAL_OP (hw1_last_got); - INSERT_SPECIAL_OP(plt); - INSERT_SPECIAL_OP (hw0_tls_gd); - INSERT_SPECIAL_OP (hw0_last_tls_gd); - INSERT_SPECIAL_OP (hw1_last_tls_gd); - INSERT_SPECIAL_OP (hw0_tls_ie); - INSERT_SPECIAL_OP (hw0_last_tls_ie); - INSERT_SPECIAL_OP (hw1_last_tls_ie); - INSERT_SPECIAL_OP (hw0_tls_le); - INSERT_SPECIAL_OP (hw0_last_tls_le); - INSERT_SPECIAL_OP (hw1_last_tls_le); - INSERT_SPECIAL_OP (tls_gd_call); - INSERT_SPECIAL_OP (tls_gd_add); - INSERT_SPECIAL_OP (tls_ie_load); - INSERT_SPECIAL_OP (tls_add); - INSERT_SPECIAL_OP (hw0_plt); - INSERT_SPECIAL_OP (hw1_plt); - INSERT_SPECIAL_OP (hw1_last_plt); - INSERT_SPECIAL_OP (hw2_last_plt); -#undef INSERT_SPECIAL_OP - - /* Initialize op_hash hash table. */ - op_hash = hash_new (); - for (op = &tilegx_opcodes[0]; op->name != NULL; op++) - { - const char *hash_err = hash_insert (op_hash, op->name, (void *)op); - if (hash_err != NULL) - as_fatal (_("Internal Error: Can't hash %s: %s"), op->name, hash_err); - } - - /* Initialize the spr hash table. */ - parsing_spr = 0; - spr_hash = hash_new (); - for (i = 0; i < tilegx_num_sprs; i++) - hash_insert (spr_hash, tilegx_sprs[i].name, - (void *) &tilegx_sprs[i]); - - /* Set up the main_reg_hash table. We use this instead of - creating a symbol in the register section to avoid ambiguities - with labels that have the same names as registers. */ - main_reg_hash = hash_new (); - for (i = 0; i < TILEGX_NUM_REGISTERS; i++) - { - char buf[64]; - - hash_insert (main_reg_hash, tilegx_register_names[i], - (void *) (long) (i | CANONICAL_REG_NAME_FLAG)); - - /* See if we should insert a noncanonical alias, like r63. */ - sprintf (buf, "r%d", i); - if (strcmp (buf, tilegx_register_names[i]) != 0) - hash_insert (main_reg_hash, xstrdup (buf), - (void *) (long) (i | NONCANONICAL_REG_NAME_FLAG)); - } -} - -#define BUNDLE_TEMPLATE_MASK(p0, p1, p2) \ - ((p0) | ((p1) << 8) | ((p2) << 16)) -#define BUNDLE_TEMPLATE(p0, p1, p2) \ - { { (p0), (p1), (p2) }, \ - BUNDLE_TEMPLATE_MASK(1 << (p0), 1 << (p1), (1 << (p2))) \ - } - -#define NO_PIPELINE TILEGX_NUM_PIPELINE_ENCODINGS - -struct bundle_template -{ - tilegx_pipeline pipe[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; - unsigned int pipe_mask; -}; - -static const struct bundle_template bundle_templates[] = -{ - /* In Y format we must always have something in Y2, since it has - no fnop, so this conveys that Y2 must always be used. */ - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0, TILEGX_PIPELINE_Y2, NO_PIPELINE), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1, TILEGX_PIPELINE_Y2, NO_PIPELINE), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y0, NO_PIPELINE), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2, TILEGX_PIPELINE_Y1, NO_PIPELINE), - - /* Y format has three instructions. */ - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y2), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y1), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y2), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y0), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y0,TILEGX_PIPELINE_Y1), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_Y2,TILEGX_PIPELINE_Y1,TILEGX_PIPELINE_Y0), - - /* X format has only two instructions. */ - BUNDLE_TEMPLATE(TILEGX_PIPELINE_X0, TILEGX_PIPELINE_X1, NO_PIPELINE), - BUNDLE_TEMPLATE(TILEGX_PIPELINE_X1, TILEGX_PIPELINE_X0, NO_PIPELINE) -}; - - -static void -prepend_nop_to_bundle (tilegx_mnemonic mnemonic) -{ - memmove (¤t_bundle[1], ¤t_bundle[0], - current_bundle_index * sizeof current_bundle[0]); - current_bundle[0].opcode = &tilegx_opcodes[mnemonic]; - ++current_bundle_index; -} - -static tilegx_bundle_bits -insert_operand (tilegx_bundle_bits bits, - const struct tilegx_operand *operand, - int operand_value, - char *file, - unsigned lineno) -{ - /* Range-check the immediate. */ - int num_bits = operand->num_bits; - - operand_value >>= operand->rightshift; - - if (bfd_check_overflow (operand->is_signed - ? complain_overflow_signed - : complain_overflow_unsigned, - num_bits, - 0, - bfd_arch_bits_per_address (stdoutput), - operand_value) - != bfd_reloc_ok) - { - offsetT min, max; - if (operand->is_signed) - { - min = -(1 << (num_bits - 1)); - max = (1 << (num_bits - 1)) - 1; - } - else - { - min = 0; - max = (1 << num_bits) - 1; - } - as_bad_value_out_of_range (_("operand"), operand_value, min, max, - file, lineno); - } - - /* Write out the bits for the immediate. */ - return bits | operand->insert (operand_value); -} - - -static int -apply_special_operator (operatorT op, offsetT num, char *file, unsigned lineno) -{ - int ret; - int check_shift = -1; - - switch (op) - { - case O_hw0_last: - check_shift = 0; - /* Fall through. */ - case O_hw0: - ret = (signed short)num; - break; - - case O_hw1_last: - check_shift = 16; - /* Fall through. */ - case O_hw1: - ret = (signed short)(num >> 16); - break; - - case O_hw2_last: - check_shift = 32; - /* Fall through. */ - case O_hw2: - ret = (signed short)(num >> 32); - break; - - case O_hw3: - ret = (signed short)(num >> 48); - break; - - default: - abort (); - break; - } - - if (check_shift >= 0 && ret != (num >> check_shift)) - { - as_bad_value_out_of_range (_("operand"), num, - ~0ULL << (check_shift + 16 - 1), - ~0ULL >> (64 - (check_shift + 16 - 1)), - file, lineno); - } - - return ret; -} - -static tilegx_bundle_bits -emit_tilegx_instruction (tilegx_bundle_bits bits, - int num_operands, - const unsigned char *operands, - expressionS *operand_values, - char *bundle_start) -{ - int i; - - for (i = 0; i < num_operands; i++) - { - const struct tilegx_operand *operand = - &tilegx_operands[operands[i]]; - expressionS *operand_exp = &operand_values[i]; - int is_pc_relative = operand->is_pc_relative; - - if (operand_exp->X_op == O_register - || (operand_exp->X_op == O_constant && !is_pc_relative)) - { - /* We know what the bits are right now, so insert them. */ - bits = insert_operand (bits, operand, operand_exp->X_add_number, - NULL, 0); - } - else - { - bfd_reloc_code_real_type reloc = operand->default_reloc; - expressionS subexp; - int die = 0, use_subexp = 0, require_symbol = 0; - fixS *fixP; - - /* Take an expression like hw0(x) and turn it into x with - a different reloc type. */ - switch (operand_exp->X_op) - { -#define HANDLE_OP16(suffix) \ - switch (reloc) \ - { \ - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST: \ - reloc = BFD_RELOC_TILEGX_IMM16_X0_##suffix; \ - break; \ - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST: \ - reloc = BFD_RELOC_TILEGX_IMM16_X1_##suffix; \ - break; \ - default: \ - die = 1; \ - break; \ - } \ - use_subexp = 1 - - case O_hw0: - HANDLE_OP16 (HW0); - break; - - case O_hw1: - HANDLE_OP16 (HW1); - break; - - case O_hw2: - HANDLE_OP16 (HW2); - break; - - case O_hw3: - HANDLE_OP16 (HW3); - break; - - case O_hw0_last: - HANDLE_OP16 (HW0_LAST); - break; - - case O_hw1_last: - HANDLE_OP16 (HW1_LAST); - break; - - case O_hw2_last: - HANDLE_OP16 (HW2_LAST); - break; - - case O_hw0_got: - HANDLE_OP16 (HW0_GOT); - require_symbol = 1; - break; - - case O_hw0_last_got: - HANDLE_OP16 (HW0_LAST_GOT); - require_symbol = 1; - break; - - case O_hw1_last_got: - HANDLE_OP16 (HW1_LAST_GOT); - require_symbol = 1; - break; - - case O_hw0_tls_gd: - HANDLE_OP16 (HW0_TLS_GD); - require_symbol = 1; - break; - - case O_hw0_last_tls_gd: - HANDLE_OP16 (HW0_LAST_TLS_GD); - require_symbol = 1; - break; - - case O_hw1_last_tls_gd: - HANDLE_OP16 (HW1_LAST_TLS_GD); - require_symbol = 1; - break; - - case O_hw0_tls_ie: - HANDLE_OP16 (HW0_TLS_IE); - require_symbol = 1; - break; - - case O_hw0_last_tls_ie: - HANDLE_OP16 (HW0_LAST_TLS_IE); - require_symbol = 1; - break; - - case O_hw1_last_tls_ie: - HANDLE_OP16 (HW1_LAST_TLS_IE); - require_symbol = 1; - break; - - case O_hw0_tls_le: - HANDLE_OP16 (HW0_TLS_LE); - require_symbol = 1; - break; - - case O_hw0_last_tls_le: - HANDLE_OP16 (HW0_LAST_TLS_LE); - require_symbol = 1; - break; - - case O_hw1_last_tls_le: - HANDLE_OP16 (HW1_LAST_TLS_LE); - require_symbol = 1; - break; - - case O_hw0_plt: - HANDLE_OP16 (HW0_PLT_PCREL); - break; - - case O_hw1_plt: - HANDLE_OP16 (HW1_PLT_PCREL); - break; - - case O_hw1_last_plt: - HANDLE_OP16 (HW1_LAST_PLT_PCREL); - break; - - case O_hw2_last_plt: - HANDLE_OP16 (HW2_LAST_PLT_PCREL); - break; - -#undef HANDLE_OP16 - - case O_plt: - switch (reloc) - { - case BFD_RELOC_TILEGX_JUMPOFF_X1: - reloc = BFD_RELOC_TILEGX_JUMPOFF_X1_PLT; - break; - default: - die = 1; - break; - } - use_subexp = 1; - require_symbol = 1; - break; - - case O_tls_gd_call: - switch (reloc) - { - case BFD_RELOC_TILEGX_JUMPOFF_X1: - reloc = BFD_RELOC_TILEGX_TLS_GD_CALL; - break; - default: - die = 1; - break; - } - use_subexp = 1; - require_symbol = 1; - break; - - case O_tls_gd_add: - switch (reloc) - { - case BFD_RELOC_TILEGX_IMM8_X0: - reloc = BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_X1: - reloc = BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_Y0: - reloc = BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_Y1: - reloc = BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD; - break; - default: - die = 1; - break; - } - use_subexp = 1; - require_symbol = 1; - break; - - case O_tls_ie_load: - switch (reloc) - { - case BFD_RELOC_TILEGX_IMM8_X1: - reloc = BFD_RELOC_TILEGX_TLS_IE_LOAD; - break; - default: - die = 1; - break; - } - use_subexp = 1; - require_symbol = 1; - break; - - case O_tls_add: - switch (reloc) - { - case BFD_RELOC_TILEGX_IMM8_X0: - reloc = BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_X1: - reloc = BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_Y0: - reloc = BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD; - break; - case BFD_RELOC_TILEGX_IMM8_Y1: - reloc = BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD; - break; - default: - die = 1; - break; - } - use_subexp = 1; - require_symbol = 1; - break; - - default: - /* Do nothing. */ - break; - } - - if (die) - { - as_bad (_("Invalid operator for operand.")); - } - else if (use_subexp) - { - /* Now that we've changed the reloc, change ha16(x) into x, - etc. */ - - if (!operand_exp->X_add_symbol->sy_flags.sy_local_symbol - && operand_exp->X_add_symbol->sy_value.X_md) - { - /* HACK: We used X_md to mark this symbol as a fake wrapper - around a real expression. To unwrap it, we just grab its - value here. */ - operand_exp = &operand_exp->X_add_symbol->sy_value; - - if (require_symbol) - { - /* Look at the expression, and reject it if it's not a - plain symbol. */ - if (operand_exp->X_op != O_symbol - || operand_exp->X_add_number != 0) - as_bad (_("Operator may only be applied to symbols.")); - } - } - else - { - /* The value of this expression is an actual symbol, so - turn that into an expression. */ - memset (&subexp, 0, sizeof subexp); - subexp.X_op = O_symbol; - subexp.X_add_symbol = operand_exp->X_add_symbol; - operand_exp = &subexp; - } - } - - /* Create a fixup to handle this later. */ - fixP = fix_new_exp (frag_now, - bundle_start - frag_now->fr_literal, - (operand->num_bits + 7) >> 3, - operand_exp, - is_pc_relative, - reloc); - fixP->tc_fix_data = operand; - - /* Don't do overflow checking if we are applying a function like - ha16. */ - fixP->fx_no_overflow |= use_subexp; - } - } - return bits; -} - - -/* Detects and complains if two instructions in current_bundle write - to the same register, either implicitly or explicitly, or if a - read-only register is written. */ -static void -check_illegal_reg_writes (void) -{ - BFD_HOST_U_64_BIT all_regs_written = 0; - int j; - - for (j = 0; j < current_bundle_index; j++) - { - const struct tilegx_instruction *instr = ¤t_bundle[j]; - int k; - BFD_HOST_U_64_BIT regs = - ((BFD_HOST_U_64_BIT)1) << instr->opcode->implicitly_written_register; - BFD_HOST_U_64_BIT conflict; - - for (k = 0; k < instr->opcode->num_operands; k++) - { - const struct tilegx_operand *operand = - &tilegx_operands[instr->opcode->operands[instr->pipe][k]]; - - if (operand->is_dest_reg) - { - int regno = instr->operand_values[k].X_add_number; - BFD_HOST_U_64_BIT mask = ((BFD_HOST_U_64_BIT)1) << regno; - - if ((mask & ( (((BFD_HOST_U_64_BIT)1) << TREG_IDN1) - | (((BFD_HOST_U_64_BIT)1) << TREG_UDN1) - | (((BFD_HOST_U_64_BIT)1) << TREG_UDN2) - | (((BFD_HOST_U_64_BIT)1) << TREG_UDN3))) != 0 - && !allow_suspicious_bundles) - { - as_bad (_("Writes to register '%s' are not allowed."), - tilegx_register_names[regno]); - } - - regs |= mask; - } - } - - /* Writing to the zero register doesn't count. */ - regs &= ~(((BFD_HOST_U_64_BIT)1) << TREG_ZERO); - - conflict = all_regs_written & regs; - if (conflict != 0 && !allow_suspicious_bundles) - { - /* Find which register caused the conflict. */ - const char *conflicting_reg_name = "???"; - int i; - - for (i = 0; i < TILEGX_NUM_REGISTERS; i++) - { - if (((conflict >> i) & 1) != 0) - { - conflicting_reg_name = tilegx_register_names[i]; - break; - } - } - - as_bad (_("Two instructions in the same bundle both write " - "to register %s, which is not allowed."), - conflicting_reg_name); - } - - all_regs_written |= regs; - } -} - - -static void -tilegx_flush_bundle (void) -{ - unsigned i; - int j; - addressT addr_mod; - unsigned compatible_pipes; - const struct bundle_template *match; - char *f; - - inside_bundle = 0; - - switch (current_bundle_index) - { - case 0: - /* No instructions. */ - return; - case 1: - if (current_bundle[0].opcode->can_bundle) - { - /* Simplify later logic by adding an explicit fnop. */ - prepend_nop_to_bundle (TILEGX_OPC_FNOP); - } - else - { - /* This instruction cannot be bundled with anything else. - Prepend an explicit 'nop', rather than an 'fnop', because - fnops can be replaced by later binary-processing tools while - nops cannot. */ - prepend_nop_to_bundle (TILEGX_OPC_NOP); - } - break; - default: - if (!allow_suspicious_bundles) - { - /* Make sure all instructions can be bundled with other - instructions. */ - const struct tilegx_opcode *cannot_bundle = NULL; - bfd_boolean seen_non_nop = FALSE; - - for (j = 0; j < current_bundle_index; j++) - { - const struct tilegx_opcode *op = current_bundle[j].opcode; - - if (!op->can_bundle && cannot_bundle == NULL) - cannot_bundle = op; - else if (op->mnemonic != TILEGX_OPC_NOP - && op->mnemonic != TILEGX_OPC_INFO - && op->mnemonic != TILEGX_OPC_INFOL) - seen_non_nop = TRUE; - } - - if (cannot_bundle != NULL && seen_non_nop) - { - current_bundle_index = 0; - as_bad (_("'%s' may not be bundled with other instructions."), - cannot_bundle->name); - return; - } - } - break; - } - - compatible_pipes = - BUNDLE_TEMPLATE_MASK(current_bundle[0].opcode->pipes, - current_bundle[1].opcode->pipes, - (current_bundle_index == 3 - ? current_bundle[2].opcode->pipes - : (1 << NO_PIPELINE))); - - /* Find a template that works, if any. */ - match = NULL; - for (i = 0; i < sizeof bundle_templates / sizeof bundle_templates[0]; i++) - { - const struct bundle_template *b = &bundle_templates[i]; - if ((b->pipe_mask & compatible_pipes) == b->pipe_mask) - { - match = b; - break; - } - } - - if (match == NULL) - { - current_bundle_index = 0; - as_bad (_("Invalid combination of instructions for bundle.")); - return; - } - - /* If the section seems to have no alignment set yet, go ahead and - make it large enough to hold code. */ - if (bfd_get_section_alignment (stdoutput, now_seg) == 0) - bfd_set_section_alignment (stdoutput, now_seg, - TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES); - - for (j = 0; j < current_bundle_index; j++) - current_bundle[j].pipe = match->pipe[j]; - - if (current_bundle_index == 2 && !tilegx_is_x_pipeline (match->pipe[0])) - { - /* We are in Y mode with only two instructions, so add an FNOP. */ - prepend_nop_to_bundle (TILEGX_OPC_FNOP); - - /* Figure out what pipe the fnop must be in via arithmetic. - * p0 + p1 + p2 must sum to the sum of TILEGX_PIPELINE_Y[012]. */ - current_bundle[0].pipe = - (tilegx_pipeline)((TILEGX_PIPELINE_Y0 - + TILEGX_PIPELINE_Y1 - + TILEGX_PIPELINE_Y2) - - (current_bundle[1].pipe + current_bundle[2].pipe)); - } - - check_illegal_reg_writes (); - - f = frag_more (TILEGX_BUNDLE_SIZE_IN_BYTES); - - /* Check to see if this bundle is at an offset that is a multiple of 8-bytes - from the start of the frag. */ - addr_mod = frag_now_fix () & (TILEGX_BUNDLE_ALIGNMENT_IN_BYTES - 1); - if (frag_now->has_code && frag_now->insn_addr != addr_mod) - as_bad (_("instruction address is not a multiple of 8")); - frag_now->insn_addr = addr_mod; - frag_now->has_code = 1; - - tilegx_bundle_bits bits = 0; - for (j = 0; j < current_bundle_index; j++) - { - struct tilegx_instruction *instr = ¤t_bundle[j]; - tilegx_pipeline pipeline = instr->pipe; - const struct tilegx_opcode *opcode = instr->opcode; - - bits |= emit_tilegx_instruction (opcode->fixed_bit_values[pipeline], - opcode->num_operands, - &opcode->operands[pipeline][0], - instr->operand_values, - f); - } - - number_to_chars_littleendian (f, bits, 8); - current_bundle_index = 0; - - /* Emit DWARF2 debugging information. */ - dwarf2_emit_insn (TILEGX_BUNDLE_SIZE_IN_BYTES); -} - - -/* Extend the expression parser to handle hw0(label), etc. - as well as SPR names when in the context of parsing an SPR. */ - -int -tilegx_parse_name (char *name, expressionS *e, char *nextcharP) -{ - operatorT op = O_illegal; - - if (parsing_spr) - { - void* val = hash_find (spr_hash, name); - if (val == NULL) - return 0; - - memset (e, 0, sizeof *e); - e->X_op = O_constant; - e->X_add_number = ((const struct tilegx_spr *)val)->number; - return 1; - } - - if (*nextcharP != '(') - { - /* hw0, etc. not followed by a paren is just a label with that name. */ - return 0; - } - else - { - /* Look up the operator in our table. */ - void* val = hash_find (special_operator_hash, name); - if (val == 0) - return 0; - op = (operatorT)(long)val; - } - - /* Restore old '(' and skip it. */ - *input_line_pointer = '('; - ++input_line_pointer; - - expression (e); - - if (*input_line_pointer != ')') - { - as_bad (_("Missing ')'")); - *nextcharP = *input_line_pointer; - return 0; - } - /* Skip ')'. */ - ++input_line_pointer; - - if (e->X_op == O_register || e->X_op == O_absent) - { - as_bad (_("Invalid expression.")); - e->X_op = O_constant; - e->X_add_number = 0; - } - else - { - /* Wrap subexpression with a unary operator. */ - symbolS *sym = make_expr_symbol (e); - - if (sym != e->X_add_symbol) - { - /* HACK: mark this symbol as a temporary wrapper around a proper - expression, so we can unwrap it later once we have communicated - the relocation type. */ - sym->sy_value.X_md = 1; - } - - memset (e, 0, sizeof *e); - e->X_op = op; - e->X_add_symbol = sym; - e->X_add_number = 0; - } - - *nextcharP = *input_line_pointer; - return 1; -} - - -/* Parses an expression which must be a register name. */ - -static void -parse_reg_expression (expressionS* expression) -{ - /* Zero everything to make sure we don't miss any flags. */ - memset (expression, 0, sizeof *expression); - - char* regname = input_line_pointer; - char terminating_char = get_symbol_end (); - - void* pval = hash_find (main_reg_hash, regname); - - if (pval == NULL) - { - as_bad (_("Expected register, got '%s'."), regname); - } - - int regno_and_flags = (int)(size_t)pval; - int regno = EXTRACT_REGNO(regno_and_flags); - - if ((regno_and_flags & NONCANONICAL_REG_NAME_FLAG) - && require_canonical_reg_names) - { - as_warn (_("Found use of non-canonical register name %s; " - "use %s instead."), - regname, - tilegx_register_names[regno]); - } - - /* Restore the old character following the register name. */ - *input_line_pointer = terminating_char; - - /* Fill in the expression fields to indicate it's a register. */ - expression->X_op = O_register; - expression->X_add_number = regno; -} - - -/* Parses and type-checks comma-separated operands in input_line_pointer. */ - -static void -parse_operands (const char *opcode_name, - const unsigned char *operands, - int num_operands, - expressionS *operand_values) -{ - int i; - - memset (operand_values, 0, num_operands * sizeof operand_values[0]); - - SKIP_WHITESPACE (); - for (i = 0; i < num_operands; i++) - { - tilegx_operand_type type = tilegx_operands[operands[i]].type; - - SKIP_WHITESPACE (); - - if (type == TILEGX_OP_TYPE_REGISTER) - { - parse_reg_expression (&operand_values[i]); - } - else if (*input_line_pointer == '}') - { - operand_values[i].X_op = O_absent; - } - else if (type == TILEGX_OP_TYPE_SPR) - { - /* Modify the expression parser to add SPRs to the namespace. */ - parsing_spr = 1; - expression (&operand_values[i]); - parsing_spr = 0; - } - else - { - expression (&operand_values[i]); - } - - SKIP_WHITESPACE (); - - if (i + 1 < num_operands) - { - int separator = (unsigned char)*input_line_pointer++; - - if (is_end_of_line[separator] || (separator == '}')) - { - as_bad (_("Too few operands to '%s'."), opcode_name); - return; - } - else if (separator != ',') - { - as_bad (_("Unexpected character '%c' after operand %d to %s."), - (char)separator, i + 1, opcode_name); - return; - } - } - - /* Arbitrarily use the first valid pipe to get the operand type, - since they are all the same. */ - switch (tilegx_operands[operands[i]].type) - { - case TILEGX_OP_TYPE_REGISTER: - /* Handled in parse_reg_expression already. */ - break; - case TILEGX_OP_TYPE_SPR: - /* Fall through */ - case TILEGX_OP_TYPE_IMMEDIATE: - /* Fall through */ - case TILEGX_OP_TYPE_ADDRESS: - if ( operand_values[i].X_op == O_register - || operand_values[i].X_op == O_illegal - || operand_values[i].X_op == O_absent) - as_bad (_("Expected immediate expression")); - break; - default: - abort(); - } - } - - if (!is_end_of_line[(unsigned char)*input_line_pointer]) - { - switch (*input_line_pointer) - { - case '}': - if (!inside_bundle) - as_bad (_("Found '}' when not bundling.")); - ++input_line_pointer; - inside_bundle = 0; - demand_empty_rest_of_line (); - break; - - case ',': - as_bad (_("Too many operands")); - break; - - default: - /* Use default error for unrecognized garbage. */ - demand_empty_rest_of_line (); - break; - } - } -} - - -/* This is the guts of the machine-dependent assembler. STR points to a - machine dependent instruction. This function is supposed to emit the - frags/bytes it assembles to. */ - -void -md_assemble (char *str) -{ - char old_char; - size_t opname_len; - char *old_input_line_pointer; - const struct tilegx_opcode *op; - int first_pipe; - - /* Split off the opcode and look it up. */ - opname_len = strcspn (str, " {}"); - old_char = str[opname_len]; - str[opname_len] = '\0'; - - op = hash_find(op_hash, str); - str[opname_len] = old_char; - if (op == NULL) - { - as_bad (_("Unknown opcode `%.*s'."), (int)opname_len, str); - return; - } - - /* Prepare to parse the operands. */ - old_input_line_pointer = input_line_pointer; - input_line_pointer = str + opname_len; - SKIP_WHITESPACE (); - - if (current_bundle_index == TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE) - { - as_bad (_("Too many instructions for bundle.")); - tilegx_flush_bundle (); - } - - /* Make sure we have room for the upcoming bundle before we - create any fixups. Otherwise if we have to switch to a new - frag the fixup dot_value fields will be wrong. */ - frag_grow (TILEGX_BUNDLE_SIZE_IN_BYTES); - - /* Find a valid pipe for this opcode. */ - for (first_pipe = 0; (op->pipes & (1 << first_pipe)) == 0; first_pipe++) - ; - - /* Call the function that assembles this instruction. */ - current_bundle[current_bundle_index].opcode = op; - parse_operands (op->name, - &op->operands[first_pipe][0], - op->num_operands, - current_bundle[current_bundle_index].operand_values); - ++current_bundle_index; - - /* Restore the saved value of input_line_pointer. */ - input_line_pointer = old_input_line_pointer; - - /* If we weren't inside curly braces, go ahead and emit - this lone instruction as a bundle right now. */ - if (!inside_bundle) - tilegx_flush_bundle (); -} - - -static void -s_require_canonical_reg_names (int require) -{ - demand_empty_rest_of_line (); - require_canonical_reg_names = require; -} - -static void -s_allow_suspicious_bundles (int allow) -{ - demand_empty_rest_of_line (); - allow_suspicious_bundles = allow; -} - -const pseudo_typeS md_pseudo_table[] = -{ - {"align", s_align_bytes, 0}, /* Defaulting is invalid (0). */ - {"word", cons, 4}, - {"require_canonical_reg_names", s_require_canonical_reg_names, 1 }, - {"no_require_canonical_reg_names", s_require_canonical_reg_names, 0 }, - {"allow_suspicious_bundles", s_allow_suspicious_bundles, 1 }, - {"no_allow_suspicious_bundles", s_allow_suspicious_bundles, 0 }, - { NULL, 0, 0 } -}; - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -void -md_number_to_chars (char * buf, valueT val, int n) -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -/* Turn the string pointed to by litP into a floating point constant - of type TYPE, and emit the appropriate bytes. The number of - LITTLENUMS emitted is stored in *SIZEP. An error message is - returned, or NULL on OK. */ - -char * -md_atof (int type, char *litP, int *sizeP) -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - case 'F': - prec = 2; - break; - - case 'd': - case 'D': - prec = 4; - break; - - default: - *sizeP = 0; - return _("Bad call to md_atof ()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - /* This loops outputs the LITTLENUMs in REVERSE order; in accord with - the bigendian 386. */ - for (wordP = words + prec - 1; prec--;) - { - md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; -} - - -/* We have no need to default values of symbols. */ - -symbolS * -md_undefined_symbol (char *name ATTRIBUTE_UNUSED) -{ - return NULL; -} - - -void -tilegx_cons_fix_new (fragS *frag, - int where, - int nbytes, - expressionS *exp) -{ - expressionS subexp; - bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; - int no_overflow = 0; - fixS *fixP; - - /* See if it's one of our special functions. */ - switch (exp->X_op) - { - case O_hw0: - reloc = BFD_RELOC_TILEGX_HW0; - no_overflow = 1; - break; - case O_hw1: - reloc = BFD_RELOC_TILEGX_HW1; - no_overflow = 1; - break; - case O_hw2: - reloc = BFD_RELOC_TILEGX_HW2; - no_overflow = 1; - break; - case O_hw3: - reloc = BFD_RELOC_TILEGX_HW3; - no_overflow = 1; - break; - case O_hw0_last: - reloc = BFD_RELOC_TILEGX_HW0_LAST; - break; - case O_hw1_last: - reloc = BFD_RELOC_TILEGX_HW1_LAST; - break; - case O_hw2_last: - reloc = BFD_RELOC_TILEGX_HW2_LAST; - break; - - default: - /* Do nothing. */ - break; - } - - if (reloc != BFD_RELOC_NONE) - { - if (nbytes != 2) - { - as_bad (_("This operator only produces two byte values.")); - nbytes = 2; - } - - memset (&subexp, 0, sizeof subexp); - subexp.X_op = O_symbol; - subexp.X_add_symbol = exp->X_add_symbol; - exp = &subexp; - } - else - { - switch (nbytes) - { - case 1: - reloc = BFD_RELOC_8; - break; - case 2: - reloc = BFD_RELOC_16; - break; - case 4: - reloc = BFD_RELOC_32; - break; - case 8: - reloc = BFD_RELOC_64; - break; - default: - as_bad (_("unsupported BFD relocation size %d"), nbytes); - reloc = BFD_RELOC_64; - break; - } - } - - fixP = fix_new_exp (frag, where, nbytes, exp, 0, reloc); - fixP->tc_fix_data = NULL; - fixP->fx_no_overflow |= no_overflow; -} - - -void -md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) -{ - const struct tilegx_operand *operand; - valueT value = *valP; - operatorT special; - char *p; - - /* Leave these for the linker. */ - if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return; - - if (fixP->fx_subsy != (symbolS *) NULL) - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); - } - - /* Correct relocation types for pc-relativeness. */ - switch (fixP->fx_r_type) - { -#define FIX_PCREL(rtype) \ - case rtype: \ - if (fixP->fx_pcrel) \ - fixP->fx_r_type = rtype##_PCREL; \ - break; \ - \ - case rtype##_PCREL: \ - if (!fixP->fx_pcrel) \ - fixP->fx_r_type = rtype; \ - break - -#define FIX_PLT_PCREL(rtype) \ - case rtype##_PLT_PCREL: \ - if (!fixP->fx_pcrel) \ - fixP->fx_r_type = rtype; \ - \ - break; - - FIX_PCREL (BFD_RELOC_8); - FIX_PCREL (BFD_RELOC_16); - FIX_PCREL (BFD_RELOC_32); - FIX_PCREL (BFD_RELOC_64); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW0); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW0); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW2); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW2); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW3); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW3); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST); - FIX_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW0); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW0); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST); - FIX_PLT_PCREL (BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST); - -#undef FIX_PCREL - - default: - /* Do nothing */ - break; - } - - if (fixP->fx_addsy != NULL) - { -#ifdef OBJ_ELF - switch (fixP->fx_r_type) - { - case BFD_RELOC_TILEGX_IMM8_X0_TLS_ADD: - case BFD_RELOC_TILEGX_IMM8_X1_TLS_ADD: - case BFD_RELOC_TILEGX_IMM8_Y0_TLS_ADD: - case BFD_RELOC_TILEGX_IMM8_Y1_TLS_ADD: - case BFD_RELOC_TILEGX_IMM8_X0_TLS_GD_ADD: - case BFD_RELOC_TILEGX_IMM8_X1_TLS_GD_ADD: - case BFD_RELOC_TILEGX_IMM8_Y0_TLS_GD_ADD: - case BFD_RELOC_TILEGX_IMM8_Y1_TLS_GD_ADD: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_GD: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_IE: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_TLS_LE: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_TLS_LE: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_TLS_LE: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_TLS_LE: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_TLS_LE: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_TLS_LE: - case BFD_RELOC_TILEGX_TLS_GD_CALL: - case BFD_RELOC_TILEGX_TLS_IE_LOAD: - case BFD_RELOC_TILEGX_TLS_DTPMOD64: - case BFD_RELOC_TILEGX_TLS_DTPOFF64: - case BFD_RELOC_TILEGX_TLS_TPOFF64: - case BFD_RELOC_TILEGX_TLS_DTPMOD32: - case BFD_RELOC_TILEGX_TLS_DTPOFF32: - case BFD_RELOC_TILEGX_TLS_TPOFF32: - S_SET_THREAD_LOCAL (fixP->fx_addsy); - break; - - default: - /* Do nothing */ - break; - } -#endif - return; - } - - /* Apply hw0, etc. */ - special = O_illegal; - switch (fixP->fx_r_type) - { - case BFD_RELOC_TILEGX_HW0: - case BFD_RELOC_TILEGX_IMM16_X0_HW0: - case BFD_RELOC_TILEGX_IMM16_X1_HW0: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_PLT_PCREL: - special = O_hw0; - break; - - case BFD_RELOC_TILEGX_HW0_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL: - special = O_hw0_last; - break; - - case BFD_RELOC_TILEGX_HW1: - case BFD_RELOC_TILEGX_IMM16_X0_HW1: - case BFD_RELOC_TILEGX_IMM16_X1_HW1: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_PLT_PCREL: - special = O_hw1; - break; - - case BFD_RELOC_TILEGX_HW1_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL: - special = O_hw1_last; - break; - - case BFD_RELOC_TILEGX_HW2: - case BFD_RELOC_TILEGX_IMM16_X0_HW2: - case BFD_RELOC_TILEGX_IMM16_X1_HW2: - case BFD_RELOC_TILEGX_IMM16_X0_HW2_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW2_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW2_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW2_PLT_PCREL: - special = O_hw2; - break; - - case BFD_RELOC_TILEGX_HW2_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST: - case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST: - case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL: - special = O_hw2_last; - break; - - case BFD_RELOC_TILEGX_HW3: - case BFD_RELOC_TILEGX_IMM16_X0_HW3: - case BFD_RELOC_TILEGX_IMM16_X1_HW3: - case BFD_RELOC_TILEGX_IMM16_X0_HW3_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW3_PCREL: - case BFD_RELOC_TILEGX_IMM16_X0_HW3_PLT_PCREL: - case BFD_RELOC_TILEGX_IMM16_X1_HW3_PLT_PCREL: - special = O_hw3; - break; - - default: - /* Do nothing */ - break; - } - - if (special != O_illegal) - { - *valP = value = apply_special_operator (special, value, - fixP->fx_file, fixP->fx_line); - } - - p = fixP->fx_frag->fr_literal + fixP->fx_where; - - operand = fixP->tc_fix_data; - if (operand != NULL) - { - /* It's an instruction operand. */ - tilegx_bundle_bits bits = - insert_operand (0, operand, value, fixP->fx_file, fixP->fx_line); - - /* Note that we might either be writing out bits for a bundle - or a static network instruction, which are different sizes, so it's - important to stop touching memory once we run out of bits. - ORing in values is OK since we know the existing bits for - this operand are zero. */ - for (; bits != 0; bits >>= 8) - *p++ |= (char)bits; - } - else - { - /* Some other kind of relocation. */ - switch (fixP->fx_r_type) - { - case BFD_RELOC_8: - case BFD_RELOC_8_PCREL: - md_number_to_chars (p, value, 1); - break; - - case BFD_RELOC_16: - case BFD_RELOC_16_PCREL: - md_number_to_chars (p, value, 2); - break; - - case BFD_RELOC_32: - case BFD_RELOC_32_PCREL: - md_number_to_chars (p, value, 4); - break; - - case BFD_RELOC_64: - case BFD_RELOC_64_PCREL: - md_number_to_chars (p, value, 8); - break; - - default: - /* Leave it for the linker. */ - return; - } - } - - fixP->fx_done = 1; -} - - -/* Generate the BFD reloc to be stuck in the object file from the - fixup used internally in the assembler. */ - -arelent * -tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixp) -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - /* Make sure none of our internal relocations make it this far. - They'd better have been fully resolved by this point. */ - gas_assert ((int) fixp->fx_r_type > 0); - - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot represent `%s' relocation in object file"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - return NULL; - } - - if (!fixp->fx_pcrel != !reloc->howto->pc_relative) - { - as_fatal (_("internal error? cannot generate `%s' relocation (%d, %d)"), - bfd_get_reloc_code_name (fixp->fx_r_type), - fixp->fx_pcrel, reloc->howto->pc_relative); - } - gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); - - reloc->addend = fixp->fx_offset; - - return reloc; -} - - -/* The location from which a PC relative jump should be calculated, - given a PC relative reloc. */ - -long -md_pcrel_from (fixS *fixP) -{ - return fixP->fx_frag->fr_address + fixP->fx_where; -} - - -/* Return 1 if it's OK to adjust a reloc by replacing the symbol with - a section symbol plus some offset. */ -int -tilegx_fix_adjustable (fixS *fix) -{ - /* Prevent all adjustments to global symbols */ - if (S_IS_EXTERNAL (fix->fx_addsy) || S_IS_WEAK (fix->fx_addsy)) - return 0; - - return 1; -} - - -int -tilegx_unrecognized_line (int ch) -{ - switch (ch) - { - case '{': - if (inside_bundle) - { - as_bad (_("Found '{' when already bundling.")); - } - else - { - inside_bundle = 1; - current_bundle_index = 0; - } - return 1; - - case '}': - if (!inside_bundle) - { - as_bad (_("Found '}' when not bundling.")); - } - else - { - tilegx_flush_bundle (); - } - - /* Allow '{' to follow on the same line. We also allow ";;", but that - happens automatically because ';' is an end of line marker. */ - SKIP_WHITESPACE (); - if (input_line_pointer[0] == '{') - { - input_line_pointer++; - return tilegx_unrecognized_line ('{'); - } - - demand_empty_rest_of_line (); - return 1; - - default: - break; - } - - /* Not a valid line. */ - return 0; -} - - -/* This is called from HANDLE_ALIGN in write.c. Fill in the contents - of an rs_align_code fragment. */ - -void -tilegx_handle_align (fragS *fragp) -{ - addressT bytes, fix; - char *p; - - if (fragp->fr_type != rs_align_code) - return; - - bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; - p = fragp->fr_literal + fragp->fr_fix; - fix = 0; - - /* Determine the bits for NOP. */ - const struct tilegx_opcode *nop_opcode = - &tilegx_opcodes[TILEGX_OPC_NOP]; - tilegx_bundle_bits nop = - ( nop_opcode->fixed_bit_values[TILEGX_PIPELINE_X0] - | nop_opcode->fixed_bit_values[TILEGX_PIPELINE_X1]); - - if ((bytes & (TILEGX_BUNDLE_SIZE_IN_BYTES - 1)) != 0) - { - fix = bytes & (TILEGX_BUNDLE_SIZE_IN_BYTES - 1); - memset (p, 0, fix); - p += fix; - bytes -= fix; - } - - number_to_chars_littleendian (p, nop, 8); - fragp->fr_fix += fix; - fragp->fr_var = TILEGX_BUNDLE_SIZE_IN_BYTES; -} - -/* Standard calling conventions leave the CFA at SP on entry. */ -void -tilegx_cfi_frame_initial_instructions (void) -{ - cfi_add_CFA_def_cfa_register (54); -} - -int -tc_tilegx_regname_to_dw2regnum (char *regname) -{ - int i; - for (i = 0; i < TILEGX_NUM_REGISTERS; i++) - { - if (!strcmp (regname, tilegx_register_names[i])) - return i; - } - - return -1; -} |