X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mips.c;h=d19a14987c25f1e77b7dc65f9a45d1dbc2a6ab08;hb=ad3fea084db196784e00a78cec90acf33897441c;hp=db1fec5a5cc4fe38402eb53dfd78cf2cdf495544;hpb=ef2e4d86d6823ab027adcbe57ba3ffaf38a550c2;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index db1fec5a5c..d19a14987c 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -150,7 +150,7 @@ struct mips_cl_insn /* True if this entry cannot be moved from its current position. */ unsigned int fixed_p : 1; - /* True if this instruction occured in a .set noreorder block. */ + /* True if this instruction occurred in a .set noreorder block. */ unsigned int noreorder_p : 1; /* True for mips16 instructions that jump to an absolute address. */ @@ -193,6 +193,7 @@ struct mips_set_options command line options, and based on the default architecture. */ int ase_mips3d; int ase_mdmx; + int ase_smartmips; int ase_dsp; int ase_mt; /* Whether we are assembling for the mips16 processor. 0 if we are @@ -245,7 +246,7 @@ static int file_mips_fp32 = -1; static struct mips_set_options mips_opts = { - ISA_UNKNOWN, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE + ISA_UNKNOWN, -1, -1, 0, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE }; /* These variables are filled in with the masks of registers used. @@ -269,14 +270,27 @@ static int file_ase_mips3d; command line (e.g., by -march). */ static int file_ase_mdmx; +/* True if -msmartmips was passed or implied by arguments passed on the + command line (e.g., by -march). */ +static int file_ase_smartmips; + +#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \ + || mips_opts.isa == ISA_MIPS32R2) + /* True if -mdsp was passed or implied by arguments passed on the command line (e.g., by -march). */ static int file_ase_dsp; +#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \ + || mips_opts.isa == ISA_MIPS64R2) + /* True if -mmt was passed or implied by arguments passed on the command line (e.g., by -march). */ static int file_ase_mt; +#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2 \ + || mips_opts.isa == ISA_MIPS64R2) + /* The argument of the -march= flag. The architecture we are assembling. */ static int file_mips_arch = CPU_UNKNOWN; static const char *mips_arch_string; @@ -293,41 +307,61 @@ static int mips_32bitmode = 0; #define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI) /* Likewise 64-bit registers. */ -#define ABI_NEEDS_64BIT_REGS(ABI) \ - ((ABI) == N32_ABI \ - || (ABI) == N64_ABI \ +#define ABI_NEEDS_64BIT_REGS(ABI) \ + ((ABI) == N32_ABI \ + || (ABI) == N64_ABI \ || (ABI) == O64_ABI) -/* Return true if ISA supports 64 bit gp register instructions. */ -#define ISA_HAS_64BIT_REGS(ISA) ( \ - (ISA) == ISA_MIPS3 \ - || (ISA) == ISA_MIPS4 \ - || (ISA) == ISA_MIPS5 \ - || (ISA) == ISA_MIPS64 \ - || (ISA) == ISA_MIPS64R2 \ - ) +/* Return true if ISA supports 64 bit wide gp registers. */ +#define ISA_HAS_64BIT_REGS(ISA) \ + ((ISA) == ISA_MIPS3 \ + || (ISA) == ISA_MIPS4 \ + || (ISA) == ISA_MIPS5 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) + +/* Return true if ISA supports 64 bit wide float registers. */ +#define ISA_HAS_64BIT_FPRS(ISA) \ + ((ISA) == ISA_MIPS3 \ + || (ISA) == ISA_MIPS4 \ + || (ISA) == ISA_MIPS5 \ + || (ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) /* Return true if ISA supports 64-bit right rotate (dror et al.) instructions. */ -#define ISA_HAS_DROR(ISA) ( \ - (ISA) == ISA_MIPS64R2 \ - ) +#define ISA_HAS_DROR(ISA) \ + ((ISA) == ISA_MIPS64R2) /* Return true if ISA supports 32-bit right rotate (ror et al.) instructions. */ -#define ISA_HAS_ROR(ISA) ( \ - (ISA) == ISA_MIPS32R2 \ - || (ISA) == ISA_MIPS64R2 \ - ) +#define ISA_HAS_ROR(ISA) \ + ((ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64R2 \ + || mips_opts.ase_smartmips) + +/* Return true if ISA supports single-precision floats in odd registers. */ +#define ISA_HAS_ODD_SINGLE_FPR(ISA) \ + ((ISA) == ISA_MIPS32 \ + || (ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) + +/* Return true if ISA supports move to/from high part of a 64-bit + floating-point register. */ +#define ISA_HAS_MXHC1(ISA) \ + ((ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64R2) #define HAVE_32BIT_GPRS \ - (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) + (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa)) #define HAVE_32BIT_FPRS \ - (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) + (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa)) -#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS) -#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS) +#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS) +#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS) #define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI) @@ -1018,11 +1052,18 @@ static int validate_mips_insn (const struct mips_opcode *); struct mips_cpu_info { const char *name; /* CPU or ISA name. */ - int is_isa; /* Is this an ISA? (If 0, a CPU.) */ + int flags; /* ASEs available, or ISA flag. */ int isa; /* ISA level. */ int cpu; /* CPU number (default CPU if ISA). */ }; +#define MIPS_CPU_IS_ISA 0x0001 /* Is this an ISA? (If 0, a CPU.) */ +#define MIPS_CPU_ASE_SMARTMIPS 0x0002 /* CPU implements SmartMIPS ASE */ +#define MIPS_CPU_ASE_DSP 0x0004 /* CPU implements DSP ASE */ +#define MIPS_CPU_ASE_MT 0x0008 /* CPU implements MT ASE */ +#define MIPS_CPU_ASE_MIPS3D 0x0010 /* CPU implements MIPS-3D ASE */ +#define MIPS_CPU_ASE_MDMX 0x0020 /* CPU implements MDMX ASE */ + static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *); static const struct mips_cpu_info *mips_cpu_info_from_isa (int); static const struct mips_cpu_info *mips_cpu_info_from_arch (int); @@ -1191,6 +1232,12 @@ mips_target_format (void) case bfd_target_coff_flavour: return "pe-mips"; case bfd_target_elf_flavour: +#ifdef TE_VXWORKS + if (!HAVE_64BIT_OBJECTS && !HAVE_NEWABI) + return (target_big_endian + ? "elf32-bigmips-vxworks" + : "elf32-littlemips-vxworks"); +#endif #ifdef TE_TMIPS /* This is traditional mips. */ return (target_big_endian @@ -1387,8 +1434,297 @@ init_vr4120_conflicts (void) #undef CONFLICT } -/* 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. */ +struct regname { + const char *name; + unsigned int num; +}; + +#define RTYPE_MASK 0x1ff00 +#define RTYPE_NUM 0x00100 +#define RTYPE_FPU 0x00200 +#define RTYPE_FCC 0x00400 +#define RTYPE_VEC 0x00800 +#define RTYPE_GP 0x01000 +#define RTYPE_CP0 0x02000 +#define RTYPE_PC 0x04000 +#define RTYPE_ACC 0x08000 +#define RTYPE_CCC 0x10000 +#define RNUM_MASK 0x000ff +#define RWARN 0x80000 + +#define GENERIC_REGISTER_NUMBERS \ + {"$0", RTYPE_NUM | 0}, \ + {"$1", RTYPE_NUM | 1}, \ + {"$2", RTYPE_NUM | 2}, \ + {"$3", RTYPE_NUM | 3}, \ + {"$4", RTYPE_NUM | 4}, \ + {"$5", RTYPE_NUM | 5}, \ + {"$6", RTYPE_NUM | 6}, \ + {"$7", RTYPE_NUM | 7}, \ + {"$8", RTYPE_NUM | 8}, \ + {"$9", RTYPE_NUM | 9}, \ + {"$10", RTYPE_NUM | 10}, \ + {"$11", RTYPE_NUM | 11}, \ + {"$12", RTYPE_NUM | 12}, \ + {"$13", RTYPE_NUM | 13}, \ + {"$14", RTYPE_NUM | 14}, \ + {"$15", RTYPE_NUM | 15}, \ + {"$16", RTYPE_NUM | 16}, \ + {"$17", RTYPE_NUM | 17}, \ + {"$18", RTYPE_NUM | 18}, \ + {"$19", RTYPE_NUM | 19}, \ + {"$20", RTYPE_NUM | 20}, \ + {"$21", RTYPE_NUM | 21}, \ + {"$22", RTYPE_NUM | 22}, \ + {"$23", RTYPE_NUM | 23}, \ + {"$24", RTYPE_NUM | 24}, \ + {"$25", RTYPE_NUM | 25}, \ + {"$26", RTYPE_NUM | 26}, \ + {"$27", RTYPE_NUM | 27}, \ + {"$28", RTYPE_NUM | 28}, \ + {"$29", RTYPE_NUM | 29}, \ + {"$30", RTYPE_NUM | 30}, \ + {"$31", RTYPE_NUM | 31} + +#define FPU_REGISTER_NAMES \ + {"$f0", RTYPE_FPU | 0}, \ + {"$f1", RTYPE_FPU | 1}, \ + {"$f2", RTYPE_FPU | 2}, \ + {"$f3", RTYPE_FPU | 3}, \ + {"$f4", RTYPE_FPU | 4}, \ + {"$f5", RTYPE_FPU | 5}, \ + {"$f6", RTYPE_FPU | 6}, \ + {"$f7", RTYPE_FPU | 7}, \ + {"$f8", RTYPE_FPU | 8}, \ + {"$f9", RTYPE_FPU | 9}, \ + {"$f10", RTYPE_FPU | 10}, \ + {"$f11", RTYPE_FPU | 11}, \ + {"$f12", RTYPE_FPU | 12}, \ + {"$f13", RTYPE_FPU | 13}, \ + {"$f14", RTYPE_FPU | 14}, \ + {"$f15", RTYPE_FPU | 15}, \ + {"$f16", RTYPE_FPU | 16}, \ + {"$f17", RTYPE_FPU | 17}, \ + {"$f18", RTYPE_FPU | 18}, \ + {"$f19", RTYPE_FPU | 19}, \ + {"$f20", RTYPE_FPU | 20}, \ + {"$f21", RTYPE_FPU | 21}, \ + {"$f22", RTYPE_FPU | 22}, \ + {"$f23", RTYPE_FPU | 23}, \ + {"$f24", RTYPE_FPU | 24}, \ + {"$f25", RTYPE_FPU | 25}, \ + {"$f26", RTYPE_FPU | 26}, \ + {"$f27", RTYPE_FPU | 27}, \ + {"$f28", RTYPE_FPU | 28}, \ + {"$f29", RTYPE_FPU | 29}, \ + {"$f30", RTYPE_FPU | 30}, \ + {"$f31", RTYPE_FPU | 31} + +#define FPU_CONDITION_CODE_NAMES \ + {"$fcc0", RTYPE_FCC | 0}, \ + {"$fcc1", RTYPE_FCC | 1}, \ + {"$fcc2", RTYPE_FCC | 2}, \ + {"$fcc3", RTYPE_FCC | 3}, \ + {"$fcc4", RTYPE_FCC | 4}, \ + {"$fcc5", RTYPE_FCC | 5}, \ + {"$fcc6", RTYPE_FCC | 6}, \ + {"$fcc7", RTYPE_FCC | 7} + +#define COPROC_CONDITION_CODE_NAMES \ + {"$cc0", RTYPE_FCC | RTYPE_CCC | 0}, \ + {"$cc1", RTYPE_FCC | RTYPE_CCC | 1}, \ + {"$cc2", RTYPE_FCC | RTYPE_CCC | 2}, \ + {"$cc3", RTYPE_FCC | RTYPE_CCC | 3}, \ + {"$cc4", RTYPE_FCC | RTYPE_CCC | 4}, \ + {"$cc5", RTYPE_FCC | RTYPE_CCC | 5}, \ + {"$cc6", RTYPE_FCC | RTYPE_CCC | 6}, \ + {"$cc7", RTYPE_FCC | RTYPE_CCC | 7} + +#define N32N64_SYMBOLIC_REGISTER_NAMES \ + {"$a4", RTYPE_GP | 8}, \ + {"$a5", RTYPE_GP | 9}, \ + {"$a6", RTYPE_GP | 10}, \ + {"$a7", RTYPE_GP | 11}, \ + {"$ta0", RTYPE_GP | 8}, /* alias for $a4 */ \ + {"$ta1", RTYPE_GP | 9}, /* alias for $a5 */ \ + {"$ta2", RTYPE_GP | 10}, /* alias for $a6 */ \ + {"$ta3", RTYPE_GP | 11}, /* alias for $a7 */ \ + {"$t0", RTYPE_GP | 12}, \ + {"$t1", RTYPE_GP | 13}, \ + {"$t2", RTYPE_GP | 14}, \ + {"$t3", RTYPE_GP | 15} + +#define O32_SYMBOLIC_REGISTER_NAMES \ + {"$t0", RTYPE_GP | 8}, \ + {"$t1", RTYPE_GP | 9}, \ + {"$t2", RTYPE_GP | 10}, \ + {"$t3", RTYPE_GP | 11}, \ + {"$t4", RTYPE_GP | 12}, \ + {"$t5", RTYPE_GP | 13}, \ + {"$t6", RTYPE_GP | 14}, \ + {"$t7", RTYPE_GP | 15}, \ + {"$ta0", RTYPE_GP | 12}, /* alias for $t4 */ \ + {"$ta1", RTYPE_GP | 13}, /* alias for $t5 */ \ + {"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \ + {"$ta3", RTYPE_GP | 15} /* alias for $t7 */ + +/* Remaining symbolic register names */ +#define SYMBOLIC_REGISTER_NAMES \ + {"$zero", RTYPE_GP | 0}, \ + {"$at", RTYPE_GP | 1}, \ + {"$AT", RTYPE_GP | 1}, \ + {"$v0", RTYPE_GP | 2}, \ + {"$v1", RTYPE_GP | 3}, \ + {"$a0", RTYPE_GP | 4}, \ + {"$a1", RTYPE_GP | 5}, \ + {"$a2", RTYPE_GP | 6}, \ + {"$a3", RTYPE_GP | 7}, \ + {"$s0", RTYPE_GP | 16}, \ + {"$s1", RTYPE_GP | 17}, \ + {"$s2", RTYPE_GP | 18}, \ + {"$s3", RTYPE_GP | 19}, \ + {"$s4", RTYPE_GP | 20}, \ + {"$s5", RTYPE_GP | 21}, \ + {"$s6", RTYPE_GP | 22}, \ + {"$s7", RTYPE_GP | 23}, \ + {"$t8", RTYPE_GP | 24}, \ + {"$t9", RTYPE_GP | 25}, \ + {"$k0", RTYPE_GP | 26}, \ + {"$kt0", RTYPE_GP | 26}, \ + {"$k1", RTYPE_GP | 27}, \ + {"$kt1", RTYPE_GP | 27}, \ + {"$gp", RTYPE_GP | 28}, \ + {"$sp", RTYPE_GP | 29}, \ + {"$s8", RTYPE_GP | 30}, \ + {"$fp", RTYPE_GP | 30}, \ + {"$ra", RTYPE_GP | 31} + +#define MIPS16_SPECIAL_REGISTER_NAMES \ + {"$pc", RTYPE_PC | 0} + +#define MDMX_VECTOR_REGISTER_NAMES \ + /* {"$v0", RTYPE_VEC | 0}, clash with REG 2 above */ \ + /* {"$v1", RTYPE_VEC | 1}, clash with REG 3 above */ \ + {"$v2", RTYPE_VEC | 2}, \ + {"$v3", RTYPE_VEC | 3}, \ + {"$v4", RTYPE_VEC | 4}, \ + {"$v5", RTYPE_VEC | 5}, \ + {"$v6", RTYPE_VEC | 6}, \ + {"$v7", RTYPE_VEC | 7}, \ + {"$v8", RTYPE_VEC | 8}, \ + {"$v9", RTYPE_VEC | 9}, \ + {"$v10", RTYPE_VEC | 10}, \ + {"$v11", RTYPE_VEC | 11}, \ + {"$v12", RTYPE_VEC | 12}, \ + {"$v13", RTYPE_VEC | 13}, \ + {"$v14", RTYPE_VEC | 14}, \ + {"$v15", RTYPE_VEC | 15}, \ + {"$v16", RTYPE_VEC | 16}, \ + {"$v17", RTYPE_VEC | 17}, \ + {"$v18", RTYPE_VEC | 18}, \ + {"$v19", RTYPE_VEC | 19}, \ + {"$v20", RTYPE_VEC | 20}, \ + {"$v21", RTYPE_VEC | 21}, \ + {"$v22", RTYPE_VEC | 22}, \ + {"$v23", RTYPE_VEC | 23}, \ + {"$v24", RTYPE_VEC | 24}, \ + {"$v25", RTYPE_VEC | 25}, \ + {"$v26", RTYPE_VEC | 26}, \ + {"$v27", RTYPE_VEC | 27}, \ + {"$v28", RTYPE_VEC | 28}, \ + {"$v29", RTYPE_VEC | 29}, \ + {"$v30", RTYPE_VEC | 30}, \ + {"$v31", RTYPE_VEC | 31} + +#define MIPS_DSP_ACCUMULATOR_NAMES \ + {"$ac0", RTYPE_ACC | 0}, \ + {"$ac1", RTYPE_ACC | 1}, \ + {"$ac2", RTYPE_ACC | 2}, \ + {"$ac3", RTYPE_ACC | 3} + +static const struct regname reg_names[] = { + GENERIC_REGISTER_NUMBERS, + FPU_REGISTER_NAMES, + FPU_CONDITION_CODE_NAMES, + COPROC_CONDITION_CODE_NAMES, + + /* The $txx registers depends on the abi, + these will be added later into the symbol table from + one of the tables below once mips_abi is set after + parsing of arguments from the command line. */ + SYMBOLIC_REGISTER_NAMES, + + MIPS16_SPECIAL_REGISTER_NAMES, + MDMX_VECTOR_REGISTER_NAMES, + MIPS_DSP_ACCUMULATOR_NAMES, + {0, 0} +}; + +static const struct regname reg_names_o32[] = { + O32_SYMBOLIC_REGISTER_NAMES, + {0, 0} +}; + +static const struct regname reg_names_n32n64[] = { + N32N64_SYMBOLIC_REGISTER_NAMES, + {0, 0} +}; + +static int +reg_lookup (char **s, unsigned int types, unsigned int *regnop) +{ + symbolS *symbolP; + char *e; + char save_c; + int reg = -1; + + /* Find end of name. */ + e = *s; + if (is_name_beginner (*e)) + ++e; + while (is_part_of_name (*e)) + ++e; + + /* Terminate name. */ + save_c = *e; + *e = '\0'; + + /* Look for a register symbol. */ + if ((symbolP = symbol_find (*s)) && S_GET_SEGMENT (symbolP) == reg_section) + { + int r = S_GET_VALUE (symbolP); + if (r & types) + reg = r & RNUM_MASK; + else if ((types & RTYPE_VEC) && (r & ~1) == (RTYPE_GP | 2)) + /* Convert GP reg $v0/1 to MDMX reg $v0/1! */ + reg = (r & RNUM_MASK) - 2; + } + /* Else see if this is a register defined in an itbl entry. */ + else if ((types & RTYPE_GP) && itbl_have_entries) + { + char *n = *s; + unsigned long r; + + if (*n == '$') + ++n; + if (itbl_get_reg_val (n, &r)) + reg = r & RNUM_MASK; + } + + /* Advance to next token if a register was recognised. */ + if (reg >= 0) + *s = e; + else if (types & RWARN) + as_warn ("Unrecognized register name `%s'", *s); + + *e = save_c; + if (regnop) + *regnop = reg; + return reg >= 0; +} + +/* 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) @@ -1397,6 +1733,13 @@ md_begin (void) int i = 0; int broken = 0; + if (mips_pic != NO_PIC) + { + if (g_switch_seen && g_switch_value != 0) + as_bad (_("-G may not be used in position-independent code")); + g_switch_value = 0; + } + if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch)) as_warn (_("Could not set architecture and machine")); @@ -1468,46 +1811,20 @@ md_begin (void) /* We add all the general register names to the symbol table. This helps us detect invalid uses of them. */ - for (i = 0; i < 32; i++) - { - char buf[5]; - - sprintf (buf, "$%d", i); - symbol_table_insert (symbol_new (buf, reg_section, i, + for (i = 0; reg_names[i].name; i++) + symbol_table_insert (symbol_new (reg_names[i].name, reg_section, + reg_names[i].num, // & RNUM_MASK, + &zero_address_frag)); + if (HAVE_NEWABI) + for (i = 0; reg_names_n32n64[i].name; i++) + symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section, + reg_names_n32n64[i].num, // & RNUM_MASK, &zero_address_frag)); - } - symbol_table_insert (symbol_new ("$ra", reg_section, RA, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$fp", reg_section, FP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$sp", reg_section, SP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$gp", reg_section, GP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$at", reg_section, AT, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$kt0", reg_section, KT0, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$kt1", reg_section, KT1, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$zero", reg_section, ZERO, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$pc", reg_section, -1, - &zero_address_frag)); - - /* If we don't add these register names to the symbol table, they - may end up being added as regular symbols by operand(), and then - make it to the object file as undefined in case they're not - regarded as local symbols. They're local in o32, since `$' is a - local symbol prefix, but not in n32 or n64. */ - for (i = 0; i < 8; i++) - { - char buf[6]; - - sprintf (buf, "$fcc%i", i); - symbol_table_insert (symbol_new (buf, reg_section, -1, + else + for (i = 0; reg_names_o32[i].name; i++) + symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section, + reg_names_o32[i].num, // & RNUM_MASK, &zero_address_frag)); - } mips_no_prev_insn (); @@ -1522,12 +1839,14 @@ md_begin (void) bfd_set_gp_size (stdoutput, g_switch_value); +#ifdef OBJ_ELF if (OUTPUT_FLAVOR == bfd_target_elf_flavour) { - /* On a native system, sections must be aligned to 16 byte - boundaries. When configured for an embedded ELF target, we - don't bother. */ - if (strcmp (TARGET_OS, "elf") != 0) + /* On a native system other than VxWorks, sections must be aligned + to 16 byte boundaries. When configured for an embedded ELF + target, we don't bother. */ + if (strcmp (TARGET_OS, "elf") != 0 + && strcmp (TARGET_OS, "vxworks") != 0) { (void) bfd_set_section_alignment (stdoutput, text_section, 4); (void) bfd_set_section_alignment (stdoutput, data_section, 4); @@ -1559,9 +1878,7 @@ md_begin (void) bfd_set_section_flags (stdoutput, sec, flags); bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2); -#ifdef OBJ_ELF mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo)); -#endif } else { @@ -1571,7 +1888,6 @@ md_begin (void) bfd_set_section_flags (stdoutput, sec, flags); bfd_set_section_alignment (stdoutput, sec, 3); -#ifdef OBJ_ELF /* Set up the option header. */ { Elf_Internal_Options opthdr; @@ -1588,7 +1904,6 @@ md_begin (void) mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo)); } -#endif } if (ECOFF_DEBUGGING) @@ -1598,7 +1913,6 @@ md_begin (void) SEC_HAS_CONTENTS | SEC_READONLY); (void) bfd_set_section_alignment (stdoutput, sec, 2); } -#ifdef OBJ_ELF else if (OUTPUT_FLAVOR == bfd_target_elf_flavour && mips_flag_pdr) { pdr_seg = subseg_new (".pdr", (subsegT) 0); @@ -1607,11 +1921,11 @@ md_begin (void) | SEC_DEBUGGING); (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2); } -#endif subseg_set (seg, subseg); } } +#endif /* OBJ_ELF */ if (! ECOFF_DEBUGGING) md_obj_begin (); @@ -1680,16 +1994,18 @@ md_assemble (char *str) } /* Return true if the given relocation might need a matching %lo(). - Note that R_MIPS_GOT16 relocations only need a matching %lo() when - applied to local symbols. */ + This is only "might" because SVR4 R_MIPS_GOT16 relocations only + need a matching %lo() when applied to local symbols. */ static inline bfd_boolean reloc_needs_lo_p (bfd_reloc_code_real_type reloc) { return (HAVE_IN_PLACE_ADDENDS && (reloc == BFD_RELOC_HI16_S - || reloc == BFD_RELOC_MIPS_GOT16 - || reloc == BFD_RELOC_MIPS16_HI16_S)); + || reloc == BFD_RELOC_MIPS16_HI16_S + /* VxWorks R_MIPS_GOT16 relocs never need a matching %lo(); + all GOT16 relocations evaluate to "G". */ + || (reloc == BFD_RELOC_MIPS_GOT16 && mips_pic != VXWORKS_PIC))); } /* Return true if the given fixup is followed by a matching R_MIPS_LO16 @@ -2313,9 +2629,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, && ! ip->use_extend && *reloc_type != BFD_RELOC_MIPS16_JMP) { - /* Make sure there is enough room to swap this instruction with - a following jump instruction. */ - frag_grow (6); + if ((pinfo & INSN_UNCOND_BRANCH_DELAY) == 0) + /* Make sure there is enough room to swap this instruction with + a following jump instruction. */ + frag_grow (6); add_fixed_insn (ip); } else @@ -2389,9 +2706,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, if ((address_expr->X_add_number & 3) != 0) as_bad (_("jump to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); - if (address_expr->X_add_number & ~0xfffffff) - as_bad (_("jump address range overflow (0x%lx)"), - (unsigned long) address_expr->X_add_number); ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff; break; @@ -2399,9 +2713,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, if ((address_expr->X_add_number & 3) != 0) as_bad (_("jump to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); - if (address_expr->X_add_number & ~0xfffffff) - as_bad (_("jump address range overflow (0x%lx)"), - (unsigned long) address_expr->X_add_number); ip->insn_opcode |= (((address_expr->X_add_number & 0x7c0000) << 3) | ((address_expr->X_add_number & 0xf800000) >> 7) @@ -2409,7 +2720,16 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, break; case BFD_RELOC_16_PCREL_S2: - goto need_reloc; + if ((address_expr->X_add_number & 3) != 0) + as_bad (_("branch to misaligned address (0x%lx)"), + (unsigned long) address_expr->X_add_number); + if (mips_relax_branch) + goto need_reloc; + if ((address_expr->X_add_number + 0x20000) & ~0x3ffff) + as_bad (_("branch address range overflow (0x%lx)"), + (unsigned long) address_expr->X_add_number); + ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0xffff; + break; default: internalError (); @@ -2692,12 +3012,29 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, sync.p, we can not swap. */ || (prev_pinfo & INSN_SYNC)) { - /* We could do even better for unconditional branches to - portions of this object file; we could pick up the - instruction at the destination, put it in the delay - slot, and bump the destination address. */ - insert_into_history (0, 1, ip); - emit_nop (); + if (mips_opts.mips16 + && (pinfo & INSN_UNCOND_BRANCH_DELAY) + && (pinfo & (MIPS16_INSN_READ_X | MIPS16_INSN_READ_31)) + && (mips_opts.isa == ISA_MIPS32 + || mips_opts.isa == ISA_MIPS32R2 + || mips_opts.isa == ISA_MIPS64 + || mips_opts.isa == ISA_MIPS64R2)) + { + /* Convert MIPS16 jr/jalr into a "compact" jump. */ + ip->insn_opcode |= 0x0080; + install_insn (ip); + insert_into_history (0, 1, ip); + } + else + { + /* We could do even better for unconditional branches to + portions of this object file; we could pick up the + instruction at the destination, put it in the delay + slot, and bump the destination address. */ + insert_into_history (0, 1, ip); + emit_nop (); + } + if (mips_relax.sequence) mips_relax.sizes[mips_relax.sequence - 1] += 4; } @@ -2707,22 +3044,9 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, struct mips_cl_insn delay = history[0]; if (mips_opts.mips16) { - if (delay.frag == ip->frag) - { - move_insn (ip, delay.frag, delay.where); - move_insn (&delay, ip->frag, delay.where - + insn_length (ip)); - } - else if (insn_length (ip) == insn_length (&delay)) - { - move_insn (&delay, ip->frag, ip->where); - move_insn (ip, history[0].frag, history[0].where); - } - else - { - add_fixed_insn (NOP_INSN); - delay = *NOP_INSN; - } + know (delay.frag == ip->frag); + move_insn (ip, delay.frag, delay.where); + move_insn (&delay, ip->frag, ip->where + insn_length (ip)); } else if (relaxed_branch) { @@ -2982,7 +3306,8 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) || mo->pinfo == INSN_MACRO || !OPCODE_IS_MEMBER (mo, (mips_opts.isa - | (file_ase_mips16 ? INSN_MIPS16 : 0)), + | (mips_opts.mips16 ? INSN_MIPS16 : 0) + | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)), mips_opts.arch) || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0)) { @@ -3134,15 +3459,22 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) case 'p': assert (ep != NULL); + /* * This allows macro() to pass an immediate expression for * creating short branches without creating a symbol. - * Note that the expression still might come from the assembly - * input, in which case the value is not checked for range nor - * is a relocation entry generated (yuck). + * + * We don't allow branch relaxation for these branches, as + * they should only appear in ".set nomacro" anyway. */ if (ep->X_op == O_constant) { + if ((ep->X_add_number & 3) != 0) + as_bad (_("branch to misaligned address (0x%lx)"), + (unsigned long) ep->X_add_number); + if ((ep->X_add_number + 0x20000) & ~0x3ffff) + as_bad (_("branch address range overflow (0x%lx)"), + (unsigned long) ep->X_add_number); insn.insn_opcode |= (ep->X_add_number >> 2) & 0xffff; ep = NULL; } @@ -3159,6 +3491,10 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) insn.insn_opcode |= va_arg (args, unsigned long); continue; + case 'k': + insn.insn_opcode |= va_arg (args, unsigned long) << OP_SH_CACHE; + continue; + default: internalError (); } @@ -3877,7 +4213,7 @@ load_address (int reg, expressionS *ep, int *used_at) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if (!mips_big_got) { expressionS ex; @@ -3938,7 +4274,7 @@ load_address (int reg, expressionS *ep, int *used_at) } } } - else if (mips_pic == SVR4_PIC) + else if (mips_big_got) { expressionS ex; @@ -4990,7 +5326,7 @@ macro (struct mips_cl_insn *ip) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got && ! HAVE_NEWABI) + else if (!mips_big_got && !HAVE_NEWABI) { int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; @@ -5026,7 +5362,9 @@ macro (struct mips_cl_insn *ip) if (offset_expr.X_add_number == 0) { - if (breg == 0 && (call || tempreg == PIC_CALL_REG)) + if (mips_pic == SVR4_PIC + && breg == 0 + && (call || tempreg == PIC_CALL_REG)) lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16; relax_start (offset_expr.X_add_symbol); @@ -5083,7 +5421,7 @@ macro (struct mips_cl_insn *ip) used_at = 1; } } - else if (mips_pic == SVR4_PIC && ! mips_big_got && HAVE_NEWABI) + else if (!mips_big_got && HAVE_NEWABI) { int add_breg_early = 0; @@ -5186,7 +5524,7 @@ macro (struct mips_cl_insn *ip) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); } } - else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) + else if (mips_big_got && !HAVE_NEWABI) { int gpdelay; int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; @@ -5343,7 +5681,7 @@ macro (struct mips_cl_insn *ip) } relax_end (); } - else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + else if (mips_big_got && HAVE_NEWABI) { int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16; @@ -5476,13 +5814,13 @@ macro (struct mips_cl_insn *ip) case M_JAL_2: if (mips_pic == NO_PIC) macro_build (NULL, "jalr", "d,s", dreg, sreg); - else if (mips_pic == SVR4_PIC) + else { if (sreg != PIC_CALL_REG) as_warn (_("MIPS PIC call to register other than $25")); macro_build (NULL, "jalr", "d,s", dreg, sreg); - if (! HAVE_NEWABI) + if (mips_pic == SVR4_PIC && !HAVE_NEWABI) { if (mips_cprestore_offset < 0) as_warn (_("No .cprestore pseudo-op used in PIC code")); @@ -5508,8 +5846,6 @@ macro (struct mips_cl_insn *ip) } } } - else - abort (); break; @@ -5645,6 +5981,8 @@ macro (struct mips_cl_insn *ip) } } } + else if (mips_pic == VXWORKS_PIC) + as_bad (_("Non-PIC jump used in PIC library")); else abort (); @@ -5781,6 +6119,9 @@ macro (struct mips_cl_insn *ip) case M_SCD_AB: s = "scd"; goto st; + case M_CACHE_AB: + s = "cache"; + goto st; case M_SDC1_AB: if (mips_opts.arch == CPU_R4650) { @@ -5818,6 +6159,8 @@ macro (struct mips_cl_insn *ip) || mask == M_L_DAB || mask == M_S_DAB) fmt = "T,o(b)"; + else if (mask == M_CACHE_AB) + fmt = "k,o(b)"; else if (coproc) fmt = "E,o(b)"; else @@ -6005,7 +6348,7 @@ macro (struct mips_cl_insn *ip) relax_end (); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if (!mips_big_got) { int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; @@ -6059,7 +6402,7 @@ macro (struct mips_cl_insn *ip) tempreg, tempreg, breg); macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg); } - else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) + else if (mips_big_got && !HAVE_NEWABI) { int gpdelay; @@ -6108,7 +6451,7 @@ macro (struct mips_cl_insn *ip) tempreg, tempreg, breg); macro_build (&expr1, s, fmt, treg, BFD_RELOC_LO16, tempreg); } - else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + else if (mips_big_got && HAVE_NEWABI) { /* If this is a reference to an external symbol, we want lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) @@ -6228,14 +6571,12 @@ macro (struct mips_cl_insn *ip) macro_build_lui (&offset_expr, AT); used_at = 1; } - else if (mips_pic == SVR4_PIC) + else { macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT, BFD_RELOC_MIPS_GOT16, mips_gp_register); used_at = 1; } - else - abort (); /* Now we load the register(s). */ if (HAVE_64BIT_GPRS) @@ -6307,7 +6648,7 @@ macro (struct mips_cl_insn *ip) { assert (strcmp (s, RDATA_SECTION_NAME) == 0); used_at = 1; - if (mips_pic == SVR4_PIC) + if (mips_pic != NO_PIC) macro_build (&offset_expr, ADDRESS_LOAD_INSN, "t,o(b)", AT, BFD_RELOC_MIPS_GOT16, mips_gp_register); else @@ -6526,7 +6867,7 @@ macro (struct mips_cl_insn *ip) if (mips_relax.sequence) relax_end (); } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if (!mips_big_got) { /* If this is a reference to an external symbol, we want lw $at,($gp) (BFD_RELOC_MIPS_GOT16) @@ -6573,7 +6914,7 @@ macro (struct mips_cl_insn *ip) mips_optimize = hold_mips_optimize; } - else if (mips_pic == SVR4_PIC) + else if (mips_big_got) { int gpdelay; @@ -7777,6 +8118,10 @@ validate_mips_insn (const struct mips_opcode *opc) case '+': switch (c = *p++) { + case '1': USE_BITS (OP_MASK_UDI1, OP_SH_UDI1); break; + case '2': USE_BITS (OP_MASK_UDI2, OP_SH_UDI2); break; + case '3': USE_BITS (OP_MASK_UDI3, OP_SH_UDI3); break; + case '4': USE_BITS (OP_MASK_UDI4, OP_SH_UDI4); break; case 'A': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break; case 'B': USE_BITS (OP_MASK_INSMSB, OP_SH_INSMSB); break; case 'C': USE_BITS (OP_MASK_EXTMSBD, OP_SH_EXTMSBD); break; @@ -7882,6 +8227,62 @@ validate_mips_insn (const struct mips_opcode *opc) return 1; } +/* UDI immediates. */ +struct mips_immed { + char type; + unsigned int shift; + unsigned long mask; + const char * desc; +}; + +static const struct mips_immed mips_immed[] = { + { '1', OP_SH_UDI1, OP_MASK_UDI1, 0}, + { '2', OP_SH_UDI2, OP_MASK_UDI2, 0}, + { '3', OP_SH_UDI3, OP_MASK_UDI3, 0}, + { '4', OP_SH_UDI4, OP_MASK_UDI4, 0}, + { 0,0,0,0 } +}; + +/* Check whether an odd floating-point register is allowed. */ +static int +mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum) +{ + const char *s = insn->name; + + if (insn->pinfo == INSN_MACRO) + /* Let a macro pass, we'll catch it later when it is expanded. */ + return 1; + + if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa)) + { + /* Allow odd registers for single-precision ops. */ + switch (insn->pinfo & (FP_S | FP_D)) + { + case FP_S: + case 0: + return 1; /* both single precision - ok */ + case FP_D: + return 0; /* both double precision - fail */ + default: + break; + } + + /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand. */ + s = strchr (insn->name, '.'); + if (argnum == 2) + s = s != NULL ? strchr (s + 1, '.') : NULL; + return (s != NULL && (s[1] == 'w' || s[1] == 's')); + } + + /* Single-precision coprocessor loads and moves are OK too. */ + if ((insn->pinfo & FP_S) + && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY + | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY))) + return 1; + + return 0; +} + /* This routine assembles an instruction into its binary format. As a side effect, it sets one of the global variables imm_reloc or offset_reloc to the type of relocation to do if one of the operands @@ -7902,6 +8303,8 @@ mips_ip (char *str, struct mips_cl_insn *ip) char *s_reset; char save_c = 0; offsetT min_range, max_range; + int argnum; + unsigned int rtype; insn_error = NULL; @@ -7962,11 +8365,15 @@ mips_ip (char *str, struct mips_cl_insn *ip) if (OPCODE_IS_MEMBER (insn, (mips_opts.isa + /* We don't check for mips_opts.mips16 here since + we want to allow jalx if -mips16 was specified + on the command line. */ | (file_ase_mips16 ? INSN_MIPS16 : 0) | (mips_opts.ase_mdmx ? INSN_MDMX : 0) | (mips_opts.ase_dsp ? INSN_DSP : 0) | (mips_opts.ase_mt ? INSN_MT : 0) - | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0)), + | (mips_opts.ase_mips3d ? INSN_MIPS3D : 0) + | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)), mips_opts.arch)) ok = TRUE; else @@ -8005,6 +8412,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) create_insn (ip, insn); insn_error = NULL; + argnum = 1; for (args = insn->args;; ++args) { int is_mdmx; @@ -8287,6 +8695,34 @@ mips_ip (char *str, struct mips_cl_insn *ip) case '+': /* Opcode extension character. */ switch (*++args) { + case '1': /* UDI immediates. */ + case '2': + case '3': + case '4': + { + const struct mips_immed *imm = mips_immed; + + while (imm->type && imm->type != *args) + ++imm; + if (! imm->type) + internalError (); + my_getExpression (&imm_expr, s); + check_absolute_expr (ip, &imm_expr); + if ((unsigned long) imm_expr.X_add_number & ~imm->mask) + { + as_warn (_("Illegal %s number (%lu, 0x%lx)"), + imm->desc ? imm->desc : ip->insn_mo->name, + (unsigned long) imm_expr.X_add_number, + (unsigned long) imm_expr.X_add_number); + imm_expr.X_add_number &= imm->mask; + } + ip->insn_opcode |= ((unsigned long) imm_expr.X_add_number + << imm->shift); + imm_expr.X_op = O_absent; + s = expr_end; + } + continue; + case 'A': /* ins/ext position, becomes LSB. */ limlo = 0; limhi = 31; @@ -8393,11 +8829,11 @@ do_msbd: s = expr_end; continue; - case 'T': /* Coprocessor register */ + case 'T': /* Coprocessor register. */ /* +T is for disassembly only; never match. */ break; - case 't': /* Coprocessor register number */ + case 't': /* Coprocessor register number. */ if (s[0] == '$' && ISDIGIT (s[1])) { ++s; @@ -8531,7 +8967,7 @@ do_msbd: s = expr_end; continue; - case 'P': /* Performance register */ + case 'P': /* Performance register. */ my_getExpression (&imm_expr, s); check_absolute_expr (ip, &imm_expr); if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1) @@ -8542,6 +8978,20 @@ do_msbd: s = expr_end; continue; + case 'G': /* Coprocessor destination register. */ + if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0) + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, ®no); + else + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); + ip->insn_opcode |= regno << OP_SH_RD; + if (ok) + { + lastregno = regno; + continue; + } + else + break; + case 'b': /* base register */ case 'd': /* destination register */ case 's': /* source register */ @@ -8550,107 +9000,22 @@ do_msbd: case 'v': /* both dest and source */ case 'w': /* both dest and target */ case 'E': /* coprocessor target register */ - case 'G': /* coprocessor destination register */ case 'K': /* 'rdhwr' destination register */ case 'x': /* ignore register name */ case 'z': /* must be zero register */ case 'U': /* destination register (clo/clz). */ case 'g': /* coprocessor destination register */ - s_reset = s; - if (s[0] == '$') + s_reset = s; + if (*args == 'E' || *args == 'K') + ok = reg_lookup (&s, RTYPE_NUM, ®no); + else + { + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); + if (regno == AT && ! mips_opts.noat) + as_warn ("Used $at without \".set noat\""); + } + if (ok) { - - if (ISDIGIT (s[1])) - { - ++s; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 31) - as_bad (_("Invalid register number (%d)"), regno); - } - else if (*args == 'E' || *args == 'G' || *args == 'K') - goto notreg; - else - { - if (s[1] == 'r' && s[2] == 'a') - { - s += 3; - regno = RA; - } - else if (s[1] == 'f' && s[2] == 'p') - { - s += 3; - regno = FP; - } - else if (s[1] == 's' && s[2] == 'p') - { - s += 3; - regno = SP; - } - else if (s[1] == 'g' && s[2] == 'p') - { - s += 3; - regno = GP; - } - else if (s[1] == 'a' && s[2] == 't') - { - s += 3; - regno = AT; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '0') - { - s += 4; - regno = KT0; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '1') - { - s += 4; - regno = KT1; - } - else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o') - { - s += 5; - regno = ZERO; - } - else if (itbl_have_entries) - { - char *p, *n; - unsigned long r; - - p = s + 1; /* advance past '$' */ - n = itbl_get_field (&p); /* n is name */ - - /* See if this is a register defined in an - itbl entry. */ - if (itbl_get_reg_val (n, &r)) - { - /* Get_field advances to the start of - the next field, so we need to back - rack to the end of the last field. */ - if (p) - s = p - 1; - else - s = strchr (s, '\0'); - regno = r; - } - else - goto notreg; - } - else - goto notreg; - } - if (regno == AT - && ! mips_opts.noat - && *args != 'E' - && *args != 'G' - && *args != 'K') - as_warn (_("Used $at without \".set noat\"")); c = *args; if (*s == ' ') ++s; @@ -8716,7 +9081,6 @@ do_msbd: lastregno = regno; continue; } - notreg: switch (*args++) { case 'r': @@ -8769,40 +9133,22 @@ do_msbd: case 'R': /* floating point source register */ case 'V': case 'W': + rtype = RTYPE_FPU; + if (is_mdmx + || (mips_opts.ase_mdmx + && (ip->insn_mo->pinfo & FP_D) + && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY + | INSN_COPROC_MEMORY_DELAY + | INSN_LOAD_COPROC_DELAY + | INSN_LOAD_MEMORY_DELAY + | INSN_STORE_MEMORY)))) + rtype |= RTYPE_VEC; s_reset = s; - /* Accept $fN for FP and MDMX register numbers, and in - addition accept $vN for MDMX register numbers. */ - if ((s[0] == '$' && s[1] == 'f' && ISDIGIT (s[2])) - || (is_mdmx != 0 && s[0] == '$' && s[1] == 'v' - && ISDIGIT (s[2]))) + if (reg_lookup (&s, rtype, ®no)) { - s += 2; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - - if (regno > 31) - as_bad (_("Invalid float register number (%d)"), regno); - if ((regno & 1) != 0 && HAVE_32BIT_FPRS - && ! (strcmp (str, "mtc1") == 0 - || strcmp (str, "mfc1") == 0 - || strcmp (str, "lwc1") == 0 - || strcmp (str, "swc1") == 0 - || strcmp (str, "l.s") == 0 - || strcmp (str, "s.s") == 0 - || strcmp (str, "mftc1") == 0 - || strcmp (str, "mfthc1") == 0 - || strcmp (str, "cftc1") == 0 - || strcmp (str, "mttc1") == 0 - || strcmp (str, "mtthc1") == 0 - || strcmp (str, "cttc1") == 0)) + && ! mips_oddfpreg_ok (ip->insn_mo, argnum)) as_warn (_("Float register should be even, was %d"), regno); @@ -9190,19 +9536,11 @@ do_msbd: case 'N': /* 3 bit branch condition code */ case 'M': /* 3 bit compare condition code */ - if (strncmp (s, "$fcc", 4) != 0) + rtype = RTYPE_CCC; + if (ip->insn_mo->pinfo & (FP_D| FP_S)) + rtype |= RTYPE_FCC; + if (!reg_lookup (&s, rtype, ®no)) break; - s += 4; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 7) - as_bad (_("Invalid condition code register $fcc%d"), regno); if ((strcmp(str + strlen(str) - 3, ".ps") == 0 || strcmp(str + strlen(str) - 5, "any2f") == 0 || strcmp(str + strlen(str) - 5, "any2t") == 0) @@ -9299,6 +9637,8 @@ do_msbd: } } +#define SKIP_SPACE_TABS(S) { while (*(S) == ' ' || *(S) == '\t') ++(S); } + /* This routine assembles an instruction into its binary format when assembling for the mips16. As a side effect, it sets one of the global variables imm_reloc or offset_reloc to the type of @@ -9367,8 +9707,38 @@ mips16_ip (char *str, struct mips_cl_insn *ip) argsstart = s; for (;;) { + bfd_boolean ok; + assert (strcmp (insn->name, str) == 0); + if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch)) + ok = TRUE; + else + ok = FALSE; + + if (! ok) + { + if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes] + && strcmp (insn->name, insn[1].name) == 0) + { + ++insn; + continue; + } + else + { + if (!insn_error) + { + static char buf[100]; + sprintf (buf, + _("opcode not supported on this processor: %s (%s)"), + mips_cpu_info_from_arch (mips_opts.arch)->name, + mips_cpu_info_from_isa (mips_opts.isa)->name); + insn_error = buf; + } + return; + } + } + create_insn (ip, insn); imm_expr.X_op = O_absent; imm_reloc[0] = BFD_RELOC_UNUSED; @@ -9481,70 +9851,19 @@ mips16_ip (char *str, struct mips_cl_insn *ip) case 'R': case 'X': case 'Y': - if (s[0] != '$') - break; - s_reset = s; - if (ISDIGIT (s[1])) + s_reset = s; + if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no)) { - ++s; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 31) - { - as_bad (_("invalid register number (%d)"), regno); - regno = 2; - } - } - else - { - if (s[1] == 'r' && s[2] == 'a') - { - s += 3; - regno = RA; - } - else if (s[1] == 'f' && s[2] == 'p') - { - s += 3; - regno = FP; - } - else if (s[1] == 's' && s[2] == 'p') - { - s += 3; - regno = SP; - } - else if (s[1] == 'g' && s[2] == 'p') - { - s += 3; - regno = GP; - } - else if (s[1] == 'a' && s[2] == 't') - { - s += 3; - regno = AT; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '0') - { - s += 4; - regno = KT0; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '1') - { - s += 4; - regno = KT1; - } - else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o') + if (c == 'v' || c == 'w') { - s += 5; - regno = ZERO; + if (c == 'v') + ip->insn_opcode |= lastregno << MIPS16OP_SH_RX; + else + ip->insn_opcode |= lastregno << MIPS16OP_SH_RY; + ++args; + continue; } - else - break; + break; } if (*s == ' ') @@ -9750,29 +10069,18 @@ mips16_ip (char *str, struct mips_cl_insn *ip) mask = 7 << 3; while (*s != '\0') { - int freg, reg1, reg2; + unsigned int freg, reg1, reg2; while (*s == ' ' || *s == ',') ++s; - if (*s != '$') - { - as_bad (_("can't parse register list")); - break; - } - ++s; - if (*s != 'f') + if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1)) freg = 0; + else if (reg_lookup (&s, RTYPE_FPU, ®1)) + freg = 1; else { - freg = 1; - ++s; - } - reg1 = 0; - while (ISDIGIT (*s)) - { - reg1 *= 10; - reg1 += *s - '0'; - ++s; + as_bad (_("can't parse register list")); + break; } if (*s == ' ') ++s; @@ -9781,25 +10089,11 @@ mips16_ip (char *str, struct mips_cl_insn *ip) else { ++s; - if (*s != '$') - break; - ++s; - if (freg) + if (!reg_lookup (&s, freg ? RTYPE_FPU + : (RTYPE_GP | RTYPE_NUM), ®2)) { - if (*s == 'f') - ++s; - else - { - as_bad (_("invalid register list")); - break; - } - } - reg2 = 0; - while (ISDIGIT (*s)) - { - reg2 *= 10; - reg2 += *s - '0'; - ++s; + as_bad (_("invalid register list")); + break; } } if (freg && reg1 == 0 && reg2 == 0 && c == 'L') @@ -9832,6 +10126,171 @@ mips16_ip (char *str, struct mips_cl_insn *ip) } continue; + case 'm': /* Register list for save insn. */ + case 'M': /* Register list for restore insn. */ + { + int opcode = 0; + int framesz = 0, seen_framesz = 0; + int args = 0, statics = 0, sregs = 0; + + while (*s != '\0') + { + unsigned int reg1, reg2; + + SKIP_SPACE_TABS (s); + while (*s == ',') + ++s; + SKIP_SPACE_TABS (s); + + my_getExpression (&imm_expr, s); + if (imm_expr.X_op == O_constant) + { + /* Handle the frame size. */ + if (seen_framesz) + { + as_bad (_("more than one frame size in list")); + break; + } + seen_framesz = 1; + framesz = imm_expr.X_add_number; + imm_expr.X_op = O_absent; + s = expr_end; + continue; + } + + if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1)) + { + as_bad (_("can't parse register list")); + break; + } + + while (*s == ' ') + ++s; + + if (*s != '-') + reg2 = reg1; + else + { + ++s; + if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®2) + || reg2 < reg1) + { + as_bad (_("can't parse register list")); + break; + } + } + + while (reg1 <= reg2) + { + if (reg1 >= 4 && reg1 <= 7) + { + if (c == 'm' && !seen_framesz) + /* args $a0-$a3 */ + args |= 1 << (reg1 - 4); + else + /* statics $a0-$a3 */ + statics |= 1 << (reg1 - 4); + } + else if ((reg1 >= 16 && reg1 <= 23) || reg1 == 30) + { + /* $s0-$s8 */ + sregs |= 1 << ((reg1 == 30) ? 8 : (reg1 - 16)); + } + else if (reg1 == 31) + { + /* Add $ra to insn. */ + opcode |= 0x40; + } + else + { + as_bad (_("unexpected register in list")); + break; + } + if (++reg1 == 24) + reg1 = 30; + } + } + + /* Encode args/statics combination. */ + if (args & statics) + as_bad (_("arg/static registers overlap")); + else if (args == 0xf) + /* All $a0-$a3 are args. */ + opcode |= MIPS16_ALL_ARGS << 16; + else if (statics == 0xf) + /* All $a0-$a3 are statics. */ + opcode |= MIPS16_ALL_STATICS << 16; + else + { + int narg = 0, nstat = 0; + + /* Count arg registers. */ + while (args & 0x1) + { + args >>= 1; + narg++; + } + if (args != 0) + as_bad (_("invalid arg register list")); + + /* Count static registers. */ + while (statics & 0x8) + { + statics = (statics << 1) & 0xf; + nstat++; + } + if (statics != 0) + as_bad (_("invalid static register list")); + + /* Encode args/statics. */ + opcode |= ((narg << 2) | nstat) << 16; + } + + /* Encode $s0/$s1. */ + if (sregs & (1 << 0)) /* $s0 */ + opcode |= 0x20; + if (sregs & (1 << 1)) /* $s1 */ + opcode |= 0x10; + sregs >>= 2; + + if (sregs != 0) + { + /* Count regs $s2-$s8. */ + int nsreg = 0; + while (sregs & 1) + { + sregs >>= 1; + nsreg++; + } + if (sregs != 0) + as_bad (_("invalid static register list")); + /* Encode $s2-$s8. */ + opcode |= nsreg << 24; + } + + /* Encode frame size. */ + if (!seen_framesz) + as_bad (_("missing frame size")); + else if ((framesz & 7) != 0 || framesz < 0 + || framesz > 0xff * 8) + as_bad (_("invalid frame size")); + else if (framesz != 128 || (opcode >> 16) != 0) + { + framesz /= 8; + opcode |= (((framesz & 0xf0) << 16) + | (framesz & 0x0f)); + } + + /* Finally build the instruction. */ + if ((opcode >> 16) != 0 || framesz == 0) + { + ip->use_extend = TRUE; + ip->extend = opcode >> 16; + } + ip->insn_opcode |= opcode & 0x7f; + } + continue; + case 'e': /* extend code */ my_getExpression (&imm_expr, s); check_absolute_expr (ip, &imm_expr); @@ -10347,9 +10806,13 @@ struct option md_longopts[] = {"mmt", no_argument, NULL, OPTION_MT}, #define OPTION_NO_MT (OPTION_ASE_BASE + 9) {"mno-mt", no_argument, NULL, OPTION_NO_MT}, +#define OPTION_SMARTMIPS (OPTION_ASE_BASE + 10) + {"msmartmips", no_argument, NULL, OPTION_SMARTMIPS}, +#define OPTION_NO_SMARTMIPS (OPTION_ASE_BASE + 11) + {"mno-smartmips", no_argument, NULL, OPTION_NO_SMARTMIPS}, /* Old-style architecture options. Don't add more of these. */ -#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 10) +#define OPTION_COMPAT_ARCH_BASE (OPTION_ASE_BASE + 12) #define OPTION_M4650 (OPTION_COMPAT_ARCH_BASE + 0) {"m4650", no_argument, NULL, OPTION_M4650}, #define OPTION_NO_M4650 (OPTION_COMPAT_ARCH_BASE + 1) @@ -10446,6 +10909,8 @@ struct option md_longopts[] = {"mpdr", no_argument, NULL, OPTION_PDR}, #define OPTION_NO_PDR (OPTION_ELF_BASE + 10) {"mno-pdr", no_argument, NULL, OPTION_NO_PDR}, +#define OPTION_MVXWORKS_PIC (OPTION_ELF_BASE + 11) + {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC}, #endif /* OBJ_ELF */ {NULL, no_argument, NULL, 0} @@ -10635,6 +11100,14 @@ md_parse_option (int c, char *arg) mips_opts.ase_mips3d = 0; break; + case OPTION_SMARTMIPS: + mips_opts.ase_smartmips = 1; + break; + + case OPTION_NO_SMARTMIPS: + mips_opts.ase_smartmips = 0; + break; + case OPTION_FIX_VR4120: mips_fix_vr4120 = 1; break; @@ -10687,12 +11160,6 @@ md_parse_option (int c, char *arg) } mips_pic = SVR4_PIC; mips_abicalls = TRUE; - if (g_switch_seen && g_switch_value != 0) - { - as_bad (_("-G may not be used with SVR4 PIC code")); - return 0; - } - g_switch_value = 0; break; case OPTION_NON_SHARED: @@ -10705,8 +11172,8 @@ md_parse_option (int c, char *arg) mips_abicalls = FALSE; break; - /* The -xgot option tells the assembler to use 32 offsets when - accessing the got in SVR4_PIC mode. It is for Irix + /* The -xgot option tells the assembler to use 32 bit offsets + when accessing the got in SVR4_PIC mode. It is for Irix compatibility. */ case OPTION_XGOT: mips_big_got = 1; @@ -10716,11 +11183,6 @@ md_parse_option (int c, char *arg) case 'G': g_switch_value = atoi (arg); g_switch_seen = 1; - if (mips_pic == SVR4_PIC && g_switch_value != 0) - { - as_bad (_("-G may not be used with SVR4 PIC code")); - return 0; - } break; #ifdef OBJ_ELF @@ -10826,6 +11288,10 @@ md_parse_option (int c, char *arg) case OPTION_NO_PDR: mips_flag_pdr = FALSE; break; + + case OPTION_MVXWORKS_PIC: + mips_pic = VXWORKS_PIC; + break; #endif /* OBJ_ELF */ default: @@ -10942,14 +11408,43 @@ mips_after_parse_args (void) || !ISA_HAS_64BIT_REGS (mips_opts.isa)); } - /* ??? GAS treats single-float processors as though they had 64-bit - float registers (although it complains when double-precision - instructions are used). As things stand, saying they have 32-bit - registers would lead to spurious "register must be even" messages. - So here we assume float registers are always the same size as - integer ones, unless the user says otherwise. */ - if (file_mips_fp32 < 0) - file_mips_fp32 = file_mips_gp32; + switch (file_mips_fp32) + { + default: + case -1: + /* No user specified float register size. + ??? GAS treats single-float processors as though they had 64-bit + float registers (although it complains when double-precision + instructions are used). As things stand, saying they have 32-bit + registers would lead to spurious "register must be even" messages. + So here we assume float registers are never smaller than the + integer ones. */ + if (file_mips_gp32 == 0) + /* 64-bit integer registers implies 64-bit float registers. */ + file_mips_fp32 = 0; + else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0) + && ISA_HAS_64BIT_FPRS (mips_opts.isa)) + /* -mips3d and -mdmx imply 64-bit float registers, if possible. */ + file_mips_fp32 = 0; + else + /* 32-bit float registers. */ + file_mips_fp32 = 1; + break; + + /* The user specified the size of the float registers. Check if it + agrees with the ABI and ISA. */ + case 0: + if (!ISA_HAS_64BIT_FPRS (mips_opts.isa)) + as_bad (_("-mfp64 used with a 32-bit fpu")); + else if (ABI_NEEDS_32BIT_REGS (mips_abi) + && !ISA_HAS_MXHC1 (mips_opts.isa)) + as_warn (_("-mfp64 used with a 32-bit ABI")); + break; + case 1: + if (ABI_NEEDS_64BIT_REGS (mips_abi)) + as_warn (_("-mfp32 used with a 64-bit ABI")); + break; + } /* End of GCC-shared inference code. */ @@ -10968,18 +11463,42 @@ mips_after_parse_args (void) if (mips_opts.mips16 == -1) mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0; if (mips_opts.ase_mips3d == -1) - mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mips3d = ((CPU_HAS_MIPS3D (file_mips_arch) + || (arch_info->flags & MIPS_CPU_ASE_MIPS3D)) + && file_mips_fp32 == 0) ? 1 : 0; + if (mips_opts.ase_mips3d && file_mips_fp32 == 1) + as_bad (_("-mfp32 used with -mips3d")); + if (mips_opts.ase_mdmx == -1) - mips_opts.ase_mdmx = (CPU_HAS_MDMX (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mdmx = ((CPU_HAS_MDMX (file_mips_arch) + || (arch_info->flags & MIPS_CPU_ASE_MDMX)) + && file_mips_fp32 == 0) ? 1 : 0; + if (mips_opts.ase_mdmx && file_mips_fp32 == 1) + as_bad (_("-mfp32 used with -mdmx")); + + if (mips_opts.ase_smartmips == -1) + mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0; + if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS) + as_warn ("%s ISA does not support SmartMIPS", + mips_cpu_info_from_isa (mips_opts.isa)->name); + if (mips_opts.ase_dsp == -1) - mips_opts.ase_dsp = (CPU_HAS_DSP (file_mips_arch)) ? 1 : 0; + mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0; + if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE) + as_warn ("%s ISA does not support DSP ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + if (mips_opts.ase_mt == -1) - mips_opts.ase_mt = (CPU_HAS_MT (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0; + if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE) + as_warn ("%s ISA does not support MT ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); file_mips_isa = mips_opts.isa; file_ase_mips16 = mips_opts.mips16; file_ase_mips3d = mips_opts.ase_mips3d; file_ase_mdmx = mips_opts.ase_mdmx; + file_ase_smartmips = mips_opts.ase_smartmips; file_ase_dsp = mips_opts.ase_dsp; file_ase_mt = mips_opts.ase_mt; mips_opts.gp32 = file_mips_gp32; @@ -11177,83 +11696,6 @@ mips_force_relocation (fixS *fixp) return 0; } -/* This hook is called before a fix is simplified. We don't really - decide whether to skip a fix here. Rather, we turn global symbols - used as branch targets into local symbols, such that they undergo - simplification. We can only do this if the symbol is defined and - it is in the same section as the branch. If this doesn't hold, we - emit a better error message than just saying the relocation is not - valid for the selected object format. - - FIXP is the fix-up we're going to try to simplify, SEG is the - segment in which the fix up occurs. The return value should be - non-zero to indicate the fix-up is valid for further - simplifications. */ - -int -mips_validate_fix (struct fix *fixP, asection *seg) -{ - /* There's a lot of discussion on whether it should be possible to - use R_MIPS_PC16 to represent branch relocations. The outcome - seems to be that it can, but gas/bfd are very broken in creating - RELA relocations for this, so for now we only accept branches to - symbols in the same section. Anything else is of dubious value, - since there's no guarantee that at link time the symbol would be - in range. Even for branches to local symbols this is arguably - wrong, since it we assume the symbol is not going to be - overridden, which should be possible per ELF library semantics, - but then, there isn't a dynamic relocation that could be used to - this effect, and the target would likely be out of range as well. - - Unfortunately, it seems that there is too much code out there - that relies on branches to symbols that are global to be resolved - as if they were local, like the IRIX tools do, so we do it as - well, but with a warning so that people are reminded to fix their - code. If we ever get back to using R_MIPS_PC16 for branch - targets, this entire block should go away (and probably the - whole function). */ - - if (fixP->fx_r_type == BFD_RELOC_16_PCREL_S2 - && ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour - || OUTPUT_FLAVOR == bfd_target_elf_flavour) - || bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16_PCREL_S2) == NULL) - && fixP->fx_addsy) - { - if (! S_IS_DEFINED (fixP->fx_addsy)) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Cannot branch to undefined symbol.")); - /* Avoid any further errors about this fixup. */ - fixP->fx_done = 1; - } - else if (S_GET_SEGMENT (fixP->fx_addsy) != seg) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Cannot branch to symbol in another section.")); - fixP->fx_done = 1; - } - else if (S_IS_EXTERNAL (fixP->fx_addsy)) - { - symbolS *sym = fixP->fx_addsy; - - if (mips_pic == SVR4_PIC) - as_warn_where (fixP->fx_file, fixP->fx_line, - _("Pretending global symbol used as branch target is local.")); - - fixP->fx_addsy = symbol_create (S_GET_NAME (sym), - S_GET_SEGMENT (sym), - S_GET_VALUE (sym), - symbol_get_frag (sym)); - copy_symbol_attributes (fixP->fx_addsy, sym); - S_CLEAR_EXTERNAL (fixP->fx_addsy); - assert (symbol_resolved_p (sym)); - symbol_mark_resolved (fixP->fx_addsy); - } - } - - return 1; -} - /* Apply a fixup to the object file. */ void @@ -11278,7 +11720,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where); - assert (! fixP->fx_pcrel); + assert (! fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2); /* Don't treat parts of a composite relocation as done. There are two reasons for this: @@ -11290,7 +11732,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) constants. The easiest way of dealing with the pathological exceptions is to generate a relocation against STN_UNDEF and leave everything up to the linker. */ - if (fixP->fx_addsy == NULL && fixP->fx_tcbit == 0) + if (fixP->fx_addsy == NULL && ! fixP->fx_pcrel && fixP->fx_tcbit == 0) fixP->fx_done = 1; switch (fixP->fx_r_type) @@ -11335,7 +11777,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_MIPS16_GPREL: case BFD_RELOC_MIPS16_HI16: case BFD_RELOC_MIPS16_HI16_S: - assert (! fixP->fx_pcrel); /* Nothing needed to do. The value comes from the reloc entry */ break; @@ -11405,7 +11846,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_16_PCREL_S2: if ((*valP & 0x3) != 0) as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch to odd address (%lx)"), (long) *valP); + _("Branch to misaligned address (%lx)"), (long) *valP); /* * We need to save the bits in the instruction since fixup_segment() @@ -11676,7 +12117,7 @@ s_change_section (int ignore ATTRIBUTE_UNUSED) There's nothing really harmful in this, since bfd will correct SHT_PROGBITS to SHT_MIPS_DWARF before writing out the file. But it - means that, for backwards compatibiltiy, the special_section entries + means that, for backwards compatibility, the special_section entries for dwarf sections must use SHT_PROGBITS rather than SHT_MIPS_DWARF. Even so, we shouldn't force users of the MIPS .section syntax to @@ -11905,12 +12346,43 @@ s_mipsset (int x ATTRIBUTE_UNUSED) { mips_opts.nobopt = 1; } + else if (strcmp (name, "gp=default") == 0) + mips_opts.gp32 = file_mips_gp32; + else if (strcmp (name, "gp=32") == 0) + mips_opts.gp32 = 1; + else if (strcmp (name, "gp=64") == 0) + { + if (!ISA_HAS_64BIT_REGS (mips_opts.isa)) + as_warn ("%s isa does not support 64-bit registers", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.gp32 = 0; + } + else if (strcmp (name, "fp=default") == 0) + mips_opts.fp32 = file_mips_fp32; + else if (strcmp (name, "fp=32") == 0) + mips_opts.fp32 = 1; + else if (strcmp (name, "fp=64") == 0) + { + if (!ISA_HAS_64BIT_FPRS (mips_opts.isa)) + as_warn ("%s isa does not support 64-bit floating point registers", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.fp32 = 0; + } else if (strcmp (name, "mips16") == 0 || strcmp (name, "MIPS-16") == 0) mips_opts.mips16 = 1; else if (strcmp (name, "nomips16") == 0 || strcmp (name, "noMIPS-16") == 0) mips_opts.mips16 = 0; + else if (strcmp (name, "smartmips") == 0) + { + if (!ISA_SUPPORTS_SMARTMIPS) + as_warn ("%s ISA does not support SmartMIPS ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.ase_smartmips = 1; + } + else if (strcmp (name, "nosmartmips") == 0) + mips_opts.ase_smartmips = 0; else if (strcmp (name, "mips3d") == 0) mips_opts.ase_mips3d = 1; else if (strcmp (name, "nomips3d") == 0) @@ -11920,11 +12392,21 @@ s_mipsset (int x ATTRIBUTE_UNUSED) else if (strcmp (name, "nomdmx") == 0) mips_opts.ase_mdmx = 0; else if (strcmp (name, "dsp") == 0) - mips_opts.ase_dsp = 1; + { + if (!ISA_SUPPORTS_DSP_ASE) + as_warn ("%s ISA does not support DSP ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.ase_dsp = 1; + } else if (strcmp (name, "nodsp") == 0) mips_opts.ase_dsp = 0; else if (strcmp (name, "mt") == 0) - mips_opts.ase_mt = 1; + { + if (!ISA_SUPPORTS_MT_ASE) + as_warn ("%s ISA does not support MT ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.ase_mt = 1; + } else if (strcmp (name, "nomt") == 0) mips_opts.ase_mt = 0; else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0) @@ -12536,73 +13018,11 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED) int tc_get_register (int frame) { - int reg; + unsigned int reg; SKIP_WHITESPACE (); - if (*input_line_pointer++ != '$') - { - as_warn (_("expected `$'")); - reg = ZERO; - } - else if (ISDIGIT (*input_line_pointer)) - { - reg = get_absolute_expression (); - if (reg < 0 || reg >= 32) - { - as_warn (_("Bad register number")); - reg = ZERO; - } - } - else - { - if (strncmp (input_line_pointer, "ra", 2) == 0) - { - reg = RA; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "fp", 2) == 0) - { - reg = FP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "sp", 2) == 0) - { - reg = SP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "gp", 2) == 0) - { - reg = GP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "at", 2) == 0) - { - reg = AT; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "kt0", 3) == 0) - { - reg = KT0; - input_line_pointer += 3; - } - else if (strncmp (input_line_pointer, "kt1", 3) == 0) - { - reg = KT1; - input_line_pointer += 3; - } - else if (strncmp (input_line_pointer, "zero", 4) == 0) - { - reg = ZERO; - input_line_pointer += 4; - } - else - { - as_warn (_("Unrecognized register name")); - reg = ZERO; - while (ISALNUM(*input_line_pointer)) - input_line_pointer++; - } - } + if (! reg_lookup (&input_line_pointer, RWARN | RTYPE_NUM | RTYPE_GP, ®)) + reg = 0; if (frame) { mips_frame_reg = reg != 0 ? reg : SP; @@ -13044,6 +13464,9 @@ md_estimate_size_before_relax (fragS *fragp, asection *segtype) change = nopic_need_relax (fragp->fr_symbol, 0); else if (mips_pic == SVR4_PIC) change = pic_need_relax (fragp->fr_symbol, segtype); + else if (mips_pic == VXWORKS_PIC) + /* For vxworks, GOT16 relocations never have a corresponding LO16. */ + change = 0; else abort (); @@ -13123,8 +13546,24 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - assert (! fixp->fx_pcrel); - reloc->addend = fixp->fx_addnumber; + if (fixp->fx_pcrel) + { + assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2); + + /* At this point, fx_addnumber is "symbol offset - pcrel address". + Relocations want only the symbol offset. */ + reloc->addend = fixp->fx_addnumber + reloc->address; + if (OUTPUT_FLAVOR != bfd_target_elf_flavour) + { + /* A gruesome hack which is a result of the gruesome gas + reloc handling. What's worse, for COFF (as opposed to + ECOFF), we might need yet another copy of reloc->address. + See bfd_install_relocation. */ + reloc->addend += reloc->address; + } + } + else + reloc->addend = fixp->fx_addnumber; /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable entry to be used in the relocation's section offset. */ @@ -13136,18 +13575,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) code = fixp->fx_r_type; - /* To support a PC relative reloc, we used a Cygnus extension. - We check for that here to make sure that we don't let such a - reloc escape normally. (FIXME: This was formerly used by - embedded-PIC support, but is now used by branch handling in - general. That probably should be fixed.) */ - if ((OUTPUT_FLAVOR == bfd_target_ecoff_flavour - || OUTPUT_FLAVOR == bfd_target_elf_flavour) - && code == BFD_RELOC_16_PCREL_S2) - reloc->howto = NULL; - else - reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); if (reloc->howto == NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, @@ -13224,8 +13652,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) exp.X_add_number = fragp->fr_offset; fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, - 4, &exp, 1, - BFD_RELOC_16_PCREL_S2); + 4, &exp, 1, BFD_RELOC_16_PCREL_S2); fixp->fx_file = fragp->fr_file; fixp->fx_line = fragp->fr_line; @@ -13606,6 +14033,10 @@ mips_define_label (symbolS *sym) l->label = sym; l->next = insn_labels; insn_labels = l; + +#ifdef OBJ_ELF + dwarf2_emit_label (sym); +#endif } #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) @@ -13693,6 +14124,12 @@ mips_elf_final_processing (void) if (mips_32bitmode) elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE; + +#if 0 /* XXX FIXME */ + /* 32 bit code with 64 bit FP registers. */ + if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi)) + elf_elfheader (stdoutput)->e_flags |= ???; +#endif } #endif /* OBJ_ELF || OBJ_MAYBE_ELF */ @@ -14095,72 +14532,90 @@ s_mips_mask (int reg_type) static const struct mips_cpu_info mips_cpu_info_table[] = { /* Entries for generic ISAs */ - { "mips1", 1, ISA_MIPS1, CPU_R3000 }, - { "mips2", 1, ISA_MIPS2, CPU_R6000 }, - { "mips3", 1, ISA_MIPS3, CPU_R4000 }, - { "mips4", 1, ISA_MIPS4, CPU_R8000 }, - { "mips5", 1, ISA_MIPS5, CPU_MIPS5 }, - { "mips32", 1, ISA_MIPS32, CPU_MIPS32 }, - { "mips32r2", 1, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "mips64", 1, ISA_MIPS64, CPU_MIPS64 }, - { "mips64r2", 1, ISA_MIPS64R2, CPU_MIPS64R2 }, + { "mips1", MIPS_CPU_IS_ISA, ISA_MIPS1, CPU_R3000 }, + { "mips2", MIPS_CPU_IS_ISA, ISA_MIPS2, CPU_R6000 }, + { "mips3", MIPS_CPU_IS_ISA, ISA_MIPS3, CPU_R4000 }, + { "mips4", MIPS_CPU_IS_ISA, ISA_MIPS4, CPU_R8000 }, + { "mips5", MIPS_CPU_IS_ISA, ISA_MIPS5, CPU_MIPS5 }, + { "mips32", MIPS_CPU_IS_ISA, ISA_MIPS32, CPU_MIPS32 }, + { "mips32r2", MIPS_CPU_IS_ISA, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "mips64", MIPS_CPU_IS_ISA, ISA_MIPS64, CPU_MIPS64 }, + { "mips64r2", MIPS_CPU_IS_ISA, ISA_MIPS64R2, CPU_MIPS64R2 }, /* MIPS I */ - { "r3000", 0, ISA_MIPS1, CPU_R3000 }, - { "r2000", 0, ISA_MIPS1, CPU_R3000 }, - { "r3900", 0, ISA_MIPS1, CPU_R3900 }, + { "r3000", 0, ISA_MIPS1, CPU_R3000 }, + { "r2000", 0, ISA_MIPS1, CPU_R3000 }, + { "r3900", 0, ISA_MIPS1, CPU_R3900 }, /* MIPS II */ - { "r6000", 0, ISA_MIPS2, CPU_R6000 }, + { "r6000", 0, ISA_MIPS2, CPU_R6000 }, /* MIPS III */ - { "r4000", 0, ISA_MIPS3, CPU_R4000 }, - { "r4010", 0, ISA_MIPS2, CPU_R4010 }, - { "vr4100", 0, ISA_MIPS3, CPU_VR4100 }, - { "vr4111", 0, ISA_MIPS3, CPU_R4111 }, - { "vr4120", 0, ISA_MIPS3, CPU_VR4120 }, - { "vr4130", 0, ISA_MIPS3, CPU_VR4120 }, - { "vr4181", 0, ISA_MIPS3, CPU_R4111 }, - { "vr4300", 0, ISA_MIPS3, CPU_R4300 }, - { "r4400", 0, ISA_MIPS3, CPU_R4400 }, - { "r4600", 0, ISA_MIPS3, CPU_R4600 }, - { "orion", 0, ISA_MIPS3, CPU_R4600 }, - { "r4650", 0, ISA_MIPS3, CPU_R4650 }, + { "r4000", 0, ISA_MIPS3, CPU_R4000 }, + { "r4010", 0, ISA_MIPS2, CPU_R4010 }, + { "vr4100", 0, ISA_MIPS3, CPU_VR4100 }, + { "vr4111", 0, ISA_MIPS3, CPU_R4111 }, + { "vr4120", 0, ISA_MIPS3, CPU_VR4120 }, + { "vr4130", 0, ISA_MIPS3, CPU_VR4120 }, + { "vr4181", 0, ISA_MIPS3, CPU_R4111 }, + { "vr4300", 0, ISA_MIPS3, CPU_R4300 }, + { "r4400", 0, ISA_MIPS3, CPU_R4400 }, + { "r4600", 0, ISA_MIPS3, CPU_R4600 }, + { "orion", 0, ISA_MIPS3, CPU_R4600 }, + { "r4650", 0, ISA_MIPS3, CPU_R4650 }, /* MIPS IV */ - { "r8000", 0, ISA_MIPS4, CPU_R8000 }, - { "r10000", 0, ISA_MIPS4, CPU_R10000 }, - { "r12000", 0, ISA_MIPS4, CPU_R12000 }, - { "vr5000", 0, ISA_MIPS4, CPU_R5000 }, - { "vr5400", 0, ISA_MIPS4, CPU_VR5400 }, - { "vr5500", 0, ISA_MIPS4, CPU_VR5500 }, - { "rm5200", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5230", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5231", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5261", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5721", 0, ISA_MIPS4, CPU_R5000 }, - { "rm7000", 0, ISA_MIPS4, CPU_RM7000 }, - { "rm9000", 0, ISA_MIPS4, CPU_RM9000 }, + { "r8000", 0, ISA_MIPS4, CPU_R8000 }, + { "r10000", 0, ISA_MIPS4, CPU_R10000 }, + { "r12000", 0, ISA_MIPS4, CPU_R12000 }, + { "vr5000", 0, ISA_MIPS4, CPU_R5000 }, + { "vr5400", 0, ISA_MIPS4, CPU_VR5400 }, + { "vr5500", 0, ISA_MIPS4, CPU_VR5500 }, + { "rm5200", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5230", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5231", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5261", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5721", 0, ISA_MIPS4, CPU_R5000 }, + { "rm7000", 0, ISA_MIPS4, CPU_RM7000 }, + { "rm9000", 0, ISA_MIPS4, CPU_RM9000 }, /* MIPS 32 */ - { "4kc", 0, ISA_MIPS32, CPU_MIPS32 }, - { "4km", 0, ISA_MIPS32, CPU_MIPS32 }, - { "4kp", 0, ISA_MIPS32, CPU_MIPS32 }, - - /* MIPS32 Release 2 */ - { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kc", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4km", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4kp", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4ksc", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32, CPU_MIPS32 }, + + /* MIPS 32 Release 2 */ + { "4kec", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kem", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kep", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4ksd", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "m4kp", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + /* 24ke is a 24k with DSP ASE, other ASEs are optional. */ + { "24ke", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kec", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kef", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kex", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + /* 34k is a 24k with MT ASE, other ASEs are optional. */ + { "34kc", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "34kf", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "34kx", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, /* MIPS 64 */ - { "5kc", 0, ISA_MIPS64, CPU_MIPS64 }, - { "5kf", 0, ISA_MIPS64, CPU_MIPS64 }, - { "20kc", 0, ISA_MIPS64, CPU_MIPS64 }, + { "5kc", 0, ISA_MIPS64, CPU_MIPS64 }, + { "5kf", 0, ISA_MIPS64, CPU_MIPS64 }, + { "20kc", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 }, + + /* MIPS 64 Release 2 */ + { "25kf", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64R2, CPU_MIPS64R2 }, /* Broadcom SB-1 CPU core */ - { "sb1", 0, ISA_MIPS64, CPU_SB1 }, + { "sb1", 0, ISA_MIPS64, CPU_SB1 }, /* End marker */ { NULL, 0, 0, 0 } @@ -14275,7 +14730,7 @@ mips_cpu_info_from_isa (int isa) int i; for (i = 0; mips_cpu_info_table[i].name != NULL; i++) - if (mips_cpu_info_table[i].is_isa + if ((mips_cpu_info_table[i].flags & MIPS_CPU_IS_ISA) && isa == mips_cpu_info_table[i].isa) return (&mips_cpu_info_table[i]); @@ -14369,6 +14824,9 @@ MIPS options:\n\ -mips16 generate mips16 instructions\n\ -no-mips16 do not generate mips16 instructions\n")); fprintf (stream, _("\ +-msmartmips generate smartmips instructions\n\ +-mno-smartmips do not generate smartmips instructions\n")); + fprintf (stream, _("\ -mdsp generate DSP instructions\n\ -mno-dsp do not generate DSP instructions\n")); fprintf (stream, _("\ @@ -14444,3 +14902,14 @@ mips_cfi_frame_initial_instructions (void) cfi_add_CFA_def_cfa_register (SP); } +int +tc_mips_regname_to_dw2regnum (char *regname) +{ + unsigned int regnum = -1; + unsigned int reg; + + if (reg_lookup (®name, RTYPE_GP | RTYPE_NUM, ®)) + regnum = reg; + + return regnum; +}