symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
isym = (Elf_Internal_Sym *) symtab_hdr->contents;
for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
- if (isym->st_shndx == sec_shndx
- && isym->st_value > addr)
+ if (isym->st_shndx == sec_shndx && isym->st_value > addr)
isym->st_value -= count;
/* Now adjust the global symbols defined in this section. */
|| sym_hash->root.type == bfd_link_hash_defweak)
&& sym_hash->root.u.def.section == sec)
{
- bfd_vma value;
+ bfd_vma value = sym_hash->root.u.def.value;
- value = sym_hash->root.u.def.value;
if (ELF_ST_IS_MICROMIPS (sym_hash->other))
value &= MINUS_TWO;
if (value > addr)
unsigned long opcode;
bfd_vma symval;
bfd_vma pcrval;
+ bfd_byte *ptr;
int fndopc;
/* The number of bytes to delete for relaxation and from where
this reloc. */
if (r_type != R_MICROMIPS_HI16
&& r_type != R_MICROMIPS_PC16_S1
- && r_type != R_MICROMIPS_26_S1
- && r_type != R_MICROMIPS_GPREL16)
+ && r_type != R_MICROMIPS_26_S1)
continue;
/* Get the section contents if we haven't done so already. */
else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
goto error_return;
}
+ ptr = contents + irel->r_offset;
/* Read this BFD's local symbols if we haven't done so already. */
if (isymbuf == NULL && symtab_hdr->sh_info != 0)
if (irel->r_offset + 4 > sec->size)
continue;
- opcode = bfd_get_16 (abfd, contents + irel->r_offset ) << 16;
- opcode |= bfd_get_16 (abfd, contents + irel->r_offset + 2);
+ opcode = bfd_get_16 (abfd, ptr ) << 16;
+ opcode |= bfd_get_16 (abfd, ptr + 2);
/* This is the pc-relative distance from the instruction the
relocation is applied to, to the symbol referred. */
/* See if the LUI instruction *might* be in a branch delay slot. */
if (irel->r_offset >= 2
- && check_br16_dslot (abfd, contents + irel->r_offset - 2) > 0
+ && check_br16_dslot (abfd, ptr - 2)
&& !(irel->r_offset >= 4
/* If the instruction is actually a 4-byte branch,
the value of check_br16_dslot doesn't matter.
irel->r_offset - 4)))
continue;
if (irel->r_offset >= 4
- && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0)
+ && check_br32_dslot (abfd, ptr - 4))
continue;
reg = OP32_SREG (opcode);
case 0:
break;
case 2:
- if (check_br16 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br16 (abfd, ptr + 4, reg))
break;
continue;
case 4:
- if (check_br32 (abfd, contents + irel->r_offset + 4, reg))
+ if (check_br32 (abfd, ptr + 4, reg))
break;
continue;
default:
&& irel->r_offset + 5 < sec->size
&& ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
|| (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
- && MATCH (bfd_get_16 (abfd, contents + irel->r_offset + 4),
- nop_insn_16))
+ && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
{
unsigned long reg;
| BZC32_REG_FIELD (reg)
| (opcode & 0xffff)); /* Addend value. */
- bfd_put_16 (abfd, (opcode >> 16) & 0xffff,
- contents + irel->r_offset);
- bfd_put_16 (abfd, opcode & 0xffff,
- contents + irel->r_offset + 2);
+ bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
+ bfd_put_16 (abfd, opcode & 0xffff, ptr + 2);
/* Delete the 16-bit delay slot NOP: two bytes from
irel->offset + 4. */
bfd_put_16 (abfd,
(b_insn_16.match
| (opcode & 0x3ff)), /* Addend value. */
- contents + irel->r_offset);
+ ptr);
/* Delete 2 bytes from irel->r_offset + 2. */
delcnt = 2;
(bz_insns_16[fndopc].match
| BZ16_REG_FIELD (reg)
| (opcode & 0x7f)), /* Addend value. */
- contents + irel->r_offset);
+ ptr);
/* Delete 2 bytes from irel->r_offset + 2. */
delcnt = 2;
unsigned long n32opc;
bfd_boolean relaxed = FALSE;
- n32opc = bfd_get_16 (abfd, contents + irel->r_offset + 4) << 16;
- n32opc |= bfd_get_16 (abfd, contents + irel->r_offset + 6);
+ n32opc = bfd_get_16 (abfd, ptr + 4) << 16;
+ n32opc |= bfd_get_16 (abfd, ptr + 6);
if (MATCH (n32opc, nop_insn_32))
{
/* Replace delay slot 32-bit NOP with a 16-bit NOP. */
- bfd_put_16 (abfd, nop_insn_16.match,
- contents + irel->r_offset + 4);
+ bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
relaxed = TRUE;
}
(move_insn_16.match
| MOVE16_RD_FIELD (MOVE32_RD (n32opc))
| MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
- contents + irel->r_offset + 4);
+ ptr + 4);
relaxed = TRUE;
}
/* JAL with 32-bit delay slot that is changed to a JALS
with 16-bit delay slot. */
bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
- contents + irel->r_offset);
+ ptr);
bfd_put_16 (abfd, jal_insn_32_bd16.match & 0xffff,
- contents + irel->r_offset + 2);
+ ptr + 2);
/* Delete 2 bytes from irel->r_offset + 6. */
delcnt = 2;
(strncmp (TARGET_CPU, "mips16", sizeof ("mips16") - 1) == 0 \
|| strncmp (TARGET_CANONICAL, "mips-lsi-elf", sizeof ("mips-lsi-elf") - 1) == 0)
-/* Return true if the given CPU supports microMIPS. */
+/* Return true if the given CPU supports the microMIPS ASE. */
#define CPU_HAS_MICROMIPS(cpu) 0
/* True if CPU has a dror instruction. */
As a special exception if one of s0-s7 registers is specified as
the range's lower delimiter and s8 (fp) is its upper one, then no
registers whose numbers place them between s7 and s8 (i.e. $24-$29)
- are selected; they have to be named separately if needed. */
+ are selected; they have to be listed separately if needed. */
static int
reglist_lookup (char **s, unsigned int types, unsigned int *reglistp)
unsigned int lastregno;
bfd_boolean ok = TRUE;
unsigned int regmask;
- unsigned int regno;
+ char *s_endlist = *s;
char *s_reset = *s;
- char *s_end_of_list = *s;
+ unsigned int regno;
while (reg_lookup (s, types, ®no))
{
regmask ^= (1 << regno) - 1;
reglist |= regmask;
- s_end_of_list = *s;
+ s_endlist = *s;
if (**s != ',')
break;
(*s)++;
}
if (ok)
- *s = s_end_of_list;
+ *s = s_endlist;
else
*s = s_reset;
if (reglistp)
}
}
+static inline bfd_boolean
+jmp_reloc_p (bfd_reloc_code_real_type reloc)
+{
+ return reloc == BFD_RELOC_MIPS_JMP || reloc == BFD_RELOC_MICROMIPS_JMP;
+}
+
static inline bfd_boolean
got16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_GOT16
- || reloc == BFD_RELOC_MIPS16_GOT16
+ return (reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16
|| reloc == BFD_RELOC_MICROMIPS_GOT16);
}
static inline bfd_boolean
hi16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_HI16_S
- || reloc == BFD_RELOC_MIPS16_HI16_S
+ return (reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S
|| reloc == BFD_RELOC_MICROMIPS_HI16_S);
}
static inline bfd_boolean
lo16_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_LO16
- || reloc == BFD_RELOC_MIPS16_LO16
+ return (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16
|| reloc == BFD_RELOC_MICROMIPS_LO16);
}
-static inline bfd_boolean
-jmp_reloc_p (bfd_reloc_code_real_type reloc)
-{
- return (reloc == BFD_RELOC_MIPS_JMP
- || reloc == BFD_RELOC_MICROMIPS_JMP);
-}
-
static inline bfd_boolean
jalr_reloc_p (bfd_reloc_code_real_type reloc)
{
- return (reloc == BFD_RELOC_MIPS_JALR
- || reloc == BFD_RELOC_MICROMIPS_JALR);
+ return reloc == BFD_RELOC_MIPS_JALR || reloc == BFD_RELOC_MICROMIPS_JALR;
}
/* Return true if the given relocation might need a matching %lo().
mips_relax.sequence = 0;
}
-/* Return the mask of core registers that instruction IP may
- read or write. */
+/* Return the mask of core registers that IP reads or writes. */
static unsigned int
gpr_mod_mask (const struct mips_cl_insn *ip)
{
- unsigned long pinfo, pinfo2;
+ unsigned long pinfo2;
unsigned int mask;
mask = 0;
- pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
if (mips_opts.micromips)
{
if (pinfo & MIPS16_INSN_READ_GPR_X)
mask |= 1 << MIPS16_EXTRACT_OPERAND (REGR32, *ip);
}
- else if (mips_opts.micromips)
- {
- if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
- if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo2 & INSN2_READ_GPR_31)
- mask |= 1 << RA;
- if (pinfo2 & INSN2_READ_GP)
- mask |= 1 << GP;
- }
else
{
if (pinfo2 & INSN2_READ_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (0, RD, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_READ_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (0, RT, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
if (pinfo & INSN_READ_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (0, RS, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
+ if (pinfo2 & INSN2_READ_GP)
+ mask |= 1 << GP;
+ if (pinfo2 & INSN2_READ_GPR_31)
+ mask |= 1 << RA;
if (pinfo2 & INSN2_READ_GPR_Z)
- mask |= 1 << EXTRACT_OPERAND (0, RZ, *ip);
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RZ, *ip);
}
/* Don't include register 0. */
return mask & ~1;
if (pinfo & MIPS16_INSN_WRITE_GPR_Y)
mask |= 1 << MIPS16OP_EXTRACT_REG32R (ip->insn_opcode);
}
- else if (mips_opts.micromips)
- {
- if (pinfo & INSN_WRITE_GPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, RD, *ip);
- if (pinfo & INSN_WRITE_GPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, RT, *ip);
- if (pinfo2 & INSN2_WRITE_GPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, RS, *ip);
- if (pinfo & INSN_WRITE_GPR_31)
- mask |= 1 << RA;
- }
else
{
if (pinfo & INSN_WRITE_GPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RD, *ip);
if (pinfo & INSN_WRITE_GPR_T)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RT, *ip);
+ if (pinfo2 & INSN2_WRITE_GPR_S)
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, RS, *ip);
if (pinfo & INSN_WRITE_GPR_31)
mask |= 1 << RA;
if (pinfo2 & INSN2_WRITE_GPR_Z)
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
+ if (!mips_opts.mips16)
{
if (pinfo2 & INSN2_READ_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_READ_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_READ_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- if (pinfo & INSN_READ_FPR_R)
- mask |= 1 << EXTRACT_OPERAND (1, FR, *ip);
- }
- else if (!mips_opts.mips16)
- {
+ mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (pinfo & INSN_READ_FPR_S)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FS, *ip);
if (pinfo & INSN_READ_FPR_T)
mask = 0;
pinfo = ip->insn_mo->pinfo;
pinfo2 = ip->insn_mo->pinfo2;
- if (mips_opts.micromips)
- {
- if (pinfo2 & INSN_WRITE_FPR_D)
- mask |= 1 << EXTRACT_OPERAND (1, FD, *ip);
- if (pinfo & INSN_WRITE_FPR_S)
- mask |= 1 << EXTRACT_OPERAND (1, FS, *ip);
- if (pinfo & INSN_WRITE_FPR_T)
- mask |= 1 << EXTRACT_OPERAND (1, FT, *ip);
- }
- else if (!mips_opts.mips16)
+ if (!mips_opts.mips16)
{
if (pinfo & INSN_WRITE_FPR_D)
mask |= 1 << EXTRACT_OPERAND (mips_opts.micromips, FD, *ip);
if (MF_HILO_INSN (hist[i].insn_mo->pinfo))
{
/* Extract the destination register. */
+ gas_assert (!mips_opts.micromips);
mask = gpr_write_mask (&hist[i]);
/* No nops are needed if INSN reads that register. */
return FALSE;
/* If the previous instruction is in a variant frag other than this
- branch's one, we cannot do the swap. This does not apply to the
- mips16, which uses variant frags for different purposes. */
+ branch's one, we cannot do the swap. This does not apply to
+ MIPS16/microMIPS code, which uses variant frags for different
+ purposes. */
if (!HAVE_CODE_COMPRESSION
&& history[0].frag
&& history[0].frag->fr_type == rs_machine_dependent)
/* If the previous instruction has an incorrect size for a fixed
branch delay slot in microMIPS mode, we cannot swap. */
- if (mips_opts.micromips)
- {
- pinfo2 = ip->insn_mo->pinfo;
- if ((pinfo2 & INSN2_BRANCH_DELAY_16BIT)
- && insn_length (history) != 2)
- return FALSE;
-
- if ((pinfo2 & INSN2_BRANCH_DELAY_32BIT)
- && insn_length (history) != 4)
- return FALSE;
- }
+ pinfo2 = ip->insn_mo->pinfo2;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_16BIT)
+ && insn_length (history) != 2)
+ return FALSE;
+ if (mips_opts.micromips
+ && (pinfo2 & INSN2_BRANCH_DELAY_32BIT)
+ && insn_length (history) != 4)
+ return FALSE;
+
return TRUE;
}
{
unsigned long prev_pinfo, prev_pinfo2, pinfo, pinfo2;
bfd_boolean relaxed_branch = FALSE;
- bfd_boolean relax32;
enum append_method method;
+ bfd_boolean relax32;
- if (mips_fix_loongson2f && !mips_opts.micromips)
+ if (mips_fix_loongson2f && !HAVE_CODE_COMPRESSION)
fix_loongson2f (ip);
mips_mark_labels ();
If the instruction produced is a branch that we will swap with
the preceding instruction, then we add the displacement by which
the branch will be moved backwards. This is more appropriate
- and for MIPS16/microMIPS code also prevents a debugger from placing
- a breakpoint in the middle of the branch (and corrupting code if
- software breakpoints are used). */
+ and for MIPS16/microMIPS code also prevents a debugger from
+ placing a breakpoint in the middle of the branch (and corrupting
+ code if software breakpoints are used). */
dwarf2_emit_insn ((HAVE_CODE_COMPRESSION ? -1 : 0)
+ (method == APPEND_SWAP ? insn_length (history) : 0));
#endif
if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED)
{
bfd_reloc_code_real_type final_type[3];
+ reloc_howto_type *howto0;
reloc_howto_type *howto;
int i;
/* In a compound relocation, it is the final (outermost)
operator that determines the relocated field. */
- howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+ howto = howto0 = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]);
+
if (howto == NULL)
{
/* To reproduce this failure try assembling gas/testsuites/
final_type[i - 1]);
howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16);
}
-
- howto = bfd_reloc_type_lookup (stdoutput, final_type[0]);
+
+ if (i > 1)
+ howto0 = bfd_reloc_type_lookup (stdoutput, final_type[0]);
ip->fixp[0] = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
address_expr,
- howto->pc_relative, final_type[0]);
+ howto0 && howto0->pc_relative,
+ final_type[0]);
/* Tag symbols that have a R_MIPS16_26 relocation against them. */
- if (reloc_type[0] == BFD_RELOC_MIPS16_JMP
- && ip->fixp[0]->fx_addsy)
+ if (final_type[0] == BFD_RELOC_MIPS16_JMP && ip->fixp[0]->fx_addsy)
*symbol_get_tc (ip->fixp[0]->fx_addsy) = 1;
/* These relocations can have an addend that won't fit in
bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype);
bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype);
int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype);
- unsigned long jal, jalr, jr;
-
+ bfd_boolean short_ds;
unsigned long insn;
expressionS exp;
fixS *fixp;
return;
}
- /* Handle 32-bit branches that fit or forced to fit. */
+ /* Handle 32-bit branches that fit or are forced to fit. */
if (!RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)
|| !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype))
{
as_warn_where (fragp->fr_file, fragp->fr_line,
_("Relaxed out-of-range branch into a jump"));
- /* Check the short-delay-slot bit. */
- if (al && (insn & 0x02000000) != 0)
- {
- jal = 0x74000000; /* jals */
- jalr = 0x45e0; /* jalrs */
- }
- else
- {
- jal = 0xf4000000; /* jal */
- jalr = 0x45c0; /* jalr */
- }
- jr = compact ? 0x45a0 : 0x4580; /* jr/c */
+ /* Set the short-delay-slot bit. */
+ short_ds = al && (insn & 0x02000000) != 0;
if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype))
{
if (mips_pic == NO_PIC)
{
+ unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s */
+
/* j/jal/jals <sym> R_MICROMIPS_26_S1 */
insn = al ? jal : 0xd4000000;
else
{
unsigned long at = RELAX_MICROMIPS_AT (fragp->fr_subtype);
+ unsigned long jalr = short_ds ? 0x45e0 : 0x45c0; /* jalr/s */
+ unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */
/* lw/ld $at, <sym>($gp) R_MICROMIPS_GOT16 */
insn = HAVE_64BIT_ADDRESSES ? 0xdc1c0000 : 0xfc1c0000;