diff options
Diffstat (limited to 'contrib/binutils/gas/config/tc-v850.c')
-rw-r--r-- | contrib/binutils/gas/config/tc-v850.c | 836 |
1 files changed, 708 insertions, 128 deletions
diff --git a/contrib/binutils/gas/config/tc-v850.c b/contrib/binutils/gas/config/tc-v850.c index 18ec114..e53054d 100644 --- a/contrib/binutils/gas/config/tc-v850.c +++ b/contrib/binutils/gas/config/tc-v850.c @@ -1,5 +1,5 @@ /* tc-v850.c -- Assembler code for the NEC V850 - Copyright (C) 1996, 1997, 1998 Free Software Foundation. + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation. This file is part of GAS, the GNU Assembler. @@ -95,6 +95,8 @@ static segT rozdata_section = NULL; static segT scommon_section = NULL; static segT tcommon_section = NULL; static segT zcommon_section = NULL; +static segT call_table_data_section = NULL; +static segT call_table_text_section = NULL; /* fixups */ #define MAX_INSN_FIXUPS (5) @@ -189,6 +191,25 @@ v850_rozdata (int ignore) demand_empty_rest_of_line (); } +void +v850_call_table_data (int ignore) +{ + obj_elf_section_change_hook(); + + subseg_set (call_table_data_section, (subsegT) get_absolute_expression ()); + + demand_empty_rest_of_line (); +} + +void +v850_call_table_text (int ignore) +{ + obj_elf_section_change_hook(); + + subseg_set (call_table_text_section, (subsegT) get_absolute_expression ()); + + demand_empty_rest_of_line (); +} void v850_bss (int ignore) @@ -230,42 +251,54 @@ v850_comm (area) name = input_line_pointer; c = get_symbol_end (); + /* just after name is now '\0' */ p = input_line_pointer; *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') { - as_bad ("Expected comma after symbol-name"); + as_bad (_("Expected comma after symbol-name")); ignore_rest_of_line (); return; } - input_line_pointer++; /* skip ',' */ + + input_line_pointer ++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) { - as_bad (".COMMon length (%d.) <0! Ignored.", temp); + /* xgettext:c-format */ + as_bad (_(".COMMon length (%d.) < 0! Ignored."), temp); ignore_rest_of_line (); return; } + size = temp; *p = 0; symbolP = symbol_find_or_make (name); *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { - as_bad ("Ignoring attempt to re-define symbol"); + as_bad (_("Ignoring attempt to re-define symbol")); ignore_rest_of_line (); return; } + if (S_GET_VALUE (symbolP) != 0) { if (S_GET_VALUE (symbolP) != size) { - as_warn ("Length of .comm \"%s\" is already %ld. Not changed to %d.", + /* xgettext:c-format */ + as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); } } - know (symbolP->sy_frag == &zero_address_frag); + + know (symbol_get_frag (symbolP) == & zero_address_frag); + if (*input_line_pointer != ',') have_align = 0; else @@ -274,6 +307,7 @@ v850_comm (area) input_line_pointer++; SKIP_WHITESPACE (); } + if (! have_align || *input_line_pointer != '"') { if (! have_align) @@ -281,35 +315,81 @@ v850_comm (area) else { temp = get_absolute_expression (); + if (temp < 0) { temp = 0; - as_warn ("Common alignment negative; 0 assumed"); + as_warn (_("Common alignment negative; 0 assumed")); } } - if (symbolP->local) + + if (symbol_get_obj (symbolP)->local) { segT old_sec; int old_subsec; char * pfrag; int align; + flagword applicable; - /* allocate_bss: */ old_sec = now_seg; old_subsec = now_subseg; + + applicable = bfd_applicable_section_flags (stdoutput); + + applicable &= SEC_ALLOC; + + switch (area) + { + case AREA_SDA: + if (sbss_section == NULL) + { + sbss_section = subseg_new (".sbss", 0); + + bfd_set_section_flags (stdoutput, sbss_section, applicable); + + seg_info (sbss_section)->bss = 1; + } + break; + + case AREA_ZDA: + if (zbss_section == NULL) + { + zbss_section = subseg_new (".zbss", 0); + + bfd_set_section_flags (stdoutput, sbss_section, applicable); + + seg_info (zbss_section)->bss = 1; + } + break; + + case AREA_TDA: + if (tbss_section == NULL) + { + tbss_section = subseg_new (".tbss", 0); + + bfd_set_section_flags (stdoutput, tbss_section, applicable); + + seg_info (tbss_section)->bss = 1; + } + break; + } + if (temp) { /* convert to a power of 2 alignment */ - for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); + for (align = 0; (temp & 1) == 0; temp >>= 1, ++align) + ; + if (temp != 1) { - as_bad ("Common alignment not a power of 2"); + as_bad (_("Common alignment not a power of 2")); ignore_rest_of_line (); return; } } else align = 0; + switch (area) { case AREA_SDA: @@ -341,24 +421,24 @@ v850_comm (area) { case AREA_SDA: if (S_GET_SEGMENT (symbolP) == sbss_section) - symbolP->sy_frag->fr_symbol = 0; + symbol_get_frag (symbolP)->fr_symbol = 0; break; case AREA_ZDA: if (S_GET_SEGMENT (symbolP) == zbss_section) - symbolP->sy_frag->fr_symbol = 0; + symbol_get_frag (symbolP)->fr_symbol = 0; break; case AREA_TDA: if (S_GET_SEGMENT (symbolP) == tbss_section) - symbolP->sy_frag->fr_symbol = 0; + symbol_get_frag (symbolP)->fr_symbol = 0; break; default: - abort(); + abort (); } - symbolP->sy_frag = frag_now; + symbol_set_frag (symbolP, frag_now); pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, (offsetT) size, (char *) 0); *pfrag = 0; @@ -366,9 +446,18 @@ v850_comm (area) switch (area) { - case AREA_SDA: S_SET_SEGMENT (symbolP, sbss_section); break; - case AREA_ZDA: S_SET_SEGMENT (symbolP, zbss_section); break; - case AREA_TDA: S_SET_SEGMENT (symbolP, tbss_section); break; + case AREA_SDA: + S_SET_SEGMENT (symbolP, sbss_section); + break; + + case AREA_ZDA: + S_SET_SEGMENT (symbolP, zbss_section); + break; + + case AREA_TDA: + S_SET_SEGMENT (symbolP, tbss_section); + break; + default: abort(); } @@ -386,9 +475,54 @@ v850_comm (area) switch (area) { - case AREA_SDA: S_SET_SEGMENT (symbolP, scommon_section); break; - case AREA_ZDA: S_SET_SEGMENT (symbolP, zcommon_section); break; - case AREA_TDA: S_SET_SEGMENT (symbolP, tcommon_section); break; + case AREA_SDA: + if (scommon_section == NULL) + { + flagword applicable; + + applicable = bfd_applicable_section_flags (stdoutput); + + scommon_section = subseg_new (".scommon", 0); + + bfd_set_section_flags (stdoutput, scommon_section, applicable + & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS) | SEC_IS_COMMON); + } + S_SET_SEGMENT (symbolP, scommon_section); + break; + + case AREA_ZDA: + if (zcommon_section == NULL) + { + flagword applicable; + + applicable = bfd_applicable_section_flags (stdoutput); + + zcommon_section = subseg_new (".zcommon", 0); + + bfd_set_section_flags (stdoutput, zcommon_section, applicable + & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS) | SEC_IS_COMMON); + } + S_SET_SEGMENT (symbolP, zcommon_section); + break; + + case AREA_TDA: + if (tcommon_section == NULL) + { + flagword applicable; + + applicable = bfd_applicable_section_flags (stdoutput); + + tcommon_section = subseg_new (".tcommon", 0); + + bfd_set_section_flags (stdoutput, tcommon_section, applicable + & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS) | SEC_IS_COMMON); + } + S_SET_SEGMENT (symbolP, tcommon_section); + break; + default: abort(); } @@ -414,7 +548,7 @@ v850_comm (area) goto allocate_common; } - symbolP->bsym->flags |= BSF_OBJECT; + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; demand_empty_rest_of_line (); return; @@ -426,7 +560,7 @@ v850_comm (area) p++; c = *p; *p = '\0'; - as_bad ("bad .common segment %s", input_line_pointer + 1); + as_bad (_("bad .common segment %s"), input_line_pointer + 1); *p = c; input_line_pointer = p; ignore_rest_of_line (); @@ -443,6 +577,8 @@ set_machine (int number) switch (machine) { case 0: processor_mask = PROCESSOR_V850; break; + case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break; + case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break; } } @@ -464,6 +600,10 @@ const pseudo_typeS md_pseudo_table[] = {"scomm", v850_comm, AREA_SDA}, {"tcomm", v850_comm, AREA_TDA}, {"v850", set_machine, 0}, + {"call_table_data", v850_call_table_data, 0}, + {"call_table_text", v850_call_table_text, 0}, + {"v850e", set_machine, bfd_mach_v850e}, + {"v850ea", set_machine, bfd_mach_v850ea}, { NULL, NULL, 0} }; @@ -518,6 +658,11 @@ static const struct reg_name pre_defined_registers[] = static const struct reg_name system_registers[] = { + { "ctbp", 20 }, + { "ctpc", 16 }, + { "ctpsw", 17 }, + { "dbpc", 18 }, + { "dbpsw", 19 }, { "ecr", 4 }, { "eipc", 0 }, { "eipsw", 1 }, @@ -527,6 +672,12 @@ static const struct reg_name system_registers[] = }; #define SYSREG_NAME_CNT (sizeof (system_registers) / sizeof (struct reg_name)) +static const struct reg_name system_list_registers[] = +{ + {"PS", 5 }, + {"SR", 0 + 1} +}; +#define SYSREGLIST_NAME_CNT (sizeof (system_list_registers) / sizeof (struct reg_name)) static const struct reg_name cc_names[] = { @@ -575,17 +726,19 @@ reg_name_search (regs, regcount, name, accept_numbers) { /* If the symbol is an alias for another name then use that. If the symbol is an alias for a number, then return the number. */ - if (symbolP->sy_value.X_op == O_symbol) + if (symbol_equated_p (symbolP)) { - name = S_GET_NAME (symbolP->sy_value.X_add_symbol); + name = S_GET_NAME (symbol_get_value_expression (symbolP)->X_add_symbol); } else if (accept_numbers) { int reg = S_GET_VALUE (symbolP); - + if (reg >= 0 && reg <= 31) return reg; } + + /* Otherwise drop through and try parsing name normally. */ } low = 0; @@ -662,6 +815,8 @@ register_name (expressionP) * in: Input_line_pointer points to 1st char of operand. * expressionP points to an expression structure to be filled in. * accept_numbers is true iff numerical register names may be used. + * accept_list_names is true iff the special names PS and SR may be + * accepted. * * out: A expressionS structure in expressionP. * The operand may have been a register: in this case, X_op == O_register, @@ -670,10 +825,10 @@ register_name (expressionP) * its original state. */ static boolean -system_register_name (expressionP, accept_numbers - ) +system_register_name (expressionP, accept_numbers, accept_list_names) expressionS * expressionP; boolean accept_numbers; + boolean accept_list_names; { int reg_number; char * name; @@ -701,13 +856,23 @@ system_register_name (expressionP, accept_numbers /* Make sure that the register number is allowable. */ if ( reg_number < 0 || reg_number > 5 + && reg_number < 16 + || reg_number > 20 ) { reg_number = -1; } } + else if (accept_list_names) + { + c = get_symbol_end (); + reg_number = reg_name_search (system_list_registers, + SYSREGLIST_NAME_CNT, name, FALSE); + + * input_line_pointer = c; /* put back the delimiting char */ + } } - + /* look to see if it's in the register table */ if (reg_number >= 0) { @@ -785,6 +950,226 @@ skip_white_space (void) ++ input_line_pointer; } +/* Summary of parse_register_list (). + * + * in: Input_line_pointer points to 1st char of a list of registers. + * insn is the partially constructed instruction. + * operand is the operand being inserted. + * + * out: NULL if the parse completed successfully, otherwise a + * pointer to an error message is returned. If the parse + * completes the correct bit fields in the instruction + * will be filled in. + * + * Parses register lists with the syntax: + * + * { rX } + * { rX, rY } + * { rX - rY } + * { rX - rY, rZ } + * etc + * + * and also parses constant epxressions whoes bits indicate the + * registers in the lists. The LSB in the expression refers to + * the lowest numbered permissable register in the register list, + * and so on upwards. System registers are considered to be very + * high numbers. + * + */ +static char * +parse_register_list +( + unsigned long * insn, + const struct v850_operand * operand +) +{ + static int type1_regs[ 32 ] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; + static int type2_regs[ 32 ] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; + static int type3_regs[ 32 ] = { 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8 }; + int * regs; + expressionS exp; + + + /* Select a register array to parse. */ + switch (operand->shift) + { + case 0xffe00001: regs = type1_regs; break; + case 0xfff8000f: regs = type2_regs; break; + case 0xfff8001f: regs = type3_regs; break; + default: + as_bad (_("unknown operand shift: %x\n"), operand->shift); + return _("internal failure in parse_register_list"); + } + + skip_white_space (); + + /* If the expression starts with a curly brace it is a register list. + Otherwise it is a constant expression, whoes bits indicate which + registers are to be included in the list. */ + + if (* input_line_pointer != '{') + { + int bits; + int reg; + int i; + + expression (& exp); + + if (exp.X_op != O_constant) + return _("constant expression or register list expected"); + + if (regs == type1_regs) + { + if (exp.X_add_number & 0xFFFFF000) + return _("high bits set in register list expression"); + + for (reg = 20; reg < 32; reg ++) + if (exp.X_add_number & (1 << (reg - 20))) + { + for (i = 0; i < 32; i++) + if (regs[i] == reg) + * insn |= (1 << i); + } + } + else if (regs == type2_regs) + { + if (exp.X_add_number & 0xFFFE0000) + return _("high bits set in register list expression"); + + for (reg = 1; reg < 16; reg ++) + if (exp.X_add_number & (1 << (reg - 1))) + { + for (i = 0; i < 32; i++) + if (regs[i] == reg) + * insn |= (1 << i); + } + + if (exp.X_add_number & (1 << 15)) + * insn |= (1 << 3); + + if (exp.X_add_number & (1 << 16)) + * insn |= (1 << 19); + } + else /* regs == type3_regs */ + { + if (exp.X_add_number & 0xFFFE0000) + return _("high bits set in register list expression"); + + for (reg = 16; reg < 32; reg ++) + if (exp.X_add_number & (1 << (reg - 16))) + { + for (i = 0; i < 32; i++) + if (regs[i] == reg) + * insn |= (1 << i); + } + + if (exp.X_add_number & (1 << 16)) + * insn |= (1 << 19); + } + + return NULL; + } + + input_line_pointer ++; + + /* Parse the register list until a terminator (closing curly brace or + new-line) is found. */ + for (;;) + { + if (register_name (& exp)) + { + int i; + + /* Locate the given register in the list, and if it is there, + insert the corresponding bit into the instruction. */ + for (i = 0; i < 32; i++) + { + if (regs[ i ] == exp.X_add_number) + { + * insn |= (1 << i); + break; + } + } + + if (i == 32) + { + return _("illegal register included in list"); + } + } + else if (system_register_name (& exp, true, true)) + { + if (regs == type1_regs) + { + return _("system registers cannot be included in list"); + } + else if (exp.X_add_number == 5) + { + if (regs == type2_regs) + return _("PSW cannot be included in list"); + else + * insn |= 0x8; + } + else if (exp.X_add_number < 4) + * insn |= 0x80000; + else + return _("High value system registers cannot be included in list"); + } + else if (* input_line_pointer == '}') + { + input_line_pointer ++; + break; + } + else if (* input_line_pointer == ',') + { + input_line_pointer ++; + continue; + } + else if (* input_line_pointer == '-') + { + /* We have encountered a range of registers: rX - rY */ + int j; + expressionS exp2; + + /* Skip the dash. */ + ++ input_line_pointer; + + /* Get the second register in the range. */ + if (! register_name (& exp2)) + { + return _("second register should follow dash in register list"); + exp2.X_add_number = exp.X_add_number; + } + + /* Add the rest of the registers in the range. */ + for (j = exp.X_add_number + 1; j <= exp2.X_add_number; j++) + { + int i; + + /* Locate the given register in the list, and if it is there, + insert the corresponding bit into the instruction. */ + for (i = 0; i < 32; i++) + { + if (regs[ i ] == j) + { + * insn |= (1 << i); + break; + } + } + + if (i == 32) + return _("illegal register included in list"); + } + } + else + { + break; + } + + skip_white_space (); + } + + return NULL; +} CONST char * md_shortopts = "m:"; @@ -799,11 +1184,14 @@ void md_show_usage (stream) FILE * stream; { - fprintf (stream, "V850 options:\n"); - fprintf (stream, "\t-mwarn-signed-overflow Warn if signed immediate values overflow\n"); - fprintf (stream, "\t-mwarn-unsigned-overflow Warn if unsigned immediate values overflow\n"); - fprintf (stream, "\t-mv850 The code is targeted at the v850\n"); -} + fprintf (stream, _(" V850 options:\n")); + fprintf (stream, _(" -mwarn-signed-overflow Warn if signed immediate values overflow\n")); + fprintf (stream, _(" -mwarn-unsigned-overflow Warn if unsigned immediate values overflow\n")); + fprintf (stream, _(" -mv850 The code is targeted at the v850\n")); + fprintf (stream, _(" -mv850e The code is targeted at the v850e\n")); + fprintf (stream, _(" -mv850ea The code is targeted at the v850ea\n")); + fprintf (stream, _(" -mv850any The code is generic, despite any processor specific instructions\n")); +} int md_parse_option (c, arg) @@ -812,7 +1200,8 @@ md_parse_option (c, arg) { if (c != 'm') { - fprintf (stderr, "unknown command line option: -%c%s\n", c, arg); + /* xgettext:c-format */ + fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg); return 0; } @@ -829,9 +1218,25 @@ md_parse_option (c, arg) machine = 0; processor_mask = PROCESSOR_V850; } + else if (strcmp (arg, "v850e") == 0) + { + machine = bfd_mach_v850e; + processor_mask = PROCESSOR_V850E; + } + else if (strcmp (arg, "v850ea") == 0) + { + machine = bfd_mach_v850ea; + processor_mask = PROCESSOR_V850EA; + } + else if (strcmp (arg, "v850any") == 0) + { + machine = 0; /* Tell the world that this is for any v850 chip. */ + processor_mask = PROCESSOR_V850EA; /* But support instructions for the extended versions. */ + } else { - fprintf (stderr, "unknown command line option: -%c%s\n", c, arg); + /* xgettext:c-format */ + fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg); return 0; } @@ -868,7 +1273,7 @@ md_atof (type, litp, sizep) default: *sizep = 0; - return "bad call to md_atof"; + return _("bad call to md_atof"); } t = atof_ieee (input_line_pointer, type, words); @@ -923,8 +1328,8 @@ md_convert_frag (abfd, sec, fragP) target. */ md_number_to_chars (buffer + 2, 0x00000780, 4); fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int) fragP->fr_opcode - + 1); + fragP->fr_offset, 1, BFD_RELOC_UNUSED + + (int) fragP->fr_opcode + 1); fragP->fr_var = 0; fragP->fr_fix += 6; } @@ -933,8 +1338,8 @@ md_convert_frag (abfd, sec, fragP) { md_number_to_chars (fragP->fr_fix + fragP->fr_literal, 0x00000780, 4); fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int) fragP->fr_opcode - + 1); + fragP->fr_offset, 1, BFD_RELOC_UNUSED + + (int) fragP->fr_opcode + 1); fragP->fr_var = 0; fragP->fr_fix += 4; } @@ -958,6 +1363,23 @@ md_begin () register const struct v850_opcode * op; flagword applicable; + if (strncmp (TARGET_CPU, "v850ea", 6) == 0) + { + if (machine == -1) + machine = bfd_mach_v850ea; + + if (processor_mask == -1) + processor_mask = PROCESSOR_V850EA; + } + else if (strncmp (TARGET_CPU, "v850e", 5) == 0) + { + if (machine == -1) + machine = bfd_mach_v850e; + + if (processor_mask == -1) + processor_mask = PROCESSOR_V850E; + } + else if (strncmp (TARGET_CPU, "v850", 4) == 0) { if (machine == -1) @@ -967,7 +1389,8 @@ md_begin () processor_mask = PROCESSOR_V850; } else - as_bad ("Unable to determine default target processor from string: %s", + /* xgettext:c-format */ + as_bad (_("Unable to determine default target processor from string: %s"), TARGET_CPU); v850_hash = hash_new(); @@ -991,57 +1414,49 @@ md_begin () bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine); applicable = bfd_applicable_section_flags (stdoutput); - - sdata_section = subseg_new (".sdata", 0); - bfd_set_section_flags (stdoutput, sdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)); - tdata_section = subseg_new (".tdata", 0); - bfd_set_section_flags (stdoutput, tdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)); + call_table_data_section = subseg_new (".call_table_data", 0); + bfd_set_section_flags (stdoutput, call_table_data_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_DATA | SEC_HAS_CONTENTS)); - zdata_section = subseg_new (".zdata", 0); - bfd_set_section_flags (stdoutput, zdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)); + call_table_text_section = subseg_new (".call_table_text", 0); + bfd_set_section_flags (stdoutput, call_table_text_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_CODE)); - sbss_section = subseg_new (".sbss", 0); - bfd_set_section_flags (stdoutput, sbss_section, applicable & SEC_ALLOC); - seg_info (sbss_section)->bss = 1; - - tbss_section = subseg_new (".tbss", 0); - bfd_set_section_flags (stdoutput, tbss_section, applicable & SEC_ALLOC); - seg_info (tbss_section)->bss = 1; - - zbss_section = subseg_new (".zbss", 0); - bfd_set_section_flags (stdoutput, zbss_section, applicable & SEC_ALLOC); - seg_info (zbss_section)->bss = 1; - - rosdata_section = subseg_new (".rosdata", 0); - bfd_set_section_flags (stdoutput, rosdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY)); - - rozdata_section = subseg_new (".rozdata", 0); - bfd_set_section_flags (stdoutput, rozdata_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY)); - - scommon_section = subseg_new (".scommon", 0); - bfd_set_section_flags (stdoutput, scommon_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS | SEC_IS_COMMON)); + /* Restore text section as the current default. */ + subseg_set (text_section, 0); +} - zcommon_section = subseg_new (".zcommon", 0); - bfd_set_section_flags (stdoutput, zcommon_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS | SEC_IS_COMMON)); - tcommon_section = subseg_new (".tcommon", 0); - bfd_set_section_flags (stdoutput, tcommon_section, applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS | SEC_IS_COMMON)); +static bfd_reloc_code_real_type +handle_ctoff (const struct v850_operand * operand) +{ + if (operand == NULL) + return BFD_RELOC_V850_CALLT_16_16_OFFSET; + if ( operand->bits != 6 + || operand->shift != 0) + { + as_bad (_("ctoff() relocation used on an instruction which does not support it")); + return BFD_RELOC_64; /* Used to indicate an error condition. */ + } + + return BFD_RELOC_V850_CALLT_6_7_OFFSET; } - - static bfd_reloc_code_real_type handle_sdaoff (const struct v850_operand * operand) { if (operand == NULL) return BFD_RELOC_V850_SDA_16_16_OFFSET; if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_SDA_15_16_OFFSET; + if (operand->bits == -1) return BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET; if ( operand->bits != 16 || operand->shift != 16) { - as_bad ("sdaoff() relocation used on an instruction which does not support it"); + as_bad (_("sdaoff() relocation used on an instruction which does not support it")); return BFD_RELOC_64; /* Used to indicate an error condition. */ } @@ -1053,11 +1468,12 @@ handle_zdaoff (const struct v850_operand * operand) { if (operand == NULL) return BFD_RELOC_V850_ZDA_16_16_OFFSET; if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_ZDA_15_16_OFFSET; + if (operand->bits == -1) return BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET; if ( operand->bits != 16 || operand->shift != 16) { - as_bad ("zdaoff() relocation used on an instruction which does not support it"); + as_bad (_("zdaoff() relocation used on an instruction which does not support it")); return BFD_RELOC_64; /* Used to indicate an error condition. */ } @@ -1069,11 +1485,13 @@ handle_tdaoff (const struct v850_operand * operand) { if (operand == NULL) return BFD_RELOC_V850_TDA_7_7_OFFSET; /* data item, not an instruction. */ if (operand->bits == 6 && operand->shift == 1) return BFD_RELOC_V850_TDA_6_8_OFFSET; /* sld.w/sst.w, operand: D8_6 */ + if (operand->bits == 4 && operand->insert != NULL) return BFD_RELOC_V850_TDA_4_5_OFFSET; /* sld.hu, operand: D5-4 */ + if (operand->bits == 4 && operand->insert == NULL) return BFD_RELOC_V850_TDA_4_4_OFFSET; /* sld.bu, operand: D4 */ if (operand->bits == 16 && operand->shift == 16) return BFD_RELOC_V850_TDA_16_16_OFFSET; /* set1 & chums, operands: D16 */ if (operand->bits != 7) { - as_bad ("tdaoff() relocation used on an instruction which does not support it"); + as_bad (_("tdaoff() relocation used on an instruction which does not support it")); return BFD_RELOC_64; /* Used to indicate an error condition. */ } @@ -1112,7 +1530,8 @@ v850_reloc_prefix (const struct v850_operand * operand) CHECK_ ("sdaoff", handle_sdaoff (operand)); CHECK_ ("zdaoff", handle_zdaoff (operand)); CHECK_ ("tdaoff", handle_tdaoff (operand)); - + CHECK_ ("hilo", BFD_RELOC_32); + CHECK_ ("ctoff", handle_ctoff (operand)); /* Restore skipped parenthesis. */ if (paren_skipped) @@ -1195,7 +1614,8 @@ v850_insert_operand (insn, operand, val, file, line, str) if (val < (offsetT) min || val > (offsetT) max) { - const char * err = "operand out of range (%s not between %ld and %ld)"; + /* xgettext:c-format */ + const char * err = _("operand out of range (%s not between %ld and %ld)"); char buf[100]; /* Restore min and mix to expected values for decimal ranges. */ @@ -1267,7 +1687,8 @@ md_assemble (str) opcode = (struct v850_opcode *) hash_find (v850_hash, str); if (opcode == NULL) { - as_bad ("Unrecognized opcode: `%s'", str); + /* xgettext:c-format */ + as_bad (_("Unrecognized opcode: `%s'"), str); ignore_rest_of_line (); return; } @@ -1288,7 +1709,7 @@ md_assemble (str) if ((opcode->processors & processor_mask) == 0) { - errmsg = "Target processor does not support this instruction."; + errmsg = _("Target processor does not support this instruction."); goto error; } @@ -1333,7 +1754,7 @@ md_assemble (str) if ((reloc = v850_reloc_prefix (operand)) != BFD_RELOC_UNUSED) { /* This is a fake reloc, used to indicate an error condition. */ - if (reloc == BFD_RELOC_64) + if (reloc == BFD_RELOC_64) { match = 1; goto error; @@ -1375,22 +1796,50 @@ md_assemble (str) break; } + case BFD_RELOC_32: + if ((operand->flags & V850E_IMMEDIATE32) == 0) + { + errmsg = _("immediate operand is too large"); + goto error; + } + + extra_data_after_insn = true; + extra_data_len = 4; + extra_data = ex.X_add_number; + ex.X_add_number = 0; + break; default: fprintf (stderr, "reloc: %d\n", reloc); - as_bad ("AAARG -> unhandled constant reloc"); + as_bad (_("AAARG -> unhandled constant reloc")); break; } - insn = v850_insert_operand (insn, operand, ex.X_add_number, - (char *) NULL, 0, - copy_of_instruction); + if (fc > MAX_INSN_FIXUPS) + as_fatal (_("too many fixups")); + + fixups[ fc ].exp = ex; + fixups[ fc ].opindex = * opindex_ptr; + fixups[ fc ].reloc = reloc; + fc++; } else { + if (reloc == BFD_RELOC_32) + { + if ((operand->flags & V850E_IMMEDIATE32) == 0) + { + errmsg = _("immediate operand is too large"); + goto error; + } + + extra_data_after_insn = true; + extra_data_len = 4; + extra_data = ex.X_add_number; + } if (fc > MAX_INSN_FIXUPS) - as_fatal ("too many fixups"); + as_fatal (_("too many fixups")); fixups[ fc ].exp = ex; fixups[ fc ].opindex = * opindex_ptr; @@ -1406,12 +1855,12 @@ md_assemble (str) { if (!register_name (& ex)) { - errmsg = "invalid register name"; + errmsg = _("invalid register name"); } else if ((operand->flags & V850_NOT_R0) && ex.X_add_number == 0) { - errmsg = "register r0 cannot be used here"; + errmsg = _("register r0 cannot be used here"); /* Force an error message to be generated by skipping over any following potential matches @@ -1421,10 +1870,9 @@ md_assemble (str) } else if ((operand->flags & V850_OPERAND_SRG) != 0) { - if (!system_register_name (& ex, true - )) + if (!system_register_name (& ex, true, false)) { - errmsg = "invalid system register name"; + errmsg = _("invalid system register name"); } } else if ((operand->flags & V850_OPERAND_EP) != 0) @@ -1437,7 +1885,7 @@ md_assemble (str) /* Put things back the way we found them. */ *input_line_pointer = c; input_line_pointer = start; - errmsg = "expected EP register"; + errmsg = _("expected EP register"); goto error; } @@ -1445,8 +1893,7 @@ md_assemble (str) str = input_line_pointer; input_line_pointer = hold; - while ( *str == ' ' || *str == ',' || *str == '[' - || *str == ']') + while (*str == ' ' || *str == ',' || *str == '[' || *str == ']') ++ str; continue; } @@ -1454,19 +1901,72 @@ md_assemble (str) { if (!cc_name (& ex)) { - errmsg = "invalid condition code name"; + errmsg = _("invalid condition code name"); } } + else if (operand->flags & V850E_PUSH_POP) + { + errmsg = parse_register_list (& insn, operand); + + /* The parse_register_list() function has already done + everything, so fake a dummy expression. */ + ex.X_op = O_constant; + ex.X_add_number = 0; + } + else if (operand->flags & V850E_IMMEDIATE16) + { + expression (& ex); + + if (ex.X_op != O_constant) + errmsg = _("constant expression expected"); + else if (ex.X_add_number & 0xffff0000) + { + if (ex.X_add_number & 0xffff) + errmsg = _("constant too big to fit into instruction"); + else if ((insn & 0x001fffc0) == 0x00130780) + ex.X_add_number >>= 16; + else + errmsg = _("constant too big to fit into instruction"); + } + + extra_data_after_insn = true; + extra_data_len = 2; + extra_data = ex.X_add_number; + ex.X_add_number = 0; + } + else if (operand->flags & V850E_IMMEDIATE32) + { + expression (& ex); + + if (ex.X_op != O_constant) + errmsg = _("constant expression expected"); + + extra_data_after_insn = true; + extra_data_len = 4; + extra_data = ex.X_add_number; + ex.X_add_number = 0; + } else if (register_name (& ex) && (operand->flags & V850_OPERAND_REG) == 0) { + char c; + int exists = 0; + /* It is possible that an alias has been defined that matches a register name. For example the code may include a ".set ZERO, 0" directive, which matches the register name "zero". Attempt to reparse the field as an expression, and only complain if we cannot generate a constant. */ + + input_line_pointer = str; + + c = get_symbol_end (); + if (symbol_find (str) != NULL) + exists = 1; + + * input_line_pointer = c; input_line_pointer = str; expression (& ex); @@ -1478,44 +1978,64 @@ md_assemble (str) field is missing) then report this. */ if (opindex_ptr[1] != 0 && (v850_operands [opindex_ptr [1]].flags & V850_OPERAND_REG)) - errmsg = "syntax error: value is missing before the register name"; + errmsg = _("syntax error: value is missing before the register name"); else - errmsg = "syntax error: register not expected"; + errmsg = _("syntax error: register not expected"); + + /* If we created a symbol in the process of this test then + delete it now, so that it will not be output with the real + symbols... */ + if (exists == 0 + && ex.X_op == O_symbol) + symbol_remove (ex.X_add_symbol, + & symbol_rootP, & symbol_lastP); } } - else if (system_register_name (& ex, false - ) + else if (system_register_name (& ex, false, false) && (operand->flags & V850_OPERAND_SRG) == 0) { - errmsg = "syntax error: system register not expected"; + errmsg = _("syntax error: system register not expected"); } else if (cc_name (&ex) && (operand->flags & V850_OPERAND_CC) == 0) { - errmsg = "syntax error: condition code not expected"; + errmsg = _("syntax error: condition code not expected"); } else { expression (& ex); + /* Special case: + If we are assembling a MOV instruction (or a CALLT.... :-) + and the immediate value does not fit into the bits + available then create a fake error so that the next MOV + instruction will be selected. This one has a 32 bit + immediate field. */ + + if (((insn & 0x07e0) == 0x0200) + && ex.X_op == O_constant + && (ex.X_add_number < (- (1 << (operand->bits - 1))) + || ex.X_add_number > ((1 << operand->bits) - 1))) + errmsg = _("immediate operand is too large"); } if (errmsg) goto error; -/* fprintf (stderr, " insn: %x, operand %d, op: %d, add_number: %d\n", insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number); */ +/* fprintf (stderr, " insn: %x, operand %d, op: %d, add_number: %d\n", + insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number); */ switch (ex.X_op) { case O_illegal: - errmsg = "illegal operand"; + errmsg = _("illegal operand"); goto error; case O_absent: - errmsg = "missing operand"; + errmsg = _("missing operand"); goto error; case O_register: if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0) { - errmsg = "invalid operand"; + errmsg = _("invalid operand"); goto error; } insn = v850_insert_operand (insn, operand, ex.X_add_number, @@ -1532,7 +2052,7 @@ md_assemble (str) default: /* We need to generate a fixup for this expression. */ if (fc >= MAX_INSN_FIXUPS) - as_fatal ("too many fixups"); + as_fatal (_("too many fixups")); fixups[ fc ].exp = ex; fixups[ fc ].opindex = * opindex_ptr; @@ -1584,7 +2104,8 @@ md_assemble (str) ++str; if (*str != '\0') - as_bad ("junk at end of line: `%s'", str); + /* xgettext:c-format */ + as_bad (_("junk at end of line: `%s'"), str); input_line_pointer = str; @@ -1622,6 +2143,9 @@ md_assemble (str) else insn_size = 2; + /* Special case: 32 bit MOV */ + if ((insn & 0xffe0) == 0x0620) + insn_size = 2; f = frag_more (insn_size); @@ -1668,7 +2192,7 @@ md_assemble (str) /* XXX This will abort on an R_V850_8 reloc - is this reloc actually used ? */ if (size != 2 && size != 4) - abort(); + abort (); address = (f - frag_now->fr_literal) + insn_size - size; @@ -1719,22 +2243,28 @@ tc_gen_reloc (seg, fixp) arelent * reloc; reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = & fixp->fx_addsy->bsym; + 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; reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, - "reloc %d not supported by object file format", - (int)fixp->fx_r_type); + /* xgettext:c-format */ + _("reloc %d not supported by object file format"), + (int) fixp->fx_r_type); xfree (reloc); return NULL; } - reloc->addend = fixp->fx_addnumber; + if ( fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT) + reloc->addend = fixp->fx_offset; + else + reloc->addend = fixp->fx_addnumber; return reloc; } @@ -1755,16 +2285,19 @@ md_estimate_size_before_relax (fragp, seg) } long -md_pcrel_from (fixp) +v850_pcrel_from_section (fixp, section) fixS * fixp; + segT section; { /* If the symbol is undefined, or in a section other than our own, + or it is weak (in which case it may well be in another section, then let the linker figure it out. */ - if (fixp->fx_addsy != (symbolS *) NULL && ! S_IS_DEFINED (fixp->fx_addsy)) - { - /* The symbol is undefined. Let the linker figure it out. */ - return 0; - } + if (fixp->fx_addsy != (symbolS *) NULL + && (! S_IS_DEFINED (fixp->fx_addsy) + || S_IS_WEAK (fixp->fx_addsy) + || (S_GET_SEGMENT (fixp->fx_addsy) != section))) + return 0; + return fixp->fx_frag->fr_address + fixp->fx_where; } @@ -1777,6 +2310,13 @@ md_apply_fix3 (fixp, valuep, seg) valueT value; char * where; + if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + { + fixp->fx_done = 0; + return 1; + } + if (fixp->fx_addsy == (symbolS *) NULL) { value = * valuep; @@ -1795,7 +2335,7 @@ md_apply_fix3 (fixp, valuep, seg) { /* We don't actually support subtracting a symbol. */ as_bad_where (fixp->fx_file, fixp->fx_line, - "expression too complex"); + _("expression too complex")); } } } @@ -1838,8 +2378,8 @@ md_apply_fix3 (fixp, valuep, seg) { /* fprintf (stderr, "bits: %d, insn: %x\n", operand->bits, insn); */ - as_bad_where(fixp->fx_file, fixp->fx_line, - "unresolved expression that must be resolved"); + as_bad_where (fixp->fx_file, fixp->fx_line, + _("unresolved expression that must be resolved")); fixp->fx_done = 1; return 1; } @@ -1850,7 +2390,7 @@ md_apply_fix3 (fixp, valuep, seg) where = fixp->fx_frag->fr_literal + fixp->fx_where; if (fixp->fx_size == 1) - *where = value & 0xff; + * where = value & 0xff; else if (fixp->fx_size == 2) bfd_putl16 (value & 0xffff, (unsigned char *) where); else if (fixp->fx_size == 4) @@ -1866,7 +2406,7 @@ md_apply_fix3 (fixp, valuep, seg) on the v850. */ void parse_cons_expression_v850 (exp) - expressionS *exp; + expressionS * exp; { /* See if there's a reloc prefix like hi() we have to handle. */ hold_cons_reloc = v850_reloc_prefix (NULL); @@ -1880,7 +2420,7 @@ parse_cons_expression_v850 (exp) appropriate one based on the size of the expression. */ void cons_fix_new_v850 (frag, where, size, exp) - fragS *frag; + fragS * frag; int where; int size; expressionS *exp; @@ -1900,3 +2440,43 @@ cons_fix_new_v850 (frag, where, size, exp) else fix_new (frag, where, size, NULL, 0, 0, hold_cons_reloc); } + +boolean +v850_fix_adjustable (fixP) + fixS * fixP; +{ + if (fixP->fx_addsy == NULL) + return 1; + + /* Prevent all adjustments to global symbols. */ + if (S_IS_EXTERN (fixP->fx_addsy)) + return 0; + + if (S_IS_WEAK (fixP->fx_addsy)) + return 0; + + /* Don't adjust function names */ + if (S_IS_FUNCTION (fixP->fx_addsy)) + return 0; + + /* We need the symbol name for the VTABLE entries */ + if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; + + return 1; +} + +int +v850_force_relocation (fixP) + struct fix * fixP; +{ + if (fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)) + return 1; + + if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 1; + + return 0; +} |