X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fconfig%2Ftc-mips.c;h=6eff83672c63b4b6fff451d14a53762232f48401;hb=b47468a6dbd1b54c44c2edc0f7db64a073d894ea;hp=dcea7bcf2692f5333827e357141509b24373f50b;hpb=e64af278469a4101a3fa515bda4d2d977051b8d4;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index dcea7bcf26..6eff83672c 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1,6 +1,6 @@ /* tc-mips.c -- assemble code for a MIPS chip. Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. Contributed by the OSF and Ralph Campbell. Written by Keith Knowles and Ralph Campbell, working independently. @@ -171,6 +171,10 @@ struct mips_cl_insn /* True if this instruction is complete. */ unsigned int complete_p : 1; + + /* True if this instruction is cleared from history by unconditional + branch. */ + unsigned int cleared_p : 1; }; /* The ABI to use. */ @@ -500,6 +504,10 @@ static int mips_32bitmode = 0; /* True if CPU has seq/sne and seqi/snei instructions. */ #define CPU_HAS_SEQ(CPU) (CPU_IS_OCTEON (CPU)) +/* True, if CPU has support for ldc1 and sdc1. */ +#define CPU_HAS_LDC1_SDC1(CPU) \ + ((mips_opts.isa != ISA_MIPS1) && ((CPU) != CPU_R5900)) + /* True if mflo and mfhi can be immediately followed by instructions which write to the HI and LO registers. @@ -518,6 +526,7 @@ static int mips_32bitmode = 0; || mips_opts.isa == ISA_MIPS64 \ || mips_opts.isa == ISA_MIPS64R2 \ || mips_opts.arch == CPU_R4010 \ + || mips_opts.arch == CPU_R5900 \ || mips_opts.arch == CPU_R10000 \ || mips_opts.arch == CPU_R12000 \ || mips_opts.arch == CPU_R14000 \ @@ -535,6 +544,7 @@ static int mips_32bitmode = 0; #define gpr_interlocks \ (mips_opts.isa != ISA_MIPS1 \ || mips_opts.arch == CPU_R3900 \ + || mips_opts.arch == CPU_R5900 \ || mips_opts.micromips \ ) @@ -1304,9 +1314,6 @@ static struct { /* Prototypes for static functions. */ -#define internalError() \ - as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__) - enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG, MIPS16_REG }; static void append_insn @@ -1465,7 +1472,9 @@ static const pseudo_typeS mips_pseudo_table[] = {"section", s_change_section, 0}, {"short", s_cons, 1}, {"single", s_float_cons, 'f'}, + {"stabd", s_mips_stab, 'd'}, {"stabn", s_mips_stab, 'n'}, + {"stabs", s_mips_stab, 's'}, {"text", s_change_sec, 't'}, {"word", s_cons, 2}, @@ -1679,6 +1688,7 @@ create_insn (struct mips_cl_insn *insn, const struct mips_opcode *mo) insn->noreorder_p = (mips_opts.noreorder > 0); insn->mips16_absolute_jump_p = 0; insn->complete_p = 0; + insn->cleared_p = 0; } /* Record the current MIPS16/microMIPS mode in now_seg. */ @@ -2321,8 +2331,7 @@ is_delay_slot_valid (const struct mips_opcode *mo) return TRUE; if (mo->pinfo == INSN_MACRO) - return ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0 - ? TRUE : FALSE); + return (history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_16BIT) == 0; if ((history[0].insn_mo->pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0 && micromips_insn_length (mo) != 4) return FALSE; @@ -2735,6 +2744,28 @@ jalr_reloc_p (bfd_reloc_code_real_type reloc) return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR; } +/* Return true if RELOC is a PC-relative relocation that does not have + full address range. */ + +static inline bfd_boolean +limited_pcrel_reloc_p (bfd_reloc_code_real_type reloc) +{ + switch (reloc) + { + case BFD_RELOC_16_PCREL_S2: + case BFD_RELOC_MICROMIPS_7_PCREL_S1: + case BFD_RELOC_MICROMIPS_10_PCREL_S1: + case BFD_RELOC_MICROMIPS_16_PCREL_S1: + return TRUE; + + case BFD_RELOC_32_PCREL: + return HAVE_64BIT_ADDRESSES; + + default: + return FALSE; + } +} + /* Return true if the given relocation might need a matching %lo(). This is only "might" because SVR4 R_MIPS_GOT16 relocations only need a matching %lo() when applied to local symbols. */ @@ -3736,10 +3767,13 @@ fix_loongson2f (struct mips_cl_insn * ip) /* IP is a branch that has a delay slot, and we need to fill it automatically. Return true if we can do that by swapping IP - with the previous instruction. */ + with the previous instruction. + ADDRESS_EXPR is an operand of the instruction to be used with + RELOC_TYPE. */ static bfd_boolean -can_swap_branch_p (struct mips_cl_insn *ip) +can_swap_branch_p (struct mips_cl_insn *ip, expressionS *address_expr, + bfd_reloc_code_real_type *reloc_type) { unsigned long pinfo, pinfo2, prev_pinfo, prev_pinfo2; unsigned int gpr_read, gpr_write, prev_gpr_read, prev_gpr_write; @@ -3858,13 +3892,64 @@ can_swap_branch_p (struct mips_cl_insn *ip) && insn_length (history) != 4) return FALSE; + /* On R5900 short loops need to be fixed by inserting a nop in + the branch delay slots. + A short loop can be terminated too early. */ + if (mips_opts.arch == CPU_R5900 + /* Check if instruction has a parameter, ignore "j $31". */ + && (address_expr != NULL) + /* Parameter must be 16 bit. */ + && (*reloc_type == BFD_RELOC_16_PCREL_S2) + /* Branch to same segment. */ + && (S_GET_SEGMENT(address_expr->X_add_symbol) == now_seg) + /* Branch to same code fragment. */ + && (symbol_get_frag(address_expr->X_add_symbol) == frag_now) + /* Can only calculate branch offset if value is known. */ + && symbol_constant_p(address_expr->X_add_symbol) + /* Check if branch is really conditional. */ + && !((ip->insn_opcode & 0xffff0000) == 0x10000000 /* beq $0,$0 */ + || (ip->insn_opcode & 0xffff0000) == 0x04010000 /* bgez $0 */ + || (ip->insn_opcode & 0xffff0000) == 0x04110000)) /* bgezal $0 */ + { + int distance; + /* Check if loop is shorter than 6 instructions including + branch and delay slot. */ + distance = frag_now_fix() - S_GET_VALUE(address_expr->X_add_symbol); + if (distance <= 20) + { + int i; + int rv; + + rv = FALSE; + /* When the loop includes branches or jumps, + it is not a short loop. */ + for (i = 0; i < (distance / 4); i++) + { + if ((history[i].cleared_p) + || delayed_branch_p(&history[i])) + { + rv = TRUE; + break; + } + } + if (rv == FALSE) + { + /* Insert nop after branch to fix short loop. */ + return FALSE; + } + } + } + return TRUE; } -/* Decide how we should add IP to the instruction stream. */ +/* Decide how we should add IP to the instruction stream. + ADDRESS_EXPR is an operand of the instruction to be used with + RELOC_TYPE. */ static enum append_method -get_append_method (struct mips_cl_insn *ip) +get_append_method (struct mips_cl_insn *ip, expressionS *address_expr, + bfd_reloc_code_real_type *reloc_type) { unsigned long pinfo; @@ -3880,7 +3965,8 @@ get_append_method (struct mips_cl_insn *ip) /* Otherwise, it's our responsibility to fill branch delay slots. */ if (delayed_branch_p (ip)) { - if (!branch_likely_p (ip) && can_swap_branch_p (ip)) + if (!branch_likely_p (ip) + && can_swap_branch_p (ip, address_expr, reloc_type)) return APPEND_SWAP; pinfo = ip->insn_mo->pinfo; @@ -4261,7 +4347,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, } } - method = get_append_method (ip); + method = get_append_method (ip, address_expr, reloc_type); branch_disp = method == APPEND_SWAP ? insn_length (history) : 0; #ifdef OBJ_ELF @@ -4464,6 +4550,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, || lo16_reloc_p (reloc_type[0]))) ip->fixp[0]->fx_no_overflow = 1; + /* These relocations can have an addend that won't fit in 2 octets. */ + if (reloc_type[0] == BFD_RELOC_MICROMIPS_7_PCREL_S1 + || reloc_type[0] == BFD_RELOC_MICROMIPS_10_PCREL_S1) + ip->fixp[0]->fx_no_overflow = 1; + if (mips_relax.sequence) { if (mips_relax.first_fixup == 0) @@ -4574,7 +4665,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, /* If we have just completed an unconditional branch, clear the history. */ if ((delayed_branch_p (&history[1]) && uncond_branch_p (&history[1])) || (compact_branch_p (&history[0]) && uncond_branch_p (&history[0]))) - mips_no_prev_insn (); + { + unsigned int i; + + mips_no_prev_insn (); + + for (i = 0; i < ARRAY_SIZE (history); i++) + history[i].cleared_p = 1; + } /* We need to emit a label at the end of branch-likely macros. */ if (emit_branch_likely_macro) @@ -4587,7 +4685,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, mips_clear_insn_labels (); } -/* Forget that there was any previous instruction or label. */ +/* Forget that there was any previous instruction or label. + When BRANCH is true, the branch history is also flushed. */ static void mips_no_prev_insn (void) @@ -4954,7 +5053,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) continue; default: - internalError (); + abort (); } continue; @@ -5158,12 +5257,12 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) break; default: - internalError (); + abort (); } continue; default: - internalError (); + abort (); } break; } @@ -8854,7 +8953,7 @@ macro (struct mips_cl_insn *ip) s = segment_name (S_GET_SEGMENT (offset_expr.X_add_symbol)); if (strcmp (s, ".lit8") == 0) { - if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips) + if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips) { macro_build (&offset_expr, "ldc1", "T,o(b)", treg, BFD_RELOC_MIPS_LITERAL, mips_gp_register); @@ -8877,7 +8976,7 @@ macro (struct mips_cl_insn *ip) macro_build_lui (&offset_expr, AT); } - if (mips_opts.isa != ISA_MIPS1 || mips_opts.micromips) + if (CPU_HAS_LDC1_SDC1 (mips_opts.arch) || mips_opts.micromips) { macro_build (&offset_expr, "ldc1", "T,o(b)", treg, BFD_RELOC_LO16, AT); @@ -8894,7 +8993,7 @@ macro (struct mips_cl_insn *ip) r = BFD_RELOC_LO16; dob: gas_assert (!mips_opts.micromips); - gas_assert (mips_opts.isa == ISA_MIPS1); + gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch)); macro_build (&offset_expr, "lwc1", "T,o(b)", target_big_endian ? treg + 1 : treg, r, breg); /* FIXME: A possible overflow which I don't know how to deal @@ -8906,7 +9005,7 @@ macro (struct mips_cl_insn *ip) case M_S_DOB: gas_assert (!mips_opts.micromips); - gas_assert (mips_opts.isa == ISA_MIPS1); + gas_assert (!CPU_HAS_LDC1_SDC1 (mips_opts.arch)); /* Even on a big endian machine $fn comes before $fn+1. We have to adjust when storing to memory. */ macro_build (&offset_expr, "swc1", "T,o(b)", @@ -8932,7 +9031,7 @@ macro (struct mips_cl_insn *ip) /* Itbl support may require additional care here. */ coproc = 1; fmt = "T,o(b)"; - if (mips_opts.isa != ISA_MIPS1) + if (CPU_HAS_LDC1_SDC1 (mips_opts.arch)) { s = "ldc1"; goto ld_st; @@ -8945,7 +9044,7 @@ macro (struct mips_cl_insn *ip) /* Itbl support may require additional care here. */ coproc = 1; fmt = "T,o(b)"; - if (mips_opts.isa != ISA_MIPS1) + if (CPU_HAS_LDC1_SDC1 (mips_opts.arch)) { s = "sdc1"; goto ld_st; @@ -8953,6 +9052,16 @@ macro (struct mips_cl_insn *ip) s = "swc1"; goto ldd_std; + case M_LQ_AB: + fmt = "t,o(b)"; + s = "lq"; + goto ld; + + case M_SQ_AB: + fmt = "t,o(b)"; + s = "sq"; + goto ld_st; + case M_LD_AB: fmt = "t,o(b)"; if (HAVE_64BIT_GPRS) @@ -9265,8 +9374,15 @@ macro (struct mips_cl_insn *ip) case M_DMUL: dbl = 1; case M_MUL: + if (mips_opts.arch == CPU_R5900) + { + macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", dreg, sreg, treg); + } + else + { macro_build (NULL, dbl ? "dmultu" : "multu", "s,t", sreg, treg); macro_build (NULL, "mflo", MFHL_FMT, dreg); + } break; case M_DMUL_I: @@ -10056,7 +10172,7 @@ mips16_macro (struct mips_cl_insn *ip) switch (mask) { default: - internalError (); + abort (); case M_DDIV_3: dbl = 1; @@ -10634,7 +10750,7 @@ mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum) /* Let a macro pass, we'll catch it later when it is expanded. */ return 1; - if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa)) + if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa) || (mips_opts.arch == CPU_R5900)) { /* Allow odd registers for single-precision ops. */ switch (insn->pinfo & (FP_S | FP_D)) @@ -10698,6 +10814,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) unsigned int destregno = 0; unsigned int lastpos = 0; unsigned int limlo, limhi; + int sizelo; char *s_reset; offsetT min_range, max_range; long opend; @@ -11204,7 +11321,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) while (imm->type && imm->type != *args) ++imm; if (! imm->type) - internalError (); + abort (); my_getExpression (&imm_expr, s); check_absolute_expr (ip, &imm_expr); if ((unsigned long) imm_expr.X_add_number & ~imm->mask) @@ -11282,23 +11399,25 @@ mips_ip (char *str, struct mips_cl_insn *ip) case 'C': /* ext size, becomes MSBD. */ limlo = 1; limhi = 32; + sizelo = 1; goto do_msbd; case 'G': limlo = 33; limhi = 64; + sizelo = 33; goto do_msbd; case 'H': limlo = 33; limhi = 64; + sizelo = 1; goto do_msbd; do_msbd: my_getExpression (&imm_expr, s); check_absolute_expr (ip, &imm_expr); - /* Check for negative input so that small negative numbers - will not succeed incorrectly. The checks against - (pos+size) transitively check "size" itself, - assuming that "pos" is reasonable. */ - if ((long) imm_expr.X_add_number < 0 + /* The checks against (pos+size) don't transitively check + "size" itself, assuming that "pos" is reasonable. + We also need to check the lower bound of "size". */ + if ((long) imm_expr.X_add_number < sizelo || ((unsigned long) imm_expr.X_add_number + lastpos) < limlo || ((unsigned long) imm_expr.X_add_number @@ -11785,6 +11904,10 @@ mips_ip (char *str, struct mips_cl_insn *ip) if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1) as_warn (_("Invalid performance register (%lu)"), (unsigned long) imm_expr.X_add_number); + if (imm_expr.X_add_number != 0 && mips_opts.arch == CPU_R5900 + && (!strcmp(insn->name,"mfps") || !strcmp(insn->name,"mtps"))) + as_warn (_("Invalid performance register (%lu)"), + (unsigned long) imm_expr.X_add_number); INSERT_OPERAND (0, PERFREG, *ip, imm_expr.X_add_number); imm_expr.X_op = O_absent; s = expr_end; @@ -12409,6 +12532,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) continue; case 'u': /* Upper 16 bits. */ + *imm_reloc = BFD_RELOC_LO16; if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0 && imm_expr.X_op == O_constant && (imm_expr.X_add_number < 0 @@ -12734,7 +12858,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) break; default: - internalError (); + abort (); } if (regno == ILLEGAL_REG) @@ -12807,7 +12931,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) break; default: - internalError (); + abort (); } continue; @@ -13271,7 +13395,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) default: as_bad (_("Bad char = '%c'\n"), *args); - internalError (); + abort (); } break; } @@ -13548,7 +13672,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip) break; default: - internalError (); + abort (); } if (regno == ILLEGAL_REG) @@ -13581,7 +13705,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip) MIPS16_INSERT_OPERAND (REG32R, *ip, regno); break; default: - internalError (); + abort (); } lastregno = regno; @@ -13940,7 +14064,7 @@ mips16_ip (char *str, struct mips_cl_insn *ip) continue; default: - internalError (); + abort (); } break; } @@ -15295,6 +15419,9 @@ md_pcrel_from (fixS *fixP) /* Return the address of the delay slot. */ return addr + 4; + case BFD_RELOC_32_PCREL: + return addr; + default: /* We have no relocation type for PC relative MIPS16 instructions. */ if (fixP->fx_addsy && S_GET_SEGMENT (fixP->fx_addsy) != now_seg) @@ -15517,7 +15644,8 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) gas_assert (!fixP->fx_pcrel || fixP->fx_r_type == BFD_RELOC_16_PCREL_S2 || fixP->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1 || fixP->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1 - || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1); + || fixP->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1 + || fixP->fx_r_type == BFD_RELOC_32_PCREL); /* Don't treat parts of a composite relocation as done. There are two reasons for this: @@ -15665,6 +15793,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) case BFD_RELOC_RVA: case BFD_RELOC_32: + case BFD_RELOC_32_PCREL: case BFD_RELOC_16: /* If we are deleting this reloc entry, we must fill in the value now. This can happen if we have a .word which is not @@ -15751,7 +15880,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) break; default: - internalError (); + abort (); } /* Remember value for tc_gen_reloc. */ @@ -16375,7 +16504,14 @@ s_mipsset (int x ATTRIBUTE_UNUSED) case ISA_MIPS64: case ISA_MIPS64R2: mips_opts.gp32 = 0; + if (mips_opts.arch == CPU_R5900) + { + mips_opts.fp32 = 1; + } + else + { mips_opts.fp32 = 0; + } break; default: as_bad (_("unknown ISA level %s"), name + 4); @@ -16517,6 +16653,9 @@ s_cpload (int ignore ATTRIBUTE_UNUSED) /* In ELF, this symbol is implicitly an STT_OBJECT symbol. */ symbol_get_bfdsym (ex.X_add_symbol)->flags |= BSF_OBJECT; + mips_mark_labels (); + mips_assembling_insn = TRUE; + macro_start (); macro_build_lui (&ex, mips_gp_register); macro_build (&ex, "addiu", "t,r,j", mips_gp_register, @@ -16526,6 +16665,7 @@ s_cpload (int ignore ATTRIBUTE_UNUSED) mips_gp_register, reg); macro_end (); + mips_assembling_insn = FALSE; demand_empty_rest_of_line (); } @@ -16602,6 +16742,9 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) SKIP_WHITESPACE (); expression (&ex_sym); + mips_mark_labels (); + mips_assembling_insn = TRUE; + macro_start (); if (mips_cpreturn_register == -1) { @@ -16649,6 +16792,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) macro_end (); + mips_assembling_insn = FALSE; demand_empty_rest_of_line (); } @@ -16706,11 +16850,15 @@ s_cprestore (int ignore ATTRIBUTE_UNUSED) ex.X_op_symbol = NULL; ex.X_add_number = mips_cprestore_offset; + mips_mark_labels (); + mips_assembling_insn = TRUE; + macro_start (); macro_build_ldst_constoffset (&ex, ADDRESS_STORE_INSN, mips_gp_register, SP, HAVE_64BIT_ADDRESSES); macro_end (); + mips_assembling_insn = FALSE; demand_empty_rest_of_line (); } @@ -16741,6 +16889,9 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED) return; } + mips_mark_labels (); + mips_assembling_insn = TRUE; + macro_start (); if (mips_cpreturn_register == -1) { @@ -16756,6 +16907,7 @@ s_cpreturn (int ignore ATTRIBUTE_UNUSED) mips_cpreturn_register, 0); macro_end (); + mips_assembling_insn = FALSE; demand_empty_rest_of_line (); } @@ -16935,12 +17087,16 @@ s_cpadd (int ignore ATTRIBUTE_UNUSED) return; } + mips_mark_labels (); + mips_assembling_insn = TRUE; + /* Add $gp to the register named as an argument. */ macro_start (); reg = tc_get_register (0); macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", reg, reg, mips_gp_register); macro_end (); + mips_assembling_insn = FALSE; demand_empty_rest_of_line (); } @@ -16961,18 +17117,24 @@ s_insn (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } -/* Handle a .stabn directive. We need these in order to mark a label - as being a mips16 text label correctly. Sometimes the compiler - will emit a label, followed by a .stabn, and then switch sections. - If the label and .stabn are in mips16 mode, then the label is - really a mips16 text label. */ +/* Handle a .stab[snd] directive. Ideally these directives would be + implemented in a transparent way, so that removing them would not + have any effect on the generated instructions. However, s_stab + internally changes the section, so in practice we need to decide + now whether the preceding label marks compressed code. We do not + support changing the compression mode of a label after a .stab* + directive, such as in: + + foo: + .stabs ... + .set mips16 + + so the current mode wins. */ static void s_mips_stab (int type) { - if (type == 'n') - mips_mark_labels (); - + mips_mark_labels (); s_stab (type); } @@ -17679,11 +17841,12 @@ mips_fix_adjustable (fixS *fixp) return 0; /* There is no place to store an in-place offset for JALR relocations. - Likewise an in-range offset of PC-relative relocations may overflow - the in-place relocatable field if recalculated against the start - address of the symbol's containing section. */ + Likewise an in-range offset of limited PC-relative relocations may + overflow the in-place relocatable field if recalculated against the + start address of the symbol's containing section. */ if (HAVE_IN_PLACE_ADDENDS - && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type))) + && (limited_pcrel_reloc_p (fixp->fx_r_type) + || jalr_reloc_p (fixp->fx_r_type))) return 0; #ifdef OBJ_ELF @@ -17763,7 +17926,8 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_7_PCREL_S1 || fixp->fx_r_type == BFD_RELOC_MICROMIPS_10_PCREL_S1 - || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1); + || fixp->fx_r_type == BFD_RELOC_MICROMIPS_16_PCREL_S1 + || fixp->fx_r_type == BFD_RELOC_32_PCREL); /* At this point, fx_addnumber is "symbol offset - pcrel address". Relocations want only the symbol offset. */ @@ -19077,6 +19241,7 @@ static const struct mips_cpu_info mips_cpu_info_table[] = { "r4600", 0, ISA_MIPS3, CPU_R4600 }, { "orion", 0, ISA_MIPS3, CPU_R4600 }, { "r4650", 0, ISA_MIPS3, CPU_R4650 }, + { "r5900", 0, ISA_MIPS3, CPU_R5900 }, /* ST Microelectronics Loongson 2E and 2F cores */ { "loongson2e", 0, ISA_MIPS3, CPU_LOONGSON_2E }, { "loongson2f", 0, ISA_MIPS3, CPU_LOONGSON_2F },