From: Thiemo Seufer Date: Thu, 4 Oct 2001 20:07:00 +0000 (+0000) Subject: * config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a X-Git-Tag: cygnus_cvs_20020108_pre~1146 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f668894301100e2e5ef05832e2dee08b90112a1e;p=external%2Fbinutils.git * config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a relocation triple. (prev_insn_fixp): Likewise. (append_insn): Changed prototype to accept a relocation pointer. (imm_reloc): Make it an array. (offset_reloc): Likewise. (md_assemble): Handle triple relocations. (append_insn): Likewise. Add handling for some NewABI relocations. (mips_no_prev_insn): Handle triple relocations. (macro_build): Likewise. Add handling for some NewABI relocations. Move handling for the 'u' case to append_insn(). (mips16_macro_build): Handle triple relocations. (macro_build_lui): Likewise. Don't handle _gp_disp as special symbol for NewABI. (mips_ip): Handle triple relocations. (mips16_ip): Likewise. (mips_force_relocation): Force handling of triple relocations without symbols for NewABI. (md_apply_fix): Add handling for some NewABI relocations. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index a74637a..c35a822 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,25 @@ +2001-10-04 Thiemo Seufer + + * config/tc-mips.c (prev_insn_reloc_type): Make it an array to hold a + relocation triple. + (prev_insn_fixp): Likewise. + (append_insn): Changed prototype to accept a relocation pointer. + (imm_reloc): Make it an array. + (offset_reloc): Likewise. + (md_assemble): Handle triple relocations. + (append_insn): Likewise. Add handling for some NewABI relocations. + (mips_no_prev_insn): Handle triple relocations. + (macro_build): Likewise. Add handling for some NewABI relocations. + Move handling for the 'u' case to append_insn(). + (mips16_macro_build): Handle triple relocations. + (macro_build_lui): Likewise. Don't handle _gp_disp as special symbol + for NewABI. + (mips_ip): Handle triple relocations. + (mips16_ip): Likewise. + (mips_force_relocation): Force handling of triple relocations + without symbols for NewABI. + (md_apply_fix): Add handling for some NewABI relocations. + 2001-10-05 Alan Modra * config/tc-i386.c (parse_register): If not producing code for diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index cb6dd62..9a5abb1 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -430,10 +430,10 @@ static struct frag *prev_insn_frag; static long prev_insn_where; /* The reloc type for the previous instruction, if any. */ -static bfd_reloc_code_real_type prev_insn_reloc_type; +static bfd_reloc_code_real_type prev_insn_reloc_type[3]; /* The reloc for the previous instruction, if any. */ -static fixS *prev_insn_fixp; +static fixS *prev_insn_fixp[3]; /* Non-zero if the previous instruction was in a delay slot. */ static int prev_insn_is_delay_slot; @@ -643,7 +643,7 @@ static void mips16_mark_labels PARAMS ((void)); static void append_insn PARAMS ((char *place, struct mips_cl_insn * ip, expressionS * p, - bfd_reloc_code_real_type r, + bfd_reloc_code_real_type *r, boolean)); static void mips_no_prev_insn PARAMS ((int)); static void mips_emit_delays PARAMS ((boolean)); @@ -868,8 +868,10 @@ static expressionS offset_expr; /* Relocs associated with imm_expr and offset_expr. */ -static bfd_reloc_code_real_type imm_reloc; -static bfd_reloc_code_real_type offset_reloc; +static bfd_reloc_code_real_type imm_reloc[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; +static bfd_reloc_code_real_type offset_reloc[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; /* This is set by mips_ip if imm_reloc is an unmatched HI16_S reloc. */ @@ -1303,12 +1305,18 @@ md_assemble (str) char *str; { struct mips_cl_insn insn; + bfd_reloc_code_real_type unused_reloc[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; imm_expr.X_op = O_absent; - imm_reloc = BFD_RELOC_UNUSED; imm_unmatched_hi = false; offset_expr.X_op = O_absent; - offset_reloc = BFD_RELOC_UNUSED; + imm_reloc[0] = BFD_RELOC_UNUSED; + imm_reloc[1] = BFD_RELOC_UNUSED; + imm_reloc[2] = BFD_RELOC_UNUSED; + offset_reloc[0] = BFD_RELOC_UNUSED; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; if (mips_opts.mips16) mips16_ip (str, &insn); @@ -1340,7 +1348,7 @@ md_assemble (str) else if (offset_expr.X_op != O_absent) append_insn ((char *) NULL, &insn, &offset_expr, offset_reloc, false); else - append_insn ((char *) NULL, &insn, NULL, BFD_RELOC_UNUSED, false); + append_insn ((char *) NULL, &insn, NULL, unused_reloc, false); } } @@ -1492,12 +1500,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) char *place; struct mips_cl_insn *ip; expressionS *address_expr; - bfd_reloc_code_real_type reloc_type; + bfd_reloc_code_real_type *reloc_type; boolean unmatched_hi; { register unsigned long prev_pinfo, pinfo; char *f; - fixS *fixp; + fixS *fixp[3]; int nops = 0; /* Mark instruction labels in mips16 mode. */ @@ -1843,16 +1851,16 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) } } - if (reloc_type > BFD_RELOC_UNUSED) + if (*reloc_type > BFD_RELOC_UNUSED) { /* We need to set up a variant frag. */ assert (mips_opts.mips16 && address_expr != NULL); f = frag_var (rs_machine_dependent, 4, 0, - RELAX_MIPS16_ENCODE (reloc_type - BFD_RELOC_UNUSED, + RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, mips16_small, mips16_ext, (prev_pinfo & INSN_UNCOND_BRANCH_DELAY), - (prev_insn_reloc_type + (*prev_insn_reloc_type == BFD_RELOC_MIPS16_JMP)), make_expr_symbol (address_expr), (offsetT) 0, (char *) NULL); @@ -1861,7 +1869,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) f = place; else if (mips_opts.mips16 && ! ip->use_extend - && reloc_type != BFD_RELOC_MIPS16_JMP) + && *reloc_type != BFD_RELOC_MIPS16_JMP) { /* Make sure there is enough room to swap this instruction with a following jump instruction. */ @@ -1878,17 +1886,39 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) f = frag_more (4); } - fixp = NULL; - if (address_expr != NULL && reloc_type < BFD_RELOC_UNUSED) + fixp[0] = fixp[1] = fixp[2] = NULL; + if (address_expr != NULL && *reloc_type < BFD_RELOC_UNUSED) { if (address_expr->X_op == O_constant) { - switch (reloc_type) + unsigned long tmp; + + switch (*reloc_type) { case BFD_RELOC_32: ip->insn_opcode |= address_expr->X_add_number; break; + case BFD_RELOC_MIPS_HIGHEST: + tmp = (address_expr->X_add_number + 0x800080008000) >> 16; + tmp >>= 16; + ip->insn_opcode |= (tmp >> 16) & 0xffff; + break; + + case BFD_RELOC_MIPS_HIGHER: + tmp = (address_expr->X_add_number + 0x80008000) >> 16; + ip->insn_opcode |= (tmp >> 16) & 0xffff; + break; + + case BFD_RELOC_HI16_S: + ip->insn_opcode |= ((address_expr->X_add_number + 0x8000) + >> 16) & 0xffff; + break; + + case BFD_RELOC_HI16: + ip->insn_opcode |= (address_expr->X_add_number >> 16) & 0xffff; + break; + case BFD_RELOC_LO16: ip->insn_opcode |= address_expr->X_add_number & 0xffff; break; @@ -1924,34 +1954,122 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) else { need_reloc: - /* Don't generate a reloc if we are writing into a variant - frag. */ + /* Don't generate a reloc if we are writing into a variant frag. */ if (place == NULL) { - fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 4, - address_expr, - (reloc_type == BFD_RELOC_16_PCREL - || reloc_type == BFD_RELOC_16_PCREL_S2), - reloc_type); + fixp[0] = fix_new_exp (frag_now, f - frag_now->fr_literal, 4, + address_expr, + (*reloc_type == BFD_RELOC_16_PCREL + || *reloc_type == BFD_RELOC_16_PCREL_S2), + reloc_type[0]); + + /* These relocations can have a addend that won't fit in + 4 octets for 64bit assembly. */ + if (HAVE_64BIT_GPRS && + (*reloc_type == BFD_RELOC_16 + || *reloc_type == BFD_RELOC_32 + || *reloc_type == BFD_RELOC_MIPS_JMP + || *reloc_type == BFD_RELOC_HI16_S + || *reloc_type == BFD_RELOC_LO16 + || *reloc_type == BFD_RELOC_GPREL16 + || *reloc_type == BFD_RELOC_MIPS_LITERAL + || *reloc_type == BFD_RELOC_GPREL32 + || *reloc_type == BFD_RELOC_64 + || *reloc_type == BFD_RELOC_CTOR + || *reloc_type == BFD_RELOC_MIPS_SUB + || *reloc_type == BFD_RELOC_MIPS_HIGHEST + || *reloc_type == BFD_RELOC_MIPS_HIGHER + || *reloc_type == BFD_RELOC_MIPS_SCN_DISP + || *reloc_type == BFD_RELOC_MIPS_REL16 + || *reloc_type == BFD_RELOC_MIPS_RELGOT)) + fixp[0]->fx_no_overflow = 1; + if (unmatched_hi) { struct mips_hi_fixup *hi_fixup; - assert (reloc_type == BFD_RELOC_HI16_S); + assert (*reloc_type == BFD_RELOC_HI16_S); hi_fixup = ((struct mips_hi_fixup *) xmalloc (sizeof (struct mips_hi_fixup))); - hi_fixup->fixp = fixp; + hi_fixup->fixp = fixp[0]; hi_fixup->seg = now_seg; hi_fixup->next = mips_hi_fixup_list; mips_hi_fixup_list = hi_fixup; } + + if (reloc_type[1] != BFD_RELOC_UNUSED) + { + /* FIXME: This symbol can be one of + RSS_UNDEF, RSS_GP, RSS_GP0, RSS_LOC. */ + address_expr->X_op = O_absent; + address_expr->X_add_symbol = 0; + address_expr->X_add_number = 0; + + fixp[1] = fix_new_exp (frag_now, f - frag_now->fr_literal, + 4, address_expr, false, + reloc_type[1]); + + /* These relocations can have a addend that won't fit in + 4 octets for 64bit assembly. */ + if (HAVE_64BIT_GPRS && + (*reloc_type == BFD_RELOC_16 + || *reloc_type == BFD_RELOC_32 + || *reloc_type == BFD_RELOC_MIPS_JMP + || *reloc_type == BFD_RELOC_HI16_S + || *reloc_type == BFD_RELOC_LO16 + || *reloc_type == BFD_RELOC_GPREL16 + || *reloc_type == BFD_RELOC_MIPS_LITERAL + || *reloc_type == BFD_RELOC_GPREL32 + || *reloc_type == BFD_RELOC_64 + || *reloc_type == BFD_RELOC_CTOR + || *reloc_type == BFD_RELOC_MIPS_SUB + || *reloc_type == BFD_RELOC_MIPS_HIGHEST + || *reloc_type == BFD_RELOC_MIPS_HIGHER + || *reloc_type == BFD_RELOC_MIPS_SCN_DISP + || *reloc_type == BFD_RELOC_MIPS_REL16 + || *reloc_type == BFD_RELOC_MIPS_RELGOT)) + fixp[1]->fx_no_overflow = 1; + + if (reloc_type[2] != BFD_RELOC_UNUSED) + { + address_expr->X_op = O_absent; + address_expr->X_add_symbol = 0; + address_expr->X_add_number = 0; + + fixp[2] = fix_new_exp (frag_now, + f - frag_now->fr_literal, 4, + address_expr, false, + reloc_type[2]); + + /* These relocations can have a addend that won't fit in + 4 octets for 64bit assembly. */ + if (HAVE_64BIT_GPRS && + (*reloc_type == BFD_RELOC_16 + || *reloc_type == BFD_RELOC_32 + || *reloc_type == BFD_RELOC_MIPS_JMP + || *reloc_type == BFD_RELOC_HI16_S + || *reloc_type == BFD_RELOC_LO16 + || *reloc_type == BFD_RELOC_GPREL16 + || *reloc_type == BFD_RELOC_MIPS_LITERAL + || *reloc_type == BFD_RELOC_GPREL32 + || *reloc_type == BFD_RELOC_64 + || *reloc_type == BFD_RELOC_CTOR + || *reloc_type == BFD_RELOC_MIPS_SUB + || *reloc_type == BFD_RELOC_MIPS_HIGHEST + || *reloc_type == BFD_RELOC_MIPS_HIGHER + || *reloc_type == BFD_RELOC_MIPS_SCN_DISP + || *reloc_type == BFD_RELOC_MIPS_REL16 + || *reloc_type == BFD_RELOC_MIPS_RELGOT)) + fixp[2]->fx_no_overflow = 1; + } + } } } } if (! mips_opts.mips16) md_number_to_chars (f, ip->insn_opcode, 4); - else if (reloc_type == BFD_RELOC_MIPS16_JMP) + else if (*reloc_type == BFD_RELOC_MIPS16_JMP) { md_number_to_chars (f, ip->insn_opcode >> 16, 2); md_number_to_chars (f + 2, ip->insn_opcode & 0xffff, 2); @@ -2235,7 +2353,7 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) /* If the previous instruction had a fixup in mips16 mode, we can not swap. This normally means that the previous instruction was a 4 byte branch anyhow. */ - || (mips_opts.mips16 && prev_insn_fixp) + || (mips_opts.mips16 && prev_insn_fixp[0]) /* If the previous instruction is a sync, sync.l, or sync.p, we can not swap. */ || (prev_pinfo & INSN_SYNC)) @@ -2261,15 +2379,35 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) memcpy (temp, prev_f, 4); memcpy (prev_f, f, 4); memcpy (f, temp, 4); - if (prev_insn_fixp) + if (prev_insn_fixp[0]) + { + prev_insn_fixp[0]->fx_frag = frag_now; + prev_insn_fixp[0]->fx_where = f - frag_now->fr_literal; + } + if (prev_insn_fixp[1]) + { + prev_insn_fixp[1]->fx_frag = frag_now; + prev_insn_fixp[1]->fx_where = f - frag_now->fr_literal; + } + if (prev_insn_fixp[2]) { - prev_insn_fixp->fx_frag = frag_now; - prev_insn_fixp->fx_where = f - frag_now->fr_literal; + prev_insn_fixp[2]->fx_frag = frag_now; + prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal; } - if (fixp) + if (fixp[0]) { - fixp->fx_frag = prev_insn_frag; - fixp->fx_where = prev_insn_where; + fixp[0]->fx_frag = prev_insn_frag; + fixp[0]->fx_where = prev_insn_where; + } + if (fixp[1]) + { + fixp[1]->fx_frag = prev_insn_frag; + fixp[1]->fx_where = prev_insn_where; + } + if (fixp[2]) + { + fixp[2]->fx_frag = prev_insn_frag; + fixp[2]->fx_where = prev_insn_where; } } else @@ -2277,13 +2415,15 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) char *prev_f; char temp[2]; - assert (prev_insn_fixp == NULL); + assert (prev_insn_fixp[0] == NULL); + assert (prev_insn_fixp[1] == NULL); + assert (prev_insn_fixp[2] == NULL); prev_f = prev_insn_frag->fr_literal + prev_insn_where; memcpy (temp, prev_f, 2); memcpy (prev_f, f, 2); - if (reloc_type != BFD_RELOC_MIPS16_JMP) + if (*reloc_type != BFD_RELOC_MIPS16_JMP) { - assert (reloc_type == BFD_RELOC_UNUSED); + assert (*reloc_type == BFD_RELOC_UNUSED); memcpy (f, temp, 2); } else @@ -2291,10 +2431,20 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) memcpy (f, f + 2, 2); memcpy (f + 2, temp, 2); } - if (fixp) + if (fixp[0]) + { + fixp[0]->fx_frag = prev_insn_frag; + fixp[0]->fx_where = prev_insn_where; + } + if (fixp[1]) + { + fixp[1]->fx_frag = prev_insn_frag; + fixp[1]->fx_where = prev_insn_where; + } + if (fixp[2]) { - fixp->fx_frag = prev_insn_frag; - fixp->fx_where = prev_insn_where; + fixp[2]->fx_frag = prev_insn_frag; + fixp[2]->fx_where = prev_insn_where; } } @@ -2312,8 +2462,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) prev_insn.insn_mo = &dummy_opcode; } - prev_insn_fixp = NULL; - prev_insn_reloc_type = BFD_RELOC_UNUSED; + prev_insn_fixp[0] = NULL; + prev_insn_fixp[1] = NULL; + prev_insn_fixp[2] = NULL; + prev_insn_reloc_type[0] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[1] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[2] = BFD_RELOC_UNUSED; prev_insn_extended = 0; } else if (pinfo & INSN_COND_BRANCH_LIKELY) @@ -2326,8 +2480,12 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) /* Update the previous insn information. */ prev_prev_insn = *ip; prev_insn.insn_mo = &dummy_opcode; - prev_insn_fixp = NULL; - prev_insn_reloc_type = BFD_RELOC_UNUSED; + prev_insn_fixp[0] = NULL; + prev_insn_fixp[1] = NULL; + prev_insn_fixp[2] = NULL; + prev_insn_reloc_type[0] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[1] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[2] = BFD_RELOC_UNUSED; prev_insn_extended = 0; } else @@ -2344,11 +2502,15 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) is not in a delay slot. */ prev_insn_is_delay_slot = 0; - prev_insn_fixp = fixp; - prev_insn_reloc_type = reloc_type; + prev_insn_fixp[0] = fixp[0]; + prev_insn_fixp[1] = fixp[1]; + prev_insn_fixp[2] = fixp[2]; + prev_insn_reloc_type[0] = reloc_type[0]; + prev_insn_reloc_type[1] = reloc_type[1]; + prev_insn_reloc_type[2] = reloc_type[2]; if (mips_opts.mips16) prev_insn_extended = (ip->use_extend - || reloc_type > BFD_RELOC_UNUSED); + || *reloc_type > BFD_RELOC_UNUSED); } prev_prev_insn_unreordered = prev_insn_unreordered; @@ -2364,7 +2526,9 @@ append_insn (place, ip, address_expr, reloc_type, unmatched_hi) PC relative relocs. */ prev_prev_insn = prev_insn; prev_insn = *ip; - prev_insn_reloc_type = reloc_type; + prev_insn_reloc_type[0] = reloc_type[0]; + prev_insn_reloc_type[1] = reloc_type[1]; + prev_insn_reloc_type[2] = reloc_type[2]; prev_prev_insn_unreordered = prev_insn_unreordered; prev_insn_unreordered = 1; } @@ -2404,7 +2568,9 @@ mips_no_prev_insn (preserve) prev_insn_is_delay_slot = 0; prev_insn_unreordered = 0; prev_insn_extended = 0; - prev_insn_reloc_type = BFD_RELOC_UNUSED; + prev_insn_reloc_type[0] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[1] = BFD_RELOC_UNUSED; + prev_insn_reloc_type[2] = BFD_RELOC_UNUSED; prev_prev_insn_unreordered = 0; mips_clear_insn_labels (); } @@ -2544,7 +2710,7 @@ macro_build (place, counter, ep, name, fmt, va_alist) #endif { struct mips_cl_insn insn; - bfd_reloc_code_real_type r; + bfd_reloc_code_real_type r[3]; va_list args; #ifdef USE_STDARG @@ -2571,7 +2737,9 @@ macro_build (place, counter, ep, name, fmt, va_alist) return; } - r = BFD_RELOC_UNUSED; + r[0] = BFD_RELOC_UNUSED; + r[1] = BFD_RELOC_UNUSED; + r[2] = BFD_RELOC_UNUSED; insn.insn_mo = (struct mips_opcode *) hash_find (op_hash, name); assert (insn.insn_mo); assert (strcmp (name, insn.insn_mo->name) == 0); @@ -2670,35 +2838,33 @@ macro_build (place, counter, ep, name, fmt, va_alist) case 'i': case 'j': case 'o': - r = (bfd_reloc_code_real_type) va_arg (args, int); - assert (r == BFD_RELOC_MIPS_GPREL - || r == BFD_RELOC_MIPS_LITERAL - || r == BFD_RELOC_LO16 - || r == BFD_RELOC_MIPS_GOT16 - || r == BFD_RELOC_MIPS_CALL16 - || r == BFD_RELOC_MIPS_GOT_LO16 - || r == BFD_RELOC_MIPS_CALL_LO16 + *r = (bfd_reloc_code_real_type) va_arg (args, int); + assert (*r == BFD_RELOC_MIPS_GPREL + || *r == BFD_RELOC_MIPS_LITERAL + || *r == BFD_RELOC_MIPS_HIGHER + || *r == BFD_RELOC_HI16_S + || *r == BFD_RELOC_LO16 + || *r == BFD_RELOC_MIPS_GOT16 + || *r == BFD_RELOC_MIPS_CALL16 + || *r == BFD_RELOC_MIPS_GOT_LO16 + || *r == BFD_RELOC_MIPS_CALL_LO16 || (ep->X_op == O_subtract - && r == BFD_RELOC_PCREL_LO16)); + && *r == BFD_RELOC_PCREL_LO16)); continue; case 'u': - r = (bfd_reloc_code_real_type) va_arg (args, int); + *r = (bfd_reloc_code_real_type) va_arg (args, int); assert (ep != NULL && (ep->X_op == O_constant || (ep->X_op == O_symbol - && (r == BFD_RELOC_HI16_S - || r == BFD_RELOC_HI16 - || r == BFD_RELOC_MIPS_GOT_HI16 - || r == BFD_RELOC_MIPS_CALL_HI16)) + && (*r == BFD_RELOC_MIPS_HIGHEST + || *r == BFD_RELOC_HI16_S + || *r == BFD_RELOC_HI16 + || *r == BFD_RELOC_GPREL16 + || *r == BFD_RELOC_MIPS_GOT_HI16 + || *r == BFD_RELOC_MIPS_CALL_HI16)) || (ep->X_op == O_subtract - && r == BFD_RELOC_PCREL_HI16_S))); - if (ep->X_op == O_constant) - { - insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff; - ep = NULL; - r = BFD_RELOC_UNUSED; - } + && *r == BFD_RELOC_PCREL_HI16_S))); continue; case 'p': @@ -2717,14 +2883,14 @@ macro_build (place, counter, ep, name, fmt, va_alist) } else if (mips_pic == EMBEDDED_PIC) - r = BFD_RELOC_16_PCREL_S2; + *r = BFD_RELOC_16_PCREL_S2; else - r = BFD_RELOC_16_PCREL; + *r = BFD_RELOC_16_PCREL; continue; case 'a': assert (ep != NULL); - r = BFD_RELOC_MIPS_JMP; + *r = BFD_RELOC_MIPS_JMP; continue; case 'C': @@ -2737,7 +2903,7 @@ macro_build (place, counter, ep, name, fmt, va_alist) break; } va_end (args); - assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL); + assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL); append_insn (place, &insn, ep, r, false); } @@ -2752,9 +2918,9 @@ mips16_macro_build (place, counter, ep, name, fmt, args) va_list args; { struct mips_cl_insn insn; - bfd_reloc_code_real_type r; + bfd_reloc_code_real_type r[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; - r = BFD_RELOC_UNUSED; insn.insn_mo = (struct mips_opcode *) hash_find (mips16_op_hash, name); assert (insn.insn_mo); assert (strcmp (name, insn.insn_mo->name) == 0); @@ -2843,14 +3009,14 @@ mips16_macro_build (place, counter, ep, name, fmt, args) assert (ep != NULL); if (ep->X_op != O_constant) - r = BFD_RELOC_UNUSED + c; + *r = BFD_RELOC_UNUSED + c; else { mips16_immed ((char *) NULL, 0, c, ep->X_add_number, false, false, false, &insn.insn_opcode, &insn.use_extend, &insn.extend); ep = NULL; - r = BFD_RELOC_UNUSED; + *r = BFD_RELOC_UNUSED; } } continue; @@ -2863,7 +3029,7 @@ mips16_macro_build (place, counter, ep, name, fmt, args) break; } - assert (r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL); + assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL); append_insn (place, &insn, ep, r, false); } @@ -2880,7 +3046,8 @@ macro_build_lui (place, counter, ep, regnum) { expressionS high_expr; struct mips_cl_insn insn; - bfd_reloc_code_real_type r; + bfd_reloc_code_real_type r[3] + = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; CONST char *name = "lui"; CONST char *fmt = "t,u"; @@ -2899,15 +3066,15 @@ macro_build_lui (place, counter, ep, regnum) /* we can compute the instruction now without a relocation entry */ high_expr.X_add_number = ((high_expr.X_add_number + 0x8000) >> 16) & 0xffff; - r = BFD_RELOC_UNUSED; + *r = BFD_RELOC_UNUSED; } - else + else if (! HAVE_NEWABI) { assert (ep->X_op == O_symbol); /* _gp_disp is a special case, used from s_cpload. */ assert (mips_pic == NO_PIC || strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0); - r = BFD_RELOC_HI16_S; + *r = BFD_RELOC_HI16_S; } /* @@ -2927,7 +3094,7 @@ macro_build_lui (place, counter, ep, regnum) assert (strcmp (fmt, insn.insn_mo->args) == 0); insn.insn_opcode = insn.insn_mo->match | (regnum << OP_SH_RT); - if (r == BFD_RELOC_UNUSED) + if (*r == BFD_RELOC_UNUSED) { insn.insn_opcode |= high_expr.X_add_number; append_insn (place, &insn, NULL, r, false); @@ -7492,7 +7659,7 @@ mips_ip (str, ip) case 'A': my_getExpression (&offset_expr, s); - imm_reloc = BFD_RELOC_32; + *imm_reloc = BFD_RELOC_32; s = expr_end; continue; @@ -7704,7 +7871,7 @@ mips_ip (str, ip) case 'i': /* 16 bit unsigned immediate */ case 'j': /* 16 bit signed immediate */ - imm_reloc = BFD_RELOC_LO16; + *imm_reloc = BFD_RELOC_LO16; c = my_getSmallExpression (&imm_expr, s); if (c != S_EX_NONE) { @@ -7714,16 +7881,16 @@ mips_ip (str, ip) imm_expr.X_add_number = (imm_expr.X_add_number >> 16) & 0xffff; else if (c == S_EX_HIGHEST) - imm_reloc = BFD_RELOC_MIPS_HIGHEST; + *imm_reloc = BFD_RELOC_MIPS_HIGHEST; else if (c == S_EX_HIGHER) - imm_reloc = BFD_RELOC_MIPS_HIGHER; + *imm_reloc = BFD_RELOC_MIPS_HIGHER; else if (c == S_EX_HI) { - imm_reloc = BFD_RELOC_HI16_S; + *imm_reloc = BFD_RELOC_HI16_S; imm_unmatched_hi = true; } else - imm_reloc = BFD_RELOC_HI16; + *imm_reloc = BFD_RELOC_HI16; } else if (imm_expr.X_op == O_constant) imm_expr.X_add_number &= 0xffff; @@ -7814,22 +7981,22 @@ mips_ip (str, ip) offset_expr.X_add_number = (offset_expr.X_add_number >> 16) & 0xffff; } - offset_reloc = BFD_RELOC_LO16; + *offset_reloc = BFD_RELOC_LO16; s = expr_end; continue; case 'p': /* pc relative offset */ if (mips_pic == EMBEDDED_PIC) - offset_reloc = BFD_RELOC_16_PCREL_S2; + *offset_reloc = BFD_RELOC_16_PCREL_S2; else - offset_reloc = BFD_RELOC_16_PCREL; + *offset_reloc = BFD_RELOC_16_PCREL; my_getExpression (&offset_expr, s); s = expr_end; continue; case 'u': /* upper 16 bits */ c = my_getSmallExpression (&imm_expr, s); - imm_reloc = BFD_RELOC_LO16; + *imm_reloc = BFD_RELOC_LO16; if (c != S_EX_NONE) { if (c != S_EX_LO) @@ -7838,14 +8005,14 @@ mips_ip (str, ip) imm_expr.X_add_number = (imm_expr.X_add_number >> 16) & 0xffff; else if (c == S_EX_HIGHEST) - imm_reloc = BFD_RELOC_MIPS_HIGHEST; + *imm_reloc = BFD_RELOC_MIPS_HIGHEST; else if (c == S_EX_HI) { - imm_reloc = BFD_RELOC_HI16_S; + *imm_reloc = BFD_RELOC_HI16_S; imm_unmatched_hi = true; } else - imm_reloc = BFD_RELOC_HI16; + *imm_reloc = BFD_RELOC_HI16; } else if (imm_expr.X_op == O_constant) imm_expr.X_add_number &= 0xffff; @@ -7860,7 +8027,7 @@ mips_ip (str, ip) case 'a': /* 26 bit address */ my_getExpression (&offset_expr, s); s = expr_end; - offset_reloc = BFD_RELOC_MIPS_JMP; + *offset_reloc = BFD_RELOC_MIPS_JMP; continue; case 'N': /* 3 bit branch condition code */ @@ -8003,9 +8170,13 @@ mips16_ip (str, ip) ip->insn_opcode = insn->match; ip->use_extend = false; imm_expr.X_op = O_absent; - imm_reloc = BFD_RELOC_UNUSED; + imm_reloc[0] = BFD_RELOC_UNUSED; + imm_reloc[1] = BFD_RELOC_UNUSED; + imm_reloc[2] = BFD_RELOC_UNUSED; offset_expr.X_op = O_absent; - offset_reloc = BFD_RELOC_UNUSED; + offset_reloc[0] = BFD_RELOC_UNUSED; + offset_reloc[1] = BFD_RELOC_UNUSED; + offset_reloc[2] = BFD_RELOC_UNUSED; for (args = insn->args; 1; ++args) { int c; @@ -8025,16 +8196,16 @@ mips16_ip (str, ip) { /* Stuff the immediate value in now, if we can. */ if (imm_expr.X_op == O_constant - && imm_reloc > BFD_RELOC_UNUSED + && *imm_reloc > BFD_RELOC_UNUSED && insn->pinfo != INSN_MACRO) { mips16_immed ((char *) NULL, 0, - imm_reloc - BFD_RELOC_UNUSED, + *imm_reloc - BFD_RELOC_UNUSED, imm_expr.X_add_number, true, mips16_small, mips16_ext, &ip->insn_opcode, &ip->use_extend, &ip->extend); imm_expr.X_op = O_absent; - imm_reloc = BFD_RELOC_UNUSED; + *imm_reloc = BFD_RELOC_UNUSED; } return; @@ -8259,7 +8430,7 @@ mips16_ip (str, ip) if (imm_expr.X_op == O_symbol) { mips16_ext = true; - imm_reloc = BFD_RELOC_MIPS16_GPREL; + *imm_reloc = BFD_RELOC_MIPS16_GPREL; s = expr_end; ip->use_extend = true; ip->extend = 0; @@ -8286,7 +8457,7 @@ mips16_ip (str, ip) explicit extensions correctly. */ imm_expr.X_op = O_constant; imm_expr.X_add_number = 0; - imm_reloc = (int) BFD_RELOC_UNUSED + c; + *imm_reloc = (int) BFD_RELOC_UNUSED + c; continue; } @@ -8294,7 +8465,7 @@ mips16_ip (str, ip) } /* We need to relax this instruction. */ - imm_reloc = (int) BFD_RELOC_UNUSED + c; + *imm_reloc = (int) BFD_RELOC_UNUSED + c; s = expr_end; continue; @@ -8312,7 +8483,7 @@ mips16_ip (str, ip) break; /* We need to relax this instruction. */ - offset_reloc = (int) BFD_RELOC_UNUSED + c; + *offset_reloc = (int) BFD_RELOC_UNUSED + c; s = expr_end; continue; @@ -8334,7 +8505,7 @@ mips16_ip (str, ip) case 'a': /* 26 bit address */ my_getExpression (&offset_expr, s); s = expr_end; - offset_reloc = BFD_RELOC_MIPS16_JMP; + *offset_reloc = BFD_RELOC_MIPS16_JMP; ip->insn_opcode <<= 16; continue; @@ -9590,7 +9761,10 @@ mips_frob_file () /* When generating embedded PIC code we must keep all PC relative relocations, in case the linker has to relax a call. We also need - to keep relocations for switch table entries. */ + to keep relocations for switch table entries. + + We may have combined relocations without symbols in the N32/N64 ABI. + We have to prevent gas from dropping them. */ int mips_force_relocation (fixp) @@ -9600,6 +9774,13 @@ mips_force_relocation (fixp) || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 1; + if (HAVE_NEWABI + && S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr + && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB + || fixp->fx_r_type == BFD_RELOC_HI16_S + || fixp->fx_r_type == BFD_RELOC_LO16)) + return 1; + return (mips_pic == EMBEDDED_PIC && (fixp->fx_pcrel || SWITCH_TABLE (fixp) @@ -9620,7 +9801,21 @@ md_apply_fix (fixP, valueP) assert (fixP->fx_size == 4 || fixP->fx_r_type == BFD_RELOC_16 + || fixP->fx_r_type == BFD_RELOC_32 + || fixP->fx_r_type == BFD_RELOC_MIPS_JMP + || fixP->fx_r_type == BFD_RELOC_HI16_S + || fixP->fx_r_type == BFD_RELOC_LO16 + || fixP->fx_r_type == BFD_RELOC_GPREL16 + || fixP->fx_r_type == BFD_RELOC_MIPS_LITERAL + || fixP->fx_r_type == BFD_RELOC_GPREL32 || fixP->fx_r_type == BFD_RELOC_64 + || fixP->fx_r_type == BFD_RELOC_CTOR + || fixP->fx_r_type == BFD_RELOC_MIPS_SUB + || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHEST + || fixP->fx_r_type == BFD_RELOC_MIPS_HIGHER + || fixP->fx_r_type == BFD_RELOC_MIPS_SCN_DISP + || fixP->fx_r_type == BFD_RELOC_MIPS_REL16 + || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY);