+ /* bCC */
+ if (size == 2)
+ {
+ /* Handle bra specially. Basically treat it like jmp so
+ that we automatically handle 8, 16 and 32 bit offsets
+ correctly as well as jumps to an undefined address.
+
+ It is also important to not treat it like other bCC
+ instructions since the long forms of bra is different
+ from other bCC instructions. */
+ if (opcode->opcode == 0xca00)
+ type = 10;
+ else
+ type = 0;
+ }
+ /* call */
+ else if (size == 5)
+ type = 6;
+ /* calls */
+ else if (size == 4)
+ type = 8;
+ /* jmp */
+ else if (size == 3 && opcode->opcode == 0xcc0000)
+ type = 10;
+ /* bCC (uncommon cases) */
+ else
+ type = 3;
+
+ f = frag_var (rs_machine_dependent, 8, 8 - size, type,
+ fixups[0].exp.X_add_symbol,
+ fixups[0].exp.X_add_number,
+ (char *)fixups[0].opindex);
+
+ /* This is pretty hokey. We basically just care about the
+ opcode, so we have to write out the first word big endian.
+
+ The exception is "call", which has two operands that we
+ care about.
+
+ The first operand (the register list) happens to be in the
+ first instruction word, and will be in the right place if
+ we output the first word in big endian mode.
+
+ The second operand (stack size) is in the extension word,
+ and we want it to appear as the first character in the extension
+ word (as it appears in memory). Luckily, writing the extension
+ word in big endian format will do what we want. */
+ number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
+ if (size > 8)
+ {
+ number_to_chars_bigendian (f + 4, extension, 4);
+ number_to_chars_bigendian (f + 8, 0, size - 8);
+ }
+ else if (size > 4)
+ number_to_chars_bigendian (f + 4, extension, size - 4);
+ }
+ else
+ {
+ /* Allocate space for the instruction. */
+ f = frag_more (size);
+
+ /* Fill in bytes for the instruction. Note that opcode fields
+ are written big-endian, 16 & 32bit immediates are written
+ little endian. Egad. */
+ if (opcode->format == FMT_S0
+ || opcode->format == FMT_S1
+ || opcode->format == FMT_D0
+ || opcode->format == FMT_D6
+ || opcode->format == FMT_D7
+ || opcode->format == FMT_D10
+ || opcode->format == FMT_D1)
+ {
+ number_to_chars_bigendian (f, insn, size);
+ }
+ else if (opcode->format == FMT_S2
+ && opcode->opcode != 0xdf0000
+ && opcode->opcode != 0xde0000)
+ {
+ /* A format S2 instruction that is _not_ "ret" and "retf". */
+ number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
+ }
+ else if (opcode->format == FMT_S2)
+ {
+ /* This must be a ret or retf, which is written entirely in
+ big-endian format. */
+ number_to_chars_bigendian (f, insn, 3);
+ }
+ else if (opcode->format == FMT_S4
+ && opcode->opcode != 0xdc000000)
+ {
+ /* This must be a format S4 "call" instruction. What a pain. */
+ unsigned long temp = (insn >> 8) & 0xffff;
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 2);
+ number_to_chars_bigendian (f + 3, insn & 0xff, 1);
+ number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+ }
+ else if (opcode->format == FMT_S4)
+ {
+ /* This must be a format S4 "jmp" instruction. */
+ unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 4);
+ }
+ else if (opcode->format == FMT_S6)
+ {
+ unsigned long temp = ((insn & 0xffffff) << 8)
+ | ((extension >> 16) & 0xff);
+ number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+ number_to_chars_littleendian (f + 1, temp, 4);
+ number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
+ number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+ }
+ else if (opcode->format == FMT_D2
+ && opcode->opcode != 0xfaf80000
+ && opcode->opcode != 0xfaf00000
+ && opcode->opcode != 0xfaf40000)
+ {
+ /* A format D2 instruction where the 16bit immediate is
+ really a single 16bit value, not two 8bit values. */
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+ }
+ else if (opcode->format == FMT_D2)
+ {
+ /* A format D2 instruction where the 16bit immediate
+ is really two 8bit immediates. */
+ number_to_chars_bigendian (f, insn, 4);
+ }
+ else if (opcode->format == FMT_D4)
+ {
+ unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, temp, 4);
+ }
+ else if (opcode->format == FMT_D5)
+ {
+ unsigned long temp = ((insn & 0xffff) << 16)
+ | ((extension >> 8) & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+ number_to_chars_littleendian (f + 2, temp, 4);
+ number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+ }
+ else if (opcode->format == FMT_D8)
+ {
+ unsigned long temp = ((insn & 0xff) << 16) | (extension & 0xffff);
+ number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+ number_to_chars_bigendian (f + 3, (temp & 0xff), 1);
+ number_to_chars_littleendian (f + 4, temp >> 8, 2);
+ }
+ else if (opcode->format == FMT_D9)
+ {
+ unsigned long temp = ((insn & 0xff) << 24) | (extension & 0xffffff);
+ number_to_chars_bigendian (f, (insn >> 8) & 0xffffff, 3);
+ number_to_chars_littleendian (f + 3, temp, 4);
+ }
+
+ /* Create any fixups. */
+ for (i = 0; i < fc; i++)
+ {
+ const struct mn10300_operand *operand;
+
+ operand = &mn10300_operands[fixups[i].opindex];
+ if (fixups[i].reloc != BFD_RELOC_UNUSED)
+ {
+ reloc_howto_type *reloc_howto;
+ int size;
+ int offset;
+ fixS *fixP;
+
+ reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+
+ if (!reloc_howto)
+ abort();
+
+ size = bfd_get_reloc_size (reloc_howto);
+
+ if (size < 1 || size > 4)
+ abort();
+
+ offset = 4 - size;
+ fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+ size, &fixups[i].exp,
+ reloc_howto->pc_relative,
+ fixups[i].reloc);
+ }
+ else
+ {
+ int reloc, pcrel, reloc_size, offset;
+ fixS *fixP;
+
+ reloc = BFD_RELOC_NONE;
+ /* How big is the reloc? Remember SPLIT relocs are
+ implicitly 32bits. */
+ if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
+ reloc_size = 32;
+ else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+ reloc_size = 24;
+ else
+ reloc_size = operand->bits;
+
+ /* Is the reloc pc-relative? */
+ pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
+
+ /* Gross. This disgusting hack is to make sure we
+ get the right offset for the 16/32 bit reloc in
+ "call" instructions. Basically they're a pain
+ because the reloc isn't at the end of the instruction. */
+ if ((size == 5 || size == 7)
+ && (((insn >> 24) & 0xff) == 0xcd
+ || ((insn >> 24) & 0xff) == 0xdd))
+ size -= 2;
+
+ /* Similarly for certain bit instructions which don't
+ hav their 32bit reloc at the tail of the instruction. */
+ if (size == 7
+ && (((insn >> 16) & 0xffff) == 0xfe00
+ || ((insn >> 16) & 0xffff) == 0xfe01
+ || ((insn >> 16) & 0xffff) == 0xfe02))
+ size -= 1;
+
+ offset = size - reloc_size / 8;
+
+ /* Choose a proper BFD relocation type. */
+ if (pcrel)
+ {
+ if (reloc_size == 32)
+ reloc = BFD_RELOC_32_PCREL;
+ else if (reloc_size == 16)
+ reloc = BFD_RELOC_16_PCREL;
+ else if (reloc_size == 8)
+ reloc = BFD_RELOC_8_PCREL;
+ else
+ abort ();
+ }
+ else
+ {
+ if (reloc_size == 32)
+ reloc = BFD_RELOC_32;
+ else if (reloc_size == 16)
+ reloc = BFD_RELOC_16;
+ else if (reloc_size == 8)
+ reloc = BFD_RELOC_8;
+ else
+ abort ();
+ }
+
+ /* Convert the size of the reloc into what fix_new_exp wants. */
+ reloc_size = reloc_size / 8;
+ if (reloc_size == 8)
+ reloc_size = 0;
+ else if (reloc_size == 16)
+ reloc_size = 1;
+ else if (reloc_size == 32)
+ reloc_size = 2;
+
+ fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+ reloc_size, &fixups[i].exp, pcrel,
+ ((bfd_reloc_code_real_type) reloc));
+
+ if (pcrel)
+ fixP->fx_offset += offset;
+ }
+ }
+ }