X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=gas%2Fconfig%2Ftc-cr16.c;fp=gas%2Fconfig%2Ftc-cr16.c;h=1ed74cda44238606f4d08b95b14874fec65038ba;hp=256feed3e336e34f0085db00a61664e397529922;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/gas/config/tc-cr16.c b/gas/config/tc-cr16.c index 256feed..1ed74cd 100644 --- a/gas/config/tc-cr16.c +++ b/gas/config/tc-cr16.c @@ -1,5 +1,5 @@ /* tc-cr16.c -- Assembler code for the CR16 CPU core. - Copyright 2007 Free Software Foundation, Inc. + Copyright 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by M R Swami Reddy @@ -99,6 +99,11 @@ const char EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant as in 0f12.456 */ const char FLT_CHARS[] = "f'"; +#ifdef OBJ_ELF +/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ +symbolS * GOT_symbol; +#endif + /* Target-specific multicharacter options, not const-declared at usage. */ const char *md_shortopts = ""; struct option md_longopts[] = @@ -141,92 +146,92 @@ l_cons (int nbytes) expression (&exp); if (*input_line_pointer == ':') - { - /* Bitfields. */ - long value = 0; + { + /* Bitfields. */ + long value = 0; - for (;;) - { - unsigned long width; - - if (*input_line_pointer != ':') - { - input_line_pointer = hold; - break; - } - if (exp.X_op == O_absent) - { - as_warn (_("using a bit field width of zero")); - exp.X_add_number = 0; - exp.X_op = O_constant; - } - - if (exp.X_op != O_constant) - { - *input_line_pointer = '\0'; - as_bad (_("field width \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = ':'; - demand_empty_rest_of_line (); - return; - } - - if ((width = exp.X_add_number) > - (unsigned int)(BITS_PER_CHAR * nbytes)) - { - as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); - width = BITS_PER_CHAR * nbytes; - } /* Too big. */ - - - if (width > bits_available) - { - /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ - input_line_pointer = hold; - exp.X_add_number = value; - break; - } - - /* Skip ':'. */ - hold = ++input_line_pointer; - - expression (&exp); - if (exp.X_op != O_constant) - { - char cache = *input_line_pointer; - - *input_line_pointer = '\0'; - as_bad (_("field value \"%s\" too complex for a bitfield"), hold); - *input_line_pointer = cache; - demand_empty_rest_of_line (); - return; - } - - value |= ((~(-1 << width) & exp.X_add_number) - << ((BITS_PER_CHAR * nbytes) - bits_available)); - - if ((bits_available -= width) == 0 - || is_it_end_of_statement () - || *input_line_pointer != ',') - break; - - hold = ++input_line_pointer; - expression (&exp); - } + for (;;) + { + unsigned long width; - exp.X_add_number = value; - exp.X_op = O_constant; - exp.X_unsigned = 1; - } + if (*input_line_pointer != ':') + { + input_line_pointer = hold; + break; + } + if (exp.X_op == O_absent) + { + as_warn (_("using a bit field width of zero")); + exp.X_add_number = 0; + exp.X_op = O_constant; + } + + if (exp.X_op != O_constant) + { + *input_line_pointer = '\0'; + as_bad (_("field width \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = ':'; + demand_empty_rest_of_line (); + return; + } + + if ((width = exp.X_add_number) > + (unsigned int)(BITS_PER_CHAR * nbytes)) + { + as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes)); + width = BITS_PER_CHAR * nbytes; + } /* Too big. */ + + + if (width > bits_available) + { + /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ + input_line_pointer = hold; + exp.X_add_number = value; + break; + } + + /* Skip ':'. */ + hold = ++input_line_pointer; + + expression (&exp); + if (exp.X_op != O_constant) + { + char cache = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("field value \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = cache; + demand_empty_rest_of_line (); + return; + } + + value |= ((~(-1 << width) & exp.X_add_number) + << ((BITS_PER_CHAR * nbytes) - bits_available)); + + if ((bits_available -= width) == 0 + || is_it_end_of_statement () + || *input_line_pointer != ',') + break; + + hold = ++input_line_pointer; + expression (&exp); + } + + exp.X_add_number = value; + exp.X_op = O_constant; + exp.X_unsigned = 1; + } if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) - code_label = 1; + code_label = 1; emit_expr (&exp, (unsigned int) nbytes); ++c; if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c')) - { - input_line_pointer +=3; - break; - } + { + input_line_pointer +=3; + break; + } } while ((*input_line_pointer++ == ',')); @@ -236,7 +241,6 @@ l_cons (int nbytes) demand_empty_rest_of_line (); } - /* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: *** Pseudo-op name without dot. @@ -248,6 +252,7 @@ const pseudo_typeS md_pseudo_table[] = /* In CR16 machine, align is in bytes (not a ptwo boundary). */ {"align", s_align_bytes, 0}, {"long", l_cons, 4 }, + {"4byte", l_cons, 4 }, {0, 0, 0} }; @@ -255,7 +260,7 @@ const pseudo_typeS md_pseudo_table[] = const relax_typeS md_relax_table[] = { /* bCC */ - {0xfa, -0x100, 2, 1}, /* 8 */ + {0x7f, -0x80, 2, 1}, /* 8 */ {0xfffe, -0x10000, 4, 2}, /* 16 */ {0xfffffe, -0x1000000, 6, 0}, /* 24 */ }; @@ -373,8 +378,8 @@ get_index_register_pair (char *reg_name) if (reg != NULL) { if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7) - || (reg->value.reg_val != 9) || (reg->value.reg_val > 10)) - return reg->value.reg_val; + || (reg->value.reg_val != 9) || (reg->value.reg_val > 10)) + return reg->value.reg_val; as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val); } @@ -478,9 +483,7 @@ reset_vars (char *op) int cr16_force_relocation (fixS *fix) { - /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added - if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) */ - if (generic_force_reloc (fix)) + if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) return 1; return 0; @@ -491,7 +494,8 @@ cr16_force_relocation (fixS *fix) void cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp) { - int rtype; + int rtype = BFD_RELOC_UNUSED; + switch (len) { default: rtype = BFD_RELOC_NONE; break; @@ -499,12 +503,12 @@ cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp) case 2: rtype = BFD_RELOC_CR16_NUM16; break; case 4: if (code_label) - { - rtype = BFD_RELOC_CR16_NUM32a; - code_label = 0; - } + { + rtype = BFD_RELOC_CR16_NUM32a; + code_label = 0; + } else - rtype = BFD_RELOC_CR16_NUM32; + rtype = BFD_RELOC_CR16_NUM32; break; } @@ -517,6 +521,14 @@ arelent * tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) { arelent * reloc; + bfd_reloc_code_real_type code; + + /* If symbols are local and resolved, then no relocation needed. */ + if ( ((fixP->fx_addsy) + && (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section)) + || ((fixP->fx_subsy) + && (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section))) + return NULL; reloc = xmalloc (sizeof (arelent)); reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); @@ -534,21 +546,21 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) switch (fixP->fx_r_type) { - case BFD_RELOC_CR16_NUM8: - fixP->fx_r_type = BFD_RELOC_CR16_NUM8; - break; - case BFD_RELOC_CR16_NUM16: - fixP->fx_r_type = BFD_RELOC_CR16_NUM16; - break; - case BFD_RELOC_CR16_NUM32: - fixP->fx_r_type = BFD_RELOC_CR16_NUM32; - break; - case BFD_RELOC_CR16_NUM32a: - fixP->fx_r_type = BFD_RELOC_CR16_NUM32a; - break; - default: - abort (); - break; + case BFD_RELOC_CR16_NUM8: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH8; + break; + case BFD_RELOC_CR16_NUM16: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH16; + break; + case BFD_RELOC_CR16_NUM32: + fixP->fx_r_type = BFD_RELOC_CR16_SWITCH32; + break; + case BFD_RELOC_CR16_NUM32a: + fixP->fx_r_type = BFD_RELOC_CR16_NUM32a; + break; + default: + abort (); + break; } } else @@ -564,8 +576,24 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) segment_name (S_GET_SEGMENT (fixP->fx_addsy))); } } +#ifdef OBJ_ELF + if ((fixP->fx_r_type == BFD_RELOC_CR16_GOT_REGREL20) + && GOT_symbol + && fixP->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_CR16_GOT_REGREL20; + reloc->addend = fixP->fx_offset = reloc->address; + } + else if ((fixP->fx_r_type == BFD_RELOC_CR16_GOTC_REGREL20) + && GOT_symbol + && fixP->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_CR16_GOTC_REGREL20; + reloc->addend = fixP->fx_offset = reloc->address; + } +#endif - assert ((int) fixP->fx_r_type > 0); + gas_assert ((int) fixP->fx_r_type > 0); reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); if (reloc->howto == NULL) @@ -576,7 +604,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS * fixP) bfd_get_reloc_code_name (fixP->fx_r_type)); return NULL; } - assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); + gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); return reloc; } @@ -613,10 +641,41 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP) { /* 'opcode' points to the start of the instruction, whether we need to change the instruction's fixed encoding. */ - bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; + char *opcode = fragP->fr_literal + fragP->fr_fix; + bfd_reloc_code_real_type reloc; subseg_change (sec, 0); + switch (fragP->fr_subtype) + { + case 0: + reloc = BFD_RELOC_CR16_DISP8; + break; + case 1: + /* If the subtype is not changed due to :m operand qualifier, + then no need to update the opcode value. */ + if ((int)opcode[1] != 0x18) + { + opcode[0] = (opcode[0] & 0xf0); + opcode[1] = 0x18; + } + reloc = BFD_RELOC_CR16_DISP16; + break; + case 2: + /* If the subtype is not changed due to :l operand qualifier, + then no need to update the opcode value. */ + if ((int)opcode[1] != 0) + { + opcode[2] = opcode[0]; + opcode[0] = opcode[1]; + opcode[1] = 0x0; + } + reloc = BFD_RELOC_CR16_DISP24; + break; + default: + abort(); + } + fix_new (fragP, fragP->fr_fix, bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)), fragP->fr_symbol, fragP->fr_offset, 1, reloc); @@ -624,6 +683,24 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, fragS *fragP) fragP->fr_fix += md_relax_table[fragP->fr_subtype].rlx_length; } +symbolS * +md_undefined_symbol (char *name) +{ + if (*name == '_' && *(name + 1) == 'G' + && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad (_("GOT already in symbol table")); + GOT_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + } + return GOT_symbol; + } + return 0; +} + /* Process machine-dependent command line options. Called once for each option on the command line that the machine-independent part of GAS does not understand. */ @@ -642,58 +719,10 @@ md_show_usage (FILE *stream ATTRIBUTE_UNUSED) return; } -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *LITP. 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; - int i; - LITTLENUM_TYPE words[4]; - char *t; - - switch (type) - { - case 'f': - prec = 2; - break; - - 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 * 2; - - if (! target_big_endian) - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - else - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - - return NULL; + return ieee_md_atof (type, litP, sizeP, target_big_endian); } /* Apply a fixS (fixup of an instruction or data that we didn't have @@ -706,39 +735,52 @@ void md_apply_fix (fixS *fixP, valueT *valP, segT seg) { valueT val = * valP; - char *buf = fixP->fx_frag->fr_literal + fixP->fx_where; - fixP->fx_offset = 0; - - switch (fixP->fx_r_type) - { - case BFD_RELOC_CR16_NUM8: - bfd_put_8 (stdoutput, (unsigned char) val, buf); - break; - case BFD_RELOC_CR16_NUM16: - bfd_put_16 (stdoutput, val, buf); - break; - case BFD_RELOC_CR16_NUM32: - bfd_put_32 (stdoutput, val, buf); - break; - case BFD_RELOC_CR16_NUM32a: - bfd_put_32 (stdoutput, val, buf); - break; - default: - /* We shouldn't ever get here because linkrelax is nonzero. */ - abort (); - break; - } - - fixP->fx_done = 0; if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) fixP->fx_done = 1; - - if (fixP->fx_pcrel == 1 + else if (fixP->fx_pcrel == 1 && fixP->fx_addsy != NULL && S_GET_SEGMENT (fixP->fx_addsy) == seg) fixP->fx_done = 1; + else + fixP->fx_done = 0; + + if (fixP->fx_addsy != NULL && !fixP->fx_pcrel) + { + val = fixP->fx_offset; + fixP->fx_done = 1; + } + + if (fixP->fx_done) + { + char *buf = fixP->fx_frag->fr_literal + fixP->fx_where; + + fixP->fx_offset = 0; + + switch (fixP->fx_r_type) + { + case BFD_RELOC_CR16_NUM8: + bfd_put_8 (stdoutput, (unsigned char) val, buf); + break; + case BFD_RELOC_CR16_NUM16: + bfd_put_16 (stdoutput, val, buf); + break; + case BFD_RELOC_CR16_NUM32: + bfd_put_32 (stdoutput, val, buf); + break; + case BFD_RELOC_CR16_NUM32a: + bfd_put_32 (stdoutput, val, buf); + break; + default: + /* We shouldn't ever get here because linkrelax is nonzero. */ + abort (); + break; + } + fixP->fx_done = 0; + } + else + fixP->fx_offset = * valP; } /* The location from which a PC relative jump should be calculated, @@ -752,8 +794,8 @@ md_pcrel_from (fixS *fixp) static void initialise_reg_hash_table (struct hash_control ** hash_table, - const reg_entry * register_table, - const unsigned int num_entries) + const reg_entry * register_table, + const unsigned int num_entries) { const reg_entry * reg; const char *hashret; @@ -767,8 +809,8 @@ initialise_reg_hash_table (struct hash_control ** hash_table, { hashret = hash_insert (* hash_table, reg->name, (char *) reg); if (hashret) - as_fatal (_("Internal Error: Can't hash %s: %s"), - reg->name, hashret); + as_fatal (_("Internal Error: Can't hash %s: %s"), + reg->name, hashret); } } @@ -790,7 +832,7 @@ md_begin (void) const char *mnemonic = cr16_instruction[i].mnemonic; hashret = hash_insert (cr16_inst_hash, mnemonic, - (char *)(cr16_instruction + i)); + (char *)(cr16_instruction + i)); if (hashret != NULL && *hashret != '\0') as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic, @@ -832,6 +874,8 @@ process_label_constant (char *str, ins * cr16_ins) int symbol_with_s = 0; int symbol_with_m = 0; int symbol_with_l = 0; + int symbol_with_at_got = 0; + int symbol_with_at_gotc = 0; argument *cur_arg = cr16_ins->arg + cur_arg_num; /* Current argument. */ saved_input_line_pointer = input_line_pointer; @@ -845,7 +889,7 @@ process_label_constant (char *str, ins * cr16_ins) case O_absent: /* Missing or bad expr becomes absolute 0. */ as_bad (_("missing or invalid displacement expression `%s' taken as 0"), - str); + str); cr16_ins->exp.X_op = O_constant; cr16_ins->exp.X_add_number = 0; cr16_ins->exp.X_add_symbol = NULL; @@ -861,115 +905,172 @@ process_label_constant (char *str, ins * cr16_ins) case O_subtract: case O_add: cur_arg->X_op = O_symbol; + cur_arg->constant = cr16_ins->exp.X_add_number; + cr16_ins->exp.X_add_number = 0; cr16_ins->rtype = BFD_RELOC_NONE; relocatable = 1; if (strneq (input_line_pointer, "@c", 2)) - symbol_with_at = 1; + symbol_with_at = 1; if (strneq (input_line_pointer, "@l", 2) - || strneq (input_line_pointer, ":l", 2)) - symbol_with_l = 1; + || strneq (input_line_pointer, ":l", 2)) + symbol_with_l = 1; if (strneq (input_line_pointer, "@m", 2) - || strneq (input_line_pointer, ":m", 2)) - symbol_with_m = 1; + || strneq (input_line_pointer, ":m", 2)) + symbol_with_m = 1; if (strneq (input_line_pointer, "@s", 2) - || strneq (input_line_pointer, ":s", 2)) - symbol_with_s = 1; + || strneq (input_line_pointer, ":s", 2)) + symbol_with_s = 1; - switch (cur_arg->type) - { - case arg_cr: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - { - if (cur_arg->size == 20) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; - } - break; + if (strneq (input_line_pointer, "@cGOT", 5) + || strneq (input_line_pointer, "@cgot", 5)) + { + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); - case arg_crp: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - switch (instruction->size) - { - case 1: - switch (cur_arg->size) - { - case 0: - cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; - break; - case 4: - if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb")) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL4; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a; - break; - default: break; - } - break; - case 2: - cr16_ins->rtype = BFD_RELOC_CR16_REGREL16; - break; - case 3: - if (cur_arg->size == 20) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - else - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; - break; - default: - break; - } - break; + symbol_with_at_gotc = 1; + } + else if (strneq (input_line_pointer, "@GOT", 4) + || strneq (input_line_pointer, "@got", 4)) + { + if ((strneq (input_line_pointer, "+", 1)) + || (strneq (input_line_pointer, "-", 1))) + as_warn (_("GOT bad expression with %s."), input_line_pointer); - case arg_idxr: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; - break; + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); - case arg_idxrp: - if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) - switch (instruction->size) - { - case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break; - case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break; - case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break; - default: break; - } - break; + symbol_with_at_got = 1; + } + + switch (cur_arg->type) + { + case arg_cr: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + { + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; + else if (cur_arg->size == 20) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; + } + break; - case arg_c: - if (IS_INSN_MNEMONIC ("bal")) - cr16_ins->rtype = BFD_RELOC_CR16_DISP24; - else if (IS_INSN_TYPE (BRANCH_INS)) + case arg_crp: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) + { + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; + } else { + switch (instruction->size) + { + case 1: + switch (cur_arg->size) + { + case 0: + cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; + break; + case 4: + if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb")) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL4; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a; + break; + default: break; + } + break; + case 2: + cr16_ins->rtype = BFD_RELOC_CR16_REGREL16; + break; + case 3: + if (cur_arg->size == 20) + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; + else + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a; + break; + default: + break; + } + } + break; + + case arg_idxr: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) { - if (symbol_with_s) - cr16_ins->rtype = BFD_RELOC_CR16_DISP8; - else if (symbol_with_m) - cr16_ins->rtype = BFD_RELOC_CR16_DISP16; + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; else - cr16_ins->rtype = BFD_RELOC_CR16_DISP24; + cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; } - else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS) - || IS_INSN_TYPE (CSTBIT_INS)) + break; + + case arg_idxrp: + if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)) { - if (symbol_with_s) - as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str); - if (symbol_with_m) - cr16_ins->rtype = BFD_RELOC_CR16_ABS20; - else /* Default to (symbol_with_l) */ - cr16_ins->rtype = BFD_RELOC_CR16_ABS24; + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; + else { + switch (instruction->size) + { + case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break; + case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break; + case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break; + default: break; + } } - else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) - cr16_ins->rtype = BFD_RELOC_CR16_DISP4; + } + break; + + case arg_c: + if (IS_INSN_MNEMONIC ("bal")) + cr16_ins->rtype = BFD_RELOC_CR16_DISP24; + else if (IS_INSN_TYPE (BRANCH_INS)) + { + if (symbol_with_l) + cr16_ins->rtype = BFD_RELOC_CR16_DISP24; + else if (symbol_with_m) + cr16_ins->rtype = BFD_RELOC_CR16_DISP16; + else + cr16_ins->rtype = BFD_RELOC_CR16_DISP8; + } + else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS) + || IS_INSN_TYPE (CSTBIT_INS)) + { + if (symbol_with_s) + as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str); + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; + else if (symbol_with_m) + cr16_ins->rtype = BFD_RELOC_CR16_ABS20; + else /* Default to (symbol_with_l) */ + cr16_ins->rtype = BFD_RELOC_CR16_ABS24; + } + else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) + cr16_ins->rtype = BFD_RELOC_CR16_DISP4; break; case arg_ic: if (IS_INSN_TYPE (ARITH_INS)) { - if (symbol_with_s) + if (symbol_with_at_got) + cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20; + else if (symbol_with_at_gotc) + cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20; + else if (symbol_with_s) cr16_ins->rtype = BFD_RELOC_CR16_IMM4; else if (symbol_with_m) cr16_ins->rtype = BFD_RELOC_CR16_IMM20; @@ -979,13 +1080,13 @@ process_label_constant (char *str, ins * cr16_ins) cr16_ins->rtype = BFD_RELOC_CR16_IMM32; } else if (IS_INSN_TYPE (ARITH_BYTE_INS)) - { - cr16_ins->rtype = BFD_RELOC_CR16_IMM16; - } + { + cr16_ins->rtype = BFD_RELOC_CR16_IMM16; + } break; default: break; - } + } break; default: @@ -1029,9 +1130,9 @@ getreg_image (reg r) { case CR16_R_REGTYPE: if (! is_procreg) - return reg->image; + return reg->image; else - IMAGE_ERR; + IMAGE_ERR; case CR16_P_REGTYPE: return reg->image; @@ -1097,10 +1198,10 @@ set_operand (char *operand, ins * cr16_ins) /* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */ if ((cur_arg->type != arg_rbase) - && ((getreg_image (cur_arg->r) == 12) - || (getreg_image (cur_arg->r) == 13) - || (getreg_image (cur_arg->r) == 14) - || (getreg_image (cur_arg->r) == 15))) + && ((getreg_image (cur_arg->r) == 12) + || (getreg_image (cur_arg->r) == 13) + || (getreg_image (cur_arg->r) == 14) + || (getreg_image (cur_arg->r) == 15))) { cur_arg->type = arg_crp; cur_arg->rp = cur_arg->r; @@ -1137,7 +1238,7 @@ set_operand (char *operand, ins * cr16_ins) cur_arg->type = arg_idxrp; } else - cur_arg->rp = -1; + cur_arg->rp = -1; operandE = operandS; /* Set displacement constant. */ @@ -1245,9 +1346,9 @@ parse_operand (char *operand, ins * cr16_ins) { case '$': if (strchr (operand, '(') != NULL) - cur_arg->type = arg_icr; + cur_arg->type = arg_icr; else - cur_arg->type = arg_ic; + cur_arg->type = arg_ic; goto set_params; break; @@ -1439,7 +1540,7 @@ static int is_bcc_insn (char * op) { if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b") - || streq (op, "beq0w") || streq (op, "bnq0w"))) + || streq (op, "beq0w") || streq (op, "bnq0w"))) if ((op[0] == 'b') && (get_b_cc (op) != NULL)) return 1; return 0; @@ -1540,18 +1641,18 @@ getidxregp_image (reg r) if (reg->type == CR16_RP_REGTYPE) { switch (reg->image) - { - case 0: return 0; break; - case 2: return 1; break; - case 4: return 2; break; - case 6: return 3; break; - case 8: return 4; break; - case 10: return 5; break; - case 3: return 6; break; - case 5: return 7; break; - default: - break; - } + { + case 0: return 0; break; + case 2: return 1; break; + case 4: return 2; break; + case 6: return 3; break; + case 8: return 4; break; + case 10: return 5; break; + case 3: return 6; break; + case 5: return 7; break; + default: + break; + } } IDX_RPAIR_IMAGE_ERR; @@ -1612,17 +1713,17 @@ getprocregp_image (reg r) r = r - MAX_REG; switch (r) { - case 4: pregptab_disp = 1; break; - case 6: pregptab_disp = 2; break; - case 8: - case 9: - case 10: - pregptab_disp = 3; break; - case 12: - pregptab_disp = 4; break; - case 14: - pregptab_disp = 5; break; - default: break; + case 4: pregptab_disp = 1; break; + case 6: pregptab_disp = 2; break; + case 8: + case 9: + case 10: + pregptab_disp = 3; break; + case 12: + pregptab_disp = 4; break; + case 14: + pregptab_disp = 5; break; + default: break; } reg = &cr16_pregptab[r - pregptab_disp]; } @@ -1679,16 +1780,16 @@ print_constant (int nbits, int shift, argument *arg) case 32: case 28: /* mask the upper part of the constant, that is, the bits - going to the lowest byte of output_opcode[0]. - The upper part of output_opcode[1] is always filled, - therefore it is always masked with 0xFFFF. */ + going to the lowest byte of output_opcode[0]. + The upper part of output_opcode[1] is always filled, + therefore it is always masked with 0xFFFF. */ mask = (1 << (nbits - 16)) - 1; /* Divide the constant between two consecutive words : - 0 1 2 3 - +---------+---------+---------+---------+ - | | X X X X | x X x X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + 0 1 2 3 + +---------+---------+---------+---------+ + | | X X X X | x X x X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0); CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); @@ -1700,70 +1801,70 @@ print_constant (int nbits, int shift, argument *arg) case 22: case 20: /* mask the upper part of the constant, that is, the bits - going to the lowest byte of output_opcode[0]. - The upper part of output_opcode[1] is always filled, - therefore it is always masked with 0xFFFF. */ + going to the lowest byte of output_opcode[0]. + The upper part of output_opcode[1] is always filled, + therefore it is always masked with 0xFFFF. */ mask = (1 << (nbits - 16)) - 1; /* Divide the constant between two consecutive words : - 0 1 2 3 - +---------+---------+---------+---------+ - | | X X X X | - X - X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + 0 1 2 3 + +---------+---------+---------+---------+ + | | X X X X | - X - X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ if ((instruction->size > 2) && (shift == WORD_SHIFT)) - { - if (arg->type == arg_idxrp) - { - CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0); - CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); - } - else - { - CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0); - CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); - } - } + { + if (arg->type == arg_idxrp) + { + CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0); + CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); + } + else + { + CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0); + CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT); + } + } else - CR16_PRINT (0, constant, shift); + CR16_PRINT (0, constant, shift); break; case 14: if (arg->type == arg_idxrp) - { - if (instruction->size == 2) - { - CR16_PRINT (0, ((constant)&0xf), shift); // 0-3 bits - CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits - CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits - CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits - } - else - CR16_PRINT (0, constant, shift); - } + { + if (instruction->size == 2) + { + CR16_PRINT (0, ((constant) & 0xf), shift); /* 0-3 bits. */ + CR16_PRINT (0, ((constant >> 4) & 0x3), (shift + 20)); /* 4-5 bits. */ + CR16_PRINT (0, ((constant >> 6) & 0x3), (shift + 14)); /* 6-7 bits. */ + CR16_PRINT (0, ((constant >> 8) & 0x3f), (shift + 8)); /* 8-13 bits. */ + } + else + CR16_PRINT (0, constant, shift); + } break; case 16: case 12: /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is - always filling the upper part of output_opcode[1]. If we mistakenly - write it to output_opcode[0], the constant prefix (that is, 'match') - will be overriden. - 0 1 2 3 - +---------+---------+---------+---------+ - | 'match' | | X X X X | | - +---------+---------+---------+---------+ - output_opcode[0] output_opcode[1] */ + always filling the upper part of output_opcode[1]. If we mistakenly + write it to output_opcode[0], the constant prefix (that is, 'match') + will be overriden. + 0 1 2 3 + +---------+---------+---------+---------+ + | 'match' | | X X X X | | + +---------+---------+---------+---------+ + output_opcode[0] output_opcode[1] */ if ((instruction->size > 2) && (shift == WORD_SHIFT)) - CR16_PRINT (1, constant, WORD_SHIFT); + CR16_PRINT (1, constant, WORD_SHIFT); else - CR16_PRINT (0, constant, shift); + CR16_PRINT (0, constant, shift); break; case 8: - CR16_PRINT (0, ((constant/2)&0xf), shift); - CR16_PRINT (0, ((constant/2)>>4), (shift+8)); + CR16_PRINT (0, ((constant / 2) & 0xf), shift); + CR16_PRINT (0, ((constant / 2) >> 4), (shift + 8)); break; default: @@ -1810,35 +1911,35 @@ print_operand (int nbits, int shift, argument *arg) +-----------------------------+ */ if (instruction->size == 3) - { - CR16_PRINT (0, getidxregp_image (arg->rp), 0); - if (getreg_image (arg->i_r) == 12) - CR16_PRINT (0, 0, 3); - else - CR16_PRINT (0, 1, 3); - } + { + CR16_PRINT (0, getidxregp_image (arg->rp), 0); + if (getreg_image (arg->i_r) == 12) + CR16_PRINT (0, 0, 3); + else + CR16_PRINT (0, 1, 3); + } else - { - CR16_PRINT (0, getidxregp_image (arg->rp), 16); - if (getreg_image (arg->i_r) == 12) - CR16_PRINT (0, 0, 19); - else - CR16_PRINT (0, 1, 19); - } + { + CR16_PRINT (0, getidxregp_image (arg->rp), 16); + if (getreg_image (arg->i_r) == 12) + CR16_PRINT (0, 0, 19); + else + CR16_PRINT (0, 1, 19); + } print_constant (nbits, shift, arg); break; case arg_idxr: if (getreg_image (arg->i_r) == 12) - if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") - || IS_INSN_MNEMONIC ("tbitb")) - CR16_PRINT (0, 0, 23); - else CR16_PRINT (0, 0, 24); + if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") + || IS_INSN_MNEMONIC ("tbitb")) + CR16_PRINT (0, 0, 23); + else CR16_PRINT (0, 0, 24); else - if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") - || IS_INSN_MNEMONIC ("tbitb")) - CR16_PRINT (0, 1, 23); - else CR16_PRINT (0, 1, 24); + if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb") + || IS_INSN_MNEMONIC ("tbitb")) + CR16_PRINT (0, 1, 23); + else CR16_PRINT (0, 1, 24); print_constant (nbits, shift, arg); break; @@ -1861,16 +1962,16 @@ print_operand (int nbits, int shift, argument *arg) case arg_crp: print_constant (nbits, shift , arg); if (instruction->size > 1) - CR16_PRINT (0, getregp_image (arg->rp), (shift + 16)); + CR16_PRINT (0, getregp_image (arg->rp), (shift + 16)); else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS))) - { - if (instruction->size == 2) - CR16_PRINT (0, getregp_image (arg->rp), (shift - 8)); - else if (instruction->size == 1) - CR16_PRINT (0, getregp_image (arg->rp), 16); - } + { + if (instruction->size == 2) + CR16_PRINT (0, getregp_image (arg->rp), (shift - 8)); + else if (instruction->size == 1) + CR16_PRINT (0, getregp_image (arg->rp), 16); + } else - CR16_PRINT (0, getregp_image (arg->rp), shift); + CR16_PRINT (0, getregp_image (arg->rp), shift); break; default: @@ -1949,11 +2050,11 @@ check_range (long *num, int bits, int unsigned flags, int update) if (value == 0xB || value == 0x9) return OP_OUT_OF_RANGE; else if (value == -1) - { - if (update) - *num = 9; - return retval; - } + { + if (update) + *num = 9; + return retval; + } } if (flags & OP_ESC1) @@ -1980,7 +2081,7 @@ check_range (long *num, int bits, int unsigned flags, int update) else if (flags & OP_NEG) { max = - 1; - min = - ((1 << (bits - 1))-1); + min = - ((1 << (bits - 1)) - 1); if ((value > max) || (value < min)) retval = OP_OUT_OF_RANGE; } @@ -2011,17 +2112,17 @@ warn_if_needed (ins *insn) unsigned int count = insn->arg[0].constant, reg_val; /* Check if count operand caused to save/retrive the RA twice - to generate warning message. */ + to generate warning message. */ if (insn->nargs > 2) { reg_val = getreg_image (insn->arg[1].r); if ( ((reg_val == 9) && (count > 7)) - || ((reg_val == 10) && (count > 6)) - || ((reg_val == 11) && (count > 5)) - || ((reg_val == 12) && (count > 4)) - || ((reg_val == 13) && (count > 2)) - || ((reg_val == 14) && (count > 0))) + || ((reg_val == 10) && (count > 6)) + || ((reg_val == 11) && (count > 5)) + || ((reg_val == 12) && (count > 4)) + || ((reg_val == 13) && (count > 2)) + || ((reg_val == 14) && (count > 0))) as_warn (_("RA register is saved twice.")); /* Check if the third operand is "RA" or "ra" */ @@ -2036,10 +2137,10 @@ warn_if_needed (ins *insn) /* If register is a register pair ie r12/r13/r14 in operand1, then the count constant should be validated. */ if (((reg_val == 11) && (count > 7)) - || ((reg_val == 12) && (count > 6)) - || ((reg_val == 13) && (count > 4)) - || ((reg_val == 14) && (count > 2)) - || ((reg_val == 15) && (count > 0))) + || ((reg_val == 12) && (count > 6)) + || ((reg_val == 13) && (count > 4)) + || ((reg_val == 14) && (count > 2)) + || ((reg_val == 15) && (count > 0))) as_bad (_("`%s' Illegal count-register combination."), ins_parse); } else @@ -2187,14 +2288,14 @@ assemble_insn (char *mnemonic, ins *insn) /* If 'bal' instruction size is '2' and reg operand is not 'ra' then goto next instruction. */ if (IS_INSN_MNEMONIC ("bal") && (i == 0) - && (instruction->size == 2) && (insn->arg[i].rp != 14)) + && (instruction->size == 2) && (insn->arg[i].rp != 14)) goto next_insn; /* If 'storb' instruction with 'sp' reg and 16-bit disp of * reg-pair, leads to undifined trap, so this should use * 20-bit disp of reg-pair. */ if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2) - && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp)) + && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp)) goto next_insn; /* Only check range - don't update the constant's value, since the @@ -2216,7 +2317,7 @@ assemble_insn (char *mnemonic, ins *insn) determined) is sufficient. */ else if ((insn->arg[i].X_op == O_symbol) && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize - > cur_size[i])) + > cur_size[i])) goto next_insn; } found_const_within_range = 1; @@ -2241,15 +2342,15 @@ next_insn: { switch (const_err) { - case OP_OUT_OF_RANGE: - as_bad (_("Operand out of range (arg %d)"), invalid_const); - break; - case OP_NOT_EVEN: - as_bad (_("Operand has odd displacement (arg %d)"), invalid_const); - break; - default: - as_bad (_("Illegal operand (arg %d)"), invalid_const); - break; + case OP_OUT_OF_RANGE: + as_bad (_("Operand out of range (arg %d)"), invalid_const); + break; + case OP_NOT_EVEN: + as_bad (_("Operand has odd displacement (arg %d)"), invalid_const); + break; + default: + as_bad (_("Illegal operand (arg %d)"), invalid_const); + break; } } @@ -2321,28 +2422,61 @@ print_insn (ins *insn) words[j++] = output_opcode[i] & 0xFFFF; } - insn_size = instruction->size; - this_frag = frag_more (insn_size * 2); - /* Handle relocation. */ - if ((relocatable) && (insn->rtype != BFD_RELOC_NONE)) + if ((instruction->flags & RELAXABLE) && relocatable) + { + int relax_subtype; + /* Write the maximal instruction size supported. */ + insn_size = INSN_MAX_SIZE; + + if (IS_INSN_TYPE (BRANCH_INS)) + { + switch (insn->rtype) + { + case BFD_RELOC_CR16_DISP24: + relax_subtype = 2; + break; + case BFD_RELOC_CR16_DISP16: + relax_subtype = 1; + break; + default: + relax_subtype = 0; + break; + } + } + else + abort (); + + this_frag = frag_var (rs_machine_dependent, insn_size *2, + 4, relax_subtype, + insn->exp.X_add_symbol, + 0, + 0); + } + else { - reloc_howto_type *reloc_howto; - int size; + insn_size = instruction->size; + this_frag = frag_more (insn_size * 2); - reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype); + if ((relocatable) && (insn->rtype != BFD_RELOC_NONE)) + { + reloc_howto_type *reloc_howto; + int size; - if (!reloc_howto) - abort (); + reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype); + + if (!reloc_howto) + abort (); - size = bfd_get_reloc_size (reloc_howto); + size = bfd_get_reloc_size (reloc_howto); - if (size < 1 || size > 4) - abort (); + if (size < 1 || size > 4) + abort (); - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn->exp, reloc_howto->pc_relative, - insn->rtype); + fix_new_exp (frag_now, this_frag - frag_now->fr_literal, + size, &insn->exp, reloc_howto->pc_relative, + insn->rtype); + } } /* Verify a 2-byte code alignment. */ @@ -2410,14 +2544,14 @@ md_assemble (char *op) instruction = (const inst *) hash_find (cr16_inst_hash, op); parse_operands (&cr16_ins, param1); if (((&cr16_ins)->arg[0].type == arg_ic) - && ((&cr16_ins)->arg[0].constant >= 0)) + && ((&cr16_ins)->arg[0].constant >= 0)) { if (streq ("lshb", op)) - op = "ashub"; + op = "ashub"; else if (streq ("lshd", op)) - op = "ashud"; - else - op = "ashuw"; + op = "ashud"; + else + op = "ashuw"; } }