Index: bfd/elfxx-mips.c =================================================================== --- bfd/elfxx-mips.c 2011-07-24 15:06:40.000000000 +0100 +++ bfd/elfxx-mips.c 2011-07-24 15:07:48.000000000 +0100 @@ -5162,7 +5162,7 @@ mips_elf_calculate_relocation (bfd *abfd target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other); /* If the output section is the PLT section, then the target is not microMIPS. */ - target_is_micromips_code_p = ((htab->splt != sec) + target_is_micromips_code_p = (htab->splt != sec && ELF_ST_IS_MICROMIPS (h->root.other)); } @@ -11910,18 +11910,9 @@ mips_elf_relax_delete_bytes (bfd *abfd, symtab_hdr = &elf_tdata (abfd)->symtab_hdr; isym = (Elf_Internal_Sym *) symtab_hdr->contents; for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - { - bfd_vma value; - - if (isym->st_shndx != sec_shndx) - continue; - - value = isym->st_value; - if (ELF_ST_IS_MICROMIPS (isym->st_other)) - value &= MINUS_TWO; - if (value > addr) - isym->st_value -= count; - } + if (isym->st_shndx == sec_shndx + && isym->st_value > addr) + isym->st_value -= count; /* Now adjust the global symbols defined in this section. */ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) @@ -11932,18 +11923,19 @@ mips_elf_relax_delete_bytes (bfd *abfd, for (; sym_hashes < end_hashes; sym_hashes++) { struct elf_link_hash_entry *sym_hash = *sym_hashes; - bfd_vma value; - - if ((sym_hash->root.type != bfd_link_hash_defined - && sym_hash->root.type != bfd_link_hash_defweak) - || sym_hash->root.u.def.section != sec) - continue; - value = sym_hash->root.u.def.value; - if (ELF_ST_IS_MICROMIPS (sym_hash->other)) - value &= MINUS_TWO; - if (value > addr) - sym_hash->root.u.def.value -= count; + if ((sym_hash->root.type == bfd_link_hash_defined + || sym_hash->root.type == bfd_link_hash_defweak) + && sym_hash->root.u.def.section == sec) + { + bfd_vma value; + + value = sym_hash->root.u.def.value; + if (ELF_ST_IS_MICROMIPS (sym_hash->other)) + value &= MINUS_TWO; + if (value > addr) + sym_hash->root.u.def.value -= count; + } } return TRUE; @@ -12279,6 +12271,27 @@ #define IS_BITSIZE(val, N) \ (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1))) \ - (1ULL << ((N) - 1))) == (val)) +/* See if relocations [INTERNAL_RELOCS, IRELEND) confirm that there + is a 4-byte branch at offset OFFSET. */ + +static bfd_boolean +check_4byte_branch (Elf_Internal_Rela *internal_relocs, + Elf_Internal_Rela *irelend, bfd_vma offset) +{ + Elf_Internal_Rela *irel; + unsigned long r_type; + + for (irel = internal_relocs; irel < irelend; irel++) + if (irel->r_offset == offset) + { + r_type = ELF32_R_TYPE (irel->r_info); + if (r_type == R_MICROMIPS_26_S1 + || r_type == R_MICROMIPS_PC16_S1 + || r_type == R_MICROMIPS_JALR) + return TRUE; + } + return FALSE; +} bfd_boolean _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, @@ -12439,12 +12452,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, out the offset). */ if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn)) { - Elf_Internal_Rela *ibrrel; - bfd_boolean brc = FALSE; - unsigned int br_r_type; unsigned long nextopc; unsigned long reg; - int bdsize = -1; bfd_vma offset; /* Give up if the previous reloc was a HI16 against this symbol @@ -12466,58 +12475,20 @@ _bfd_mips_elf_relax_section (bfd *abfd, && ELF32_R_SYM (irel[2].r_info) == r_symndx) continue; - /* See if there is a jump or a branch reloc preceding the - LUI instruction immediately. */ - for (ibrrel = internal_relocs; ibrrel < irelend; ibrrel++) - { - offset = irel->r_offset - ibrrel->r_offset; - if (offset != 2 && offset != 4) - continue; - - br_r_type = ELF32_R_TYPE (ibrrel->r_info); - if (offset == 2 - && (br_r_type == R_MICROMIPS_PC7_S1 - || br_r_type == R_MICROMIPS_PC10_S1 - || br_r_type == R_MICROMIPS_JALR)) - break; - if (offset == 4 - && (br_r_type == R_MICROMIPS_26_S1 - || br_r_type == R_MICROMIPS_PC16_S1 - || br_r_type == R_MICROMIPS_JALR)) - { - bfd_byte *ptr = contents + ibrrel->r_offset; - unsigned long bropc; - - bropc = bfd_get_16 (abfd, ptr); - bropc <<= 16; - bropc |= bfd_get_16 (abfd, ptr + 2); - /* Compact branches are OK. */ - if (find_match (opcode, bzc_insns_32) >= 0) - brc = TRUE; - break; - } - } - /* A delay slot was found, give up, sigh... */ - if (!brc && ibrrel < irelend) + /* 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 + && !(irel->r_offset >= 4 + /* If the instruction is actually a 4-byte branch, + the value of check_br16_dslot doesn't matter. + We should use check_br32_dslot to check whether + the branch has a delay slot. */ + && check_4byte_branch (internal_relocs, irelend, + irel->r_offset - 4))) + continue; + if (irel->r_offset >= 4 + && check_br32_dslot (abfd, contents + irel->r_offset - 4) > 0) continue; - - /* Otherwise see if the LUI instruction *might* be in a - branch delay slot. */ - if (!brc) - { - bfd_byte *ptr = contents + irel->r_offset; - - if (irel->r_offset >= 2) - bdsize = check_br16_dslot (abfd, ptr - 2); - /* A branch possibly found, give up, sigh... */ - if (bdsize > 0) - continue; - if (irel->r_offset >= 4) - bdsize = check_br32_dslot (abfd, ptr - 4); - /* A branch possibly found, give up, sigh... */ - if (bdsize > 0) - continue; - } reg = OP32_SREG (opcode); @@ -12545,7 +12516,8 @@ _bfd_mips_elf_relax_section (bfd *abfd, nextopc = bfd_get_16 (abfd, contents + irel[1].r_offset ) << 16; nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2); - /* Give up unless the same register used with both relocations. */ + /* Give up unless the same register is used with both + relocations. */ if (OP32_SREG (nextopc) != reg) continue; Index: gas/config/tc-mips.c =================================================================== --- gas/config/tc-mips.c 2011-07-24 15:07:45.000000000 +0100 +++ gas/config/tc-mips.c 2011-07-24 15:07:48.000000000 +0100 @@ -2150,7 +2150,7 @@ reglist_lookup (char **s, unsigned int t unsigned int regmask; unsigned int regno; char *s_reset = *s; - char *s_comma = *s; + char *s_end_of_list = *s; while (reg_lookup (s, types, ®no)) { @@ -2175,14 +2175,14 @@ reglist_lookup (char **s, unsigned int t regmask ^= (1 << regno) - 1; reglist |= regmask; - s_comma = *s; + s_end_of_list = *s; if (**s != ',') break; (*s)++; } if (ok) - *s = s_comma; + *s = s_end_of_list; else *s = s_reset; if (reglistp) @@ -2663,24 +2663,41 @@ micromips_reloc_p (bfd_reloc_code_real_t 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 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. */ @@ -3761,7 +3778,7 @@ can_swap_branch_p (struct mips_cl_insn * return FALSE; /* If the previous instruction has an incorrect size for a fixed - branch delay slot in the microMIPS mode, we cannot swap. */ + branch delay slot in microMIPS mode, we cannot swap. */ if (mips_opts.micromips) { pinfo2 = ip->insn_mo->pinfo; @@ -4030,11 +4047,9 @@ append_insn (struct mips_cl_insn *ip, ex case BFD_RELOC_MIPS_JMP: { - bfd_reloc_code_real_type reloc; int shift; - reloc = micromips_map_reloc (*reloc_type); - shift = reloc == BFD_RELOC_MICROMIPS_JMP ? 1 : 2; + shift = mips_opts.micromips ? 1 : 2; if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0) as_bad (_("jump to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); @@ -4057,11 +4072,9 @@ append_insn (struct mips_cl_insn *ip, ex case BFD_RELOC_16_PCREL_S2: { - bfd_reloc_code_real_type reloc; int shift; - reloc = micromips_map_reloc (*reloc_type); - shift = reloc == BFD_RELOC_MICROMIPS_16_PCREL_S1 ? 1 : 2; + shift = mips_opts.micromips ? 1 : 2; if ((address_expr->X_add_number & ((1 << shift) - 1)) != 0) as_bad (_("branch to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); @@ -4313,32 +4326,32 @@ append_insn (struct mips_cl_insn *ip, ex if (!ip->complete_p && *reloc_type < BFD_RELOC_UNUSED) { - bfd_reloc_code_real_type reloc; + bfd_reloc_code_real_type final_type[3]; reloc_howto_type *howto; int i; + /* Perform any necessary conversion to microMIPS relocations + and find out how many relocations there actually are. */ + for (i = 0; i < 3 && reloc_type[i] != BFD_RELOC_UNUSED; i++) + final_type[i] = micromips_map_reloc (reloc_type[i]); + /* In a compound relocation, it is the final (outermost) operator that determines the relocated field. */ - for (i = 1; i < 3; i++) - if (reloc_type[i] == BFD_RELOC_UNUSED) - break; - - reloc = micromips_map_reloc (reloc_type[i - 1]); - howto = bfd_reloc_type_lookup (stdoutput, reloc); + howto = bfd_reloc_type_lookup (stdoutput, final_type[i - 1]); if (howto == NULL) { /* To reproduce this failure try assembling gas/testsuites/ gas/mips/mips16-intermix.s with a mips-ecoff targeted assembler. */ - as_bad (_("Unsupported MIPS relocation number %d"), reloc); + as_bad (_("Unsupported MIPS relocation number %d"), + final_type[i - 1]); howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_16); } ip->fixp[0] = fix_new_exp (ip->frag, ip->where, bfd_get_reloc_size (howto), address_expr, - howto->pc_relative, - micromips_map_reloc (reloc_type[0])); + howto->pc_relative, final_type[0]); /* Tag symbols that have a R_MIPS16_26 relocation against them. */ if (reloc_type[0] == BFD_RELOC_MIPS16_JMP @@ -4352,7 +4365,6 @@ append_insn (struct mips_cl_insn *ip, ex && (reloc_type[0] == BFD_RELOC_16 || reloc_type[0] == BFD_RELOC_32 || reloc_type[0] == BFD_RELOC_MIPS_JMP - || reloc_type[0] == BFD_RELOC_MICROMIPS_JMP || reloc_type[0] == BFD_RELOC_GPREL16 || reloc_type[0] == BFD_RELOC_MIPS_LITERAL || reloc_type[0] == BFD_RELOC_GPREL32 @@ -4401,8 +4413,8 @@ append_insn (struct mips_cl_insn *ip, ex if (reloc_type[i] != BFD_RELOC_UNUSED) { ip->fixp[i] = fix_new (ip->frag, ip->where, - ip->fixp[0]->fx_size, NULL, 0, FALSE, - micromips_map_reloc (reloc_type[i])); + ip->fixp[0]->fx_size, NULL, 0, + FALSE, final_type[i]); /* Use fx_tcbit to mark compound relocs. */ ip->fixp[0]->fx_tcbit = 1; @@ -17323,7 +17335,7 @@ md_estimate_size_before_relax (fragS *fr length = relaxed_micromips_16bit_branch_length (fragp, segtype, FALSE); if (length == 4 && RELAX_MICROMIPS_RELAX32 (fragp->fr_subtype)) length = relaxed_micromips_32bit_branch_length (fragp, segtype, FALSE); - fragp->fr_var= length; + fragp->fr_var = length; return length; } @@ -17385,9 +17397,7 @@ mips_fix_adjustable (fixS *fixp) 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 - || fixp->fx_r_type == BFD_RELOC_MIPS_JALR - || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JALR)) + && (fixp->fx_pcrel || jalr_reloc_p (fixp->fx_r_type))) return 0; #ifdef OBJ_ELF @@ -17439,8 +17449,7 @@ mips_fix_adjustable (fixS *fixp) || *symbol_get_tc (fixp->fx_addsy) || (HAVE_IN_PLACE_ADDENDS && ELF_ST_IS_MICROMIPS (S_GET_OTHER (fixp->fx_addsy)) - && (fixp->fx_r_type == BFD_RELOC_MIPS_JMP - || fixp->fx_r_type == BFD_RELOC_MICROMIPS_JMP)))) + && jmp_reloc_p (fixp->fx_r_type)))) return 0; #endif @@ -17781,12 +17790,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU 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); - - /* Default to the long-delay-slot versions. */ - unsigned long jal = 0xf4000000; /* jal */ - unsigned long jalr = 0x45c0; /* jalr */ - - unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */ + unsigned long jal, jalr, jr; unsigned long insn; expressionS exp; @@ -17798,7 +17802,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU fragp->fr_fix += fragp->fr_var; - /* Handle 16-bit branches that fit or forced to fit. */ + /* Handle 16-bit branches that fit or are forced to fit. */ if (type != 0 && !RELAX_MICROMIPS_TOOFAR16 (fragp->fr_subtype)) { /* We generate a fixup instead of applying it right now, @@ -17906,6 +17910,12 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNU jal = 0x74000000; /* jals */ jalr = 0x45e0; /* jalrs */ } + else + { + jal = 0xf4000000; /* jal */ + jalr = 0x45c0; /* jalr */ + } + jr = compact ? 0x45a0 : 0x4580; /* jr/c */ if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype)) { Index: include/opcode/mips.h =================================================================== --- include/opcode/mips.h 2011-07-24 15:06:40.000000000 +0100 +++ include/opcode/mips.h 2011-07-24 15:07:48.000000000 +0100 @@ -1330,7 +1330,7 @@ #define MIPS16_INSN_COND_BRANCH 0x0 extern const int bfd_mips16_num_opcodes; /* These are the bitmasks and shift counts used for the different - fields in the instruction formats. Other than OP, no masks are + fields in the instruction formats. Other than MAJOR, no masks are provided for the fixed portions of an instruction, since they are not needed. */