daily update
[external/binutils.git] / gas / config / tc-m32c.c
index 8ee44f8..cae3302 100644 (file)
@@ -1,12 +1,12 @@
 /* tc-m32c.c -- Assembler for the Renesas M32C.
-   Copyright (C) 2005 Free Software Foundation.
+   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation.
    Contributed by RedHat.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
@@ -19,7 +19,6 @@
    the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include <stdio.h>
 #include "as.h"
 #include "subsegs.h"     
 #include "symcat.h"
@@ -29,7 +28,6 @@
 #include "elf/common.h"
 #include "elf/m32c.h"
 #include "libbfd.h"
-#include "libiberty.h"
 #include "safe-ctype.h"
 
 /* Structure to hold all of the different components
@@ -54,6 +52,9 @@ typedef struct
 }
 m32c_insn;
 
+#define rl_for(_insn) (CGEN_ATTR_CGEN_INSN_RL_TYPE_VALUE (&((_insn).insn->base->attrs)))
+#define relaxable(_insn) (CGEN_ATTR_CGEN_INSN_RELAXABLE_VALUE (&((_insn).insn->base->attrs)))
+
 const char comment_chars[]        = ";";
 const char line_comment_chars[]   = "#";
 const char line_separator_chars[] = "|";
@@ -66,11 +67,15 @@ const char * md_shortopts = M32C_SHORTOPTS;
 /* assembler options */
 #define OPTION_CPU_M16C               (OPTION_MD_BASE)
 #define OPTION_CPU_M32C        (OPTION_MD_BASE + 1)
+#define OPTION_LINKRELAX       (OPTION_MD_BASE + 2)
+#define OPTION_H_TICK_HEX      (OPTION_MD_BASE + 3)
 
 struct option md_longopts[] =
 {
   { "m16c",       no_argument,       NULL, OPTION_CPU_M16C   },
   { "m32c",       no_argument,       NULL, OPTION_CPU_M32C   },
+  { "relax",      no_argument,       NULL, OPTION_LINKRELAX   },
+  { "h-tick-hex", no_argument,       NULL, OPTION_H_TICK_HEX  },
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -83,16 +88,18 @@ size_t md_longopts_size = sizeof (md_longopts);
 static unsigned long m32c_mach = bfd_mach_m16c;
 static int cpu_mach = (1 << MACH_M16C);
 static int insn_size;
+static int m32c_relax = 0;
 
 /* Flags to set in the elf header */
 static flagword m32c_flags = DEFAULT_FLAGS;
 
-static unsigned int m32c_isa = (1 << ISA_M16C);
+static char default_isa = 1 << (7 - ISA_M16C);
+static CGEN_BITSET m32c_isa = {1, & default_isa};
 
 static void
 set_isa (enum isa_attr isa_num)
 {
-  m32c_isa = (1 << isa_num);
+  cgen_bitset_set (& m32c_isa, isa_num);
 }
 
 static void s_bss (int);
@@ -116,6 +123,14 @@ md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
       set_isa (ISA_M32C);
       break;
 
+    case OPTION_LINKRELAX:
+      m32c_relax = 1;
+      break;
+
+    case OPTION_H_TICK_HEX:
+      enable_h_tick_hex = 1;
+      break;
+
     default:
       return 0;
     }
@@ -142,6 +157,7 @@ s_bss (int ignore ATTRIBUTE_UNUSED)
 const pseudo_typeS md_pseudo_table[] =
 {
   { "bss",     s_bss,          0},
+  { "3byte",   cons,           3 },
   { "word",    cons,           4 },
   { NULL,      NULL,           0 }
 };
@@ -151,7 +167,7 @@ void
 md_begin (void)
 {
   /* Initialize the `cgen' interface.  */
-  
+
   /* Set the machine number and endian.  */
   gas_cgen_cpu_desc = m32c_cgen_cpu_open (CGEN_CPU_OPEN_MACHS, cpu_mach,
                                          CGEN_CPU_OPEN_ENDIAN,
@@ -179,10 +195,13 @@ m32c_md_end (void)
 {
   int i, n_nops;
 
-  /* Pad with nops for objdump.  */
-  n_nops = (32 - ((insn_size) % 32)) / 8;
-  for (i = 1; i <= n_nops; i++)
-    md_assemble ("nop");
+  if (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE)
+    {
+      /* Pad with nops for objdump.  */
+      n_nops = (32 - ((insn_size) % 32)) / 8;
+      for (i = 1; i <= n_nops; i++)
+       md_assemble ("nop");
+    }
 }
 
 void
@@ -315,6 +334,8 @@ md_assemble (char * str)
   static int last_insn_had_delay_slot = 0;
   m32c_insn insn;
   char *    errmsg;
+  finished_insnS results;
+  int rl_type;
 
   if (m32c_mach == bfd_mach_m32c && m32c_indirect_operand (str))
     return;
@@ -327,17 +348,50 @@ md_assemble (char * str)
   
   if (!insn.insn)
     {
-      as_bad (errmsg);
+      as_bad ("%s", errmsg);
       return;
     }
 
+  results.num_fixups = 0;
   /* Doesn't really matter what we pass for RELAX_P here.  */
   gas_cgen_finish_insn (insn.insn, insn.buffer,
-                       CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
+                       CGEN_FIELDS_BITSIZE (& insn.fields), 1, &results);
 
   last_insn_had_delay_slot
     = CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
   insn_size = CGEN_INSN_BITSIZE(insn.insn);
+
+  rl_type = rl_for (insn);
+
+  /* We have to mark all the jumps, because we need to adjust them
+     when we delete bytes, but we only need to mark the displacements
+     if they're symbolic - if they're not, we've already picked the
+     shortest opcode by now.  The linker, however, will still have to
+     check any operands to see if they're the displacement type, since
+     we don't know (nor record) *which* operands are relaxable.  */
+  if (m32c_relax
+      && rl_type != RL_TYPE_NONE
+      && (rl_type == RL_TYPE_JUMP || results.num_fixups)
+      && !relaxable (insn))
+    {
+      int reloc = 0;
+      int addend = results.num_fixups + 16 * insn_size/8;
+
+      switch (rl_for (insn))
+       {
+       case RL_TYPE_JUMP:  reloc = BFD_RELOC_M32C_RL_JUMP;  break;
+       case RL_TYPE_1ADDR: reloc = BFD_RELOC_M32C_RL_1ADDR; break;
+       case RL_TYPE_2ADDR: reloc = BFD_RELOC_M32C_RL_2ADDR; break;
+       }
+      if (insn.insn->base->num == M32C_INSN_JMP16_S
+         || insn.insn->base->num == M32C_INSN_JMP32_S)
+       addend = 0x10;
+
+      fix_new (results.frag,
+              results.addr - results.frag->fr_literal,
+              0, abs_section_sym, addend, 0,
+              reloc);
+    }
 }
 
 /* The syntax in the manual says constants begin with '#'.
@@ -395,7 +449,17 @@ const relax_typeS md_relax_table[] =
  /* 15 */ {     8,      1, 1, 16 }, /* jmp32.s */
  /* 16 */ {   127,   -128, 2, 17 }, /* jmp32.b */
  /* 17 */ { 32767, -32768, 3, 18 }, /* jmp32.w */
- /* 18 */ {     0,      0, 4,  0 }  /* jmp32.a */
+ /* 18 */ {     0,      0, 4,  0 }, /* jmp32.a */
+
+ /* 19 */ { 32767, -32768, 3, 20 }, /* jsr16.w */
+ /* 20 */ {     0,      0, 4,  0 }, /* jsr16.a */
+ /* 21 */ { 32767, -32768, 3, 11 }, /* jsr32.w */
+ /* 22 */ {     0,      0, 4,  0 }, /* jsr32.a */
+
+ /* 23 */ {     0,      0, 3,  0 }, /* adjnz pc8 */
+ /* 24 */ {     0,      0, 4,  0 }, /* adjnz disp8 pc8 */
+ /* 25 */ {     0,      0, 5,  0 }, /* adjnz disp16 pc8 */
+ /* 26 */ {     0,      0, 6,  0 }  /* adjnz disp24 pc8 */
 };
 
 enum {
@@ -405,6 +469,11 @@ enum {
   M32C_MACRO_JCND16_A,
   M32C_MACRO_JCND32_W,
   M32C_MACRO_JCND32_A,
+  /* the digit is the array index of the pcrel byte */
+  M32C_MACRO_ADJNZ_2,
+  M32C_MACRO_ADJNZ_3,
+  M32C_MACRO_ADJNZ_4,
+  M32C_MACRO_ADJNZ_5,
 } M32C_Macros;
 
 static struct {
@@ -436,7 +505,17 @@ static struct {
  /* 15 */ {  M32C_INSN_JMP32_S,     1, M32C_INSN_JMP32_A,     0 },
  /* 16 */ {  M32C_INSN_JMP32_B,     2, M32C_INSN_JMP32_A,     1 },
  /* 17 */ {  M32C_INSN_JMP32_W,     3, M32C_INSN_JMP32_A,     2 },
- /* 18 */ {  M32C_INSN_JMP32_A,     4, M32C_INSN_JMP32_A,     0 }
+ /* 18 */ {  M32C_INSN_JMP32_A,     4, M32C_INSN_JMP32_A,     0 },
+
+ /* 19 */ {  M32C_INSN_JSR16_W,     3, M32C_INSN_JSR16_A,     2 },
+ /* 20 */ {  M32C_INSN_JSR16_A,     4, M32C_INSN_JSR16_A,     0 },
+ /* 21 */ {  M32C_INSN_JSR32_W,     3, M32C_INSN_JSR32_A,     2 },
+ /* 22 */ {  M32C_INSN_JSR32_A,     4, M32C_INSN_JSR32_A,     0 },
+
+ /* 23 */ { -M32C_MACRO_ADJNZ_2,    3, -M32C_MACRO_ADJNZ_2,    0 },
+ /* 24 */ { -M32C_MACRO_ADJNZ_3,    4, -M32C_MACRO_ADJNZ_3,    0 },
+ /* 25 */ { -M32C_MACRO_ADJNZ_4,    5, -M32C_MACRO_ADJNZ_4,    0 },
+ /* 26 */ { -M32C_MACRO_ADJNZ_5,    6, -M32C_MACRO_ADJNZ_5,    0 }
 };
 #define NUM_MAPPINGS (sizeof (subtype_mappings) / sizeof (subtype_mappings[0]))
 
@@ -451,11 +530,21 @@ m32c_prepare_relax_scan (fragS *fragP, offsetT *aim, relax_substateT this_state)
 }
 
 static int
-insn_to_subtype (int insn)
+insn_to_subtype (int inum, const CGEN_INSN *insn)
 {
   unsigned int i;
+
+  if (insn
+      && (strncmp (insn->base->mnemonic, "adjnz", 5) == 0
+         || strncmp (insn->base->mnemonic, "sbjnz", 5) == 0))
+    {
+      i = 23 + insn->base->bitsize/8 - 3;
+      /*printf("mapping %d used for %s\n", i, insn->base->mnemonic);*/
+      return i;
+    }
+
   for (i=0; i<NUM_MAPPINGS; i++)
-    if (insn == subtype_mappings[i].insn)
+    if (inum == subtype_mappings[i].insn)
       {
        /*printf("mapping %d used\n", i);*/
        return i;
@@ -480,14 +569,14 @@ md_estimate_size_before_relax (fragS * fragP, segT segment ATTRIBUTE_UNUSED)
   int where = fragP->fr_opcode - fragP->fr_literal;
 
   if (fragP->fr_subtype == 1)
-    fragP->fr_subtype = insn_to_subtype (fragP->fr_cgen.insn->base->num);
+    fragP->fr_subtype = insn_to_subtype (fragP->fr_cgen.insn->base->num, fragP->fr_cgen.insn);
 
   if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
     {
       int new_insn;
 
       new_insn = subtype_mappings[fragP->fr_subtype].insn_for_extern;
-      fragP->fr_subtype = insn_to_subtype (new_insn);
+      fragP->fr_subtype = insn_to_subtype (new_insn, 0);
     }
 
   if (fragP->fr_cgen.insn->base
@@ -536,18 +625,26 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
   int operand;
   int new_insn;
   int where = fragP->fr_opcode - fragP->fr_literal;
+  int rl_where = fragP->fr_opcode - fragP->fr_literal;
   unsigned char *op = (unsigned char *)fragP->fr_opcode;
+  int op_base = 0;
+  int op_op = 0;
+  int rl_addend = 0;
 
   addend = target_address_for (fragP) - (fragP->fr_address + where);
   new_insn = subtype_mappings[fragP->fr_subtype].insn;
 
   fragP->fr_fix = where + subtype_mappings[fragP->fr_subtype].bytes;
 
+  op_base = 0;
+
   switch (subtype_mappings[fragP->fr_subtype].insn)
     {
     case M32C_INSN_JCND16_5:
       op[1] = addend - 1;
       operand = M32C_OPERAND_LAB_8_8;
+      op_op = 1;
+      rl_addend = 0x21;
       break;
 
     case -M32C_MACRO_JCND16_5_W:
@@ -559,6 +656,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_16;
       where += 2;
       new_insn = M32C_INSN_JMP16_W;
+      op_base = 2;
+      op_op = 3;
+      rl_addend = 0x51;
       break;
 
     case -M32C_MACRO_JCND16_5_A:
@@ -568,12 +668,18 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_24;
       where += 2;
       new_insn = M32C_INSN_JMP16_A;
+      op_base = 2;
+      op_op = 3;
+      rl_addend = 0x61;
       break;
 
 
     case M32C_INSN_JCND16:
       op[2] = addend - 2;
       operand = M32C_OPERAND_LAB_16_8;
+      op_base = 0;
+      op_op = 2;
+      rl_addend = 0x31;
       break;
 
     case -M32C_MACRO_JCND16_W:
@@ -585,6 +691,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_16;
       where += 3;
       new_insn = M32C_INSN_JMP16_W;
+      op_base = 3;
+      op_op = 4;
+      rl_addend = 0x61;
       break;
 
     case -M32C_MACRO_JCND16_A:
@@ -594,17 +703,26 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_24;
       where += 3;
       new_insn = M32C_INSN_JMP16_A;
+      op_base = 3;
+      op_op = 4;
+      rl_addend = 0x71;
       break;
 
     case M32C_INSN_JMP16_S:
       op[0] = 0x60 | ((addend-2) & 0x07);
       operand = M32C_OPERAND_LAB_5_3;
+      op_base = 0;
+      op_op = 0;
+      rl_addend = 0x10;
       break;
 
     case M32C_INSN_JMP16_B:
       op[0] = 0xfe;
       op[1] = addend - 1;
       operand = M32C_OPERAND_LAB_8_8;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x21;
       break;
 
     case M32C_INSN_JMP16_W:
@@ -612,6 +730,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       op[1] = addend - 1;
       op[2] = (addend - 1) >> 8;
       operand = M32C_OPERAND_LAB_8_16;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x31;
       break;
 
     case M32C_INSN_JMP16_A:
@@ -620,11 +741,17 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       op[2] = 0;
       op[3] = 0;
       operand = M32C_OPERAND_LAB_8_24;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x41;
       break;
 
     case M32C_INSN_JCND32:
       op[1] = addend - 1;
       operand = M32C_OPERAND_LAB_8_8;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x21;
       break;
 
     case -M32C_MACRO_JCND32_W:
@@ -636,6 +763,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_16;
       where += 2;
       new_insn = M32C_INSN_JMP32_W;
+      op_base = 2;
+      op_op = 3;
+      rl_addend = 0x51;
       break;
 
     case -M32C_MACRO_JCND32_A:
@@ -645,6 +775,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       operand = M32C_OPERAND_LAB_8_24;
       where += 2;
       new_insn = M32C_INSN_JMP32_A;
+      op_base = 2;
+      op_op = 3;
+      rl_addend = 0x61;
       break;
 
 
@@ -653,12 +786,18 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       addend = ((addend-2) & 0x07);
       op[0] = 0x4a | (addend & 0x01) | ((addend << 3) & 0x30);
       operand = M32C_OPERAND_LAB32_JMP_S;
+      op_base = 0;
+      op_op = 0;
+      rl_addend = 0x10;
       break;
 
     case M32C_INSN_JMP32_B:
       op[0] = 0xbb;
       op[1] = addend - 1;
       operand = M32C_OPERAND_LAB_8_8;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x21;
       break;
 
     case M32C_INSN_JMP32_W:
@@ -666,6 +805,9 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       op[1] = addend - 1;
       op[2] = (addend - 1) >> 8;
       operand = M32C_OPERAND_LAB_8_16;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x31;
       break;
 
     case M32C_INSN_JMP32_A:
@@ -674,6 +816,73 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       op[2] = 0;
       op[3] = 0;
       operand = M32C_OPERAND_LAB_8_24;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x41;
+      break;
+
+
+    case M32C_INSN_JSR16_W:
+      op[0] = 0xf5;
+      op[1] = addend - 1;
+      op[2] = (addend - 1) >> 8;
+      operand = M32C_OPERAND_LAB_8_16;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x31;
+      break;
+
+    case M32C_INSN_JSR16_A:
+      op[0] = 0xfd;
+      op[1] = 0;
+      op[2] = 0;
+      op[3] = 0;
+      operand = M32C_OPERAND_LAB_8_24;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x41;
+      break;
+
+    case M32C_INSN_JSR32_W:
+      op[0] = 0xcf;
+      op[1] = addend - 1;
+      op[2] = (addend - 1) >> 8;
+      operand = M32C_OPERAND_LAB_8_16;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x31;
+      break;
+
+    case M32C_INSN_JSR32_A:
+      op[0] = 0xcd;
+      op[1] = 0;
+      op[2] = 0;
+      op[3] = 0;
+      operand = M32C_OPERAND_LAB_8_24;
+      op_base = 0;
+      op_op = 1;
+      rl_addend = 0x41;
+      break;
+
+    case -M32C_MACRO_ADJNZ_2:
+      rl_addend = 0x31;
+      op[2] = addend - 2;
+      operand = M32C_OPERAND_LAB_16_8;
+      break;
+    case -M32C_MACRO_ADJNZ_3:
+      rl_addend = 0x41;
+      op[3] = addend - 2;
+      operand = M32C_OPERAND_LAB_24_8;
+      break;
+    case -M32C_MACRO_ADJNZ_4:
+      rl_addend = 0x51;
+      op[4] = addend - 2;
+      operand = M32C_OPERAND_LAB_32_8;
+      break;
+    case -M32C_MACRO_ADJNZ_5:
+      rl_addend = 0x61;
+      op[5] = addend - 2;
+      operand = M32C_OPERAND_LAB_40_8;
       break;
 
 
@@ -684,18 +893,32 @@ md_convert_frag (bfd *   abfd ATTRIBUTE_UNUSED,
       abort();
     }
 
+  if (m32c_relax)
+    {
+      if (operand != M32C_OPERAND_LAB_8_24)
+       fragP->fr_offset = (fragP->fr_address + where);
+
+      fix_new (fragP,
+              rl_where,
+              0, abs_section_sym, rl_addend, 0,
+              BFD_RELOC_M32C_RL_JUMP);
+    }
+
   if (S_GET_SEGMENT (fragP->fr_symbol) != sec
-      || operand == M32C_OPERAND_LAB_8_24)
+      || operand == M32C_OPERAND_LAB_8_24
+      || (m32c_relax && (operand != M32C_OPERAND_LAB_5_3
+                        && operand != M32C_OPERAND_LAB32_JMP_S)))
     {
-      assert (fragP->fr_cgen.insn != 0);
-      gas_cgen_record_fixup (fragP,
-                            where,
-                            fragP->fr_cgen.insn,
-                            (fragP->fr_fix - where) * 8,
-                            cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
-                                                        operand),
-                            fragP->fr_cgen.opinfo,
-                            fragP->fr_symbol, fragP->fr_offset);
+      fixS *fixP;
+      gas_assert (fragP->fr_cgen.insn != 0);
+      fixP = gas_cgen_record_fixup (fragP,
+                                   where,
+                                   fragP->fr_cgen.insn,
+                                   (fragP->fr_fix - where) * 8,
+                                   cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
+                                                               operand),
+                                   fragP->fr_cgen.opinfo,
+                                   fragP->fr_symbol, fragP->fr_offset);
     }
 }
 \f
@@ -738,10 +961,50 @@ md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
     int offset;
   } op_reloc_table[] = {
 
+    /* PC-REL relocs for 8-bit fields.  */
+    { M32C_OPERAND_LAB_8_8,    BFD_RELOC_8_PCREL, 1 },
+    { M32C_OPERAND_LAB_16_8,   BFD_RELOC_8_PCREL, 2 },
+    { M32C_OPERAND_LAB_24_8,   BFD_RELOC_8_PCREL, 3 },
+    { M32C_OPERAND_LAB_32_8,   BFD_RELOC_8_PCREL, 4 },
+    { M32C_OPERAND_LAB_40_8,   BFD_RELOC_8_PCREL, 5 },
+
+    /* PC-REL relocs for 16-bit fields.  */
+    { M32C_OPERAND_LAB_8_16,   BFD_RELOC_16_PCREL, 1 },
+
+    /* Absolute relocs for 8-bit fields.  */
+    { M32C_OPERAND_IMM_8_QI,   BFD_RELOC_8, 1 },
+    { M32C_OPERAND_IMM_16_QI,  BFD_RELOC_8, 2 },
+    { M32C_OPERAND_IMM_24_QI,  BFD_RELOC_8, 3 },
+    { M32C_OPERAND_IMM_32_QI,  BFD_RELOC_8, 4 },
+    { M32C_OPERAND_IMM_40_QI,  BFD_RELOC_8, 5 },
+    { M32C_OPERAND_IMM_48_QI,  BFD_RELOC_8, 6 },
+    { M32C_OPERAND_IMM_56_QI,  BFD_RELOC_8, 7 },
+    { M32C_OPERAND_DSP_8_S8,   BFD_RELOC_8, 1 },
+    { M32C_OPERAND_DSP_16_S8,  BFD_RELOC_8, 2 },
+    { M32C_OPERAND_DSP_24_S8,  BFD_RELOC_8, 3 },
+    { M32C_OPERAND_DSP_32_S8,  BFD_RELOC_8, 4 },
+    { M32C_OPERAND_DSP_40_S8,  BFD_RELOC_8, 5 },
+    { M32C_OPERAND_DSP_48_S8,  BFD_RELOC_8, 6 },
+    { M32C_OPERAND_DSP_8_U8,   BFD_RELOC_8, 1 },
+    { M32C_OPERAND_DSP_16_U8,  BFD_RELOC_8, 2 },
+    { M32C_OPERAND_DSP_24_U8,  BFD_RELOC_8, 3 },
+    { M32C_OPERAND_DSP_32_U8,  BFD_RELOC_8, 4 },
+    { M32C_OPERAND_DSP_40_U8,  BFD_RELOC_8, 5 },
+    { M32C_OPERAND_DSP_48_U8,  BFD_RELOC_8, 6 },
+    { M32C_OPERAND_BITBASE32_16_S11_UNPREFIXED, BFD_RELOC_8, 2 },
+    { M32C_OPERAND_BITBASE32_16_U11_UNPREFIXED, BFD_RELOC_8, 2 },
+    { M32C_OPERAND_BITBASE32_24_S11_PREFIXED, BFD_RELOC_8, 3 },
+    { M32C_OPERAND_BITBASE32_24_U11_PREFIXED, BFD_RELOC_8, 3 },
+
     /* Absolute relocs for 16-bit fields.  */
+    { M32C_OPERAND_IMM_8_HI,   BFD_RELOC_16, 1 },
     { M32C_OPERAND_IMM_16_HI,  BFD_RELOC_16, 2 },
     { M32C_OPERAND_IMM_24_HI,  BFD_RELOC_16, 3 },
     { M32C_OPERAND_IMM_32_HI,  BFD_RELOC_16, 4 },
+    { M32C_OPERAND_IMM_40_HI,  BFD_RELOC_16, 5 },
+    { M32C_OPERAND_IMM_48_HI,  BFD_RELOC_16, 6 },
+    { M32C_OPERAND_IMM_56_HI,  BFD_RELOC_16, 7 },
+    { M32C_OPERAND_IMM_64_HI,  BFD_RELOC_16, 8 },
     { M32C_OPERAND_DSP_16_S16, BFD_RELOC_16, 2 },
     { M32C_OPERAND_DSP_24_S16, BFD_RELOC_16, 3 },
     { M32C_OPERAND_DSP_32_S16, BFD_RELOC_16, 4 },
@@ -750,13 +1013,27 @@ md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
     { M32C_OPERAND_DSP_16_U16, BFD_RELOC_16, 2 },
     { M32C_OPERAND_DSP_24_U16, BFD_RELOC_16, 3 },
     { M32C_OPERAND_DSP_32_U16, BFD_RELOC_16, 4 },
+    { M32C_OPERAND_DSP_40_U16, BFD_RELOC_16, 5 },
+    { M32C_OPERAND_DSP_48_U16, BFD_RELOC_16, 6 },
+    { M32C_OPERAND_BITBASE32_16_S19_UNPREFIXED, BFD_RELOC_16, 2 },
+    { M32C_OPERAND_BITBASE32_16_U19_UNPREFIXED, BFD_RELOC_16, 2 },
+    { M32C_OPERAND_BITBASE32_24_S19_PREFIXED, BFD_RELOC_16, 3 },
+    { M32C_OPERAND_BITBASE32_24_U19_PREFIXED, BFD_RELOC_16, 3 },
 
     /* Absolute relocs for 24-bit fields.  */
     { M32C_OPERAND_LAB_8_24,   BFD_RELOC_24, 1 },
+    { M32C_OPERAND_DSP_8_S24,  BFD_RELOC_24, 1 },
+    { M32C_OPERAND_DSP_8_U24,  BFD_RELOC_24, 1 },
     { M32C_OPERAND_DSP_16_U24, BFD_RELOC_24, 2 },
     { M32C_OPERAND_DSP_24_U24, BFD_RELOC_24, 3 },
     { M32C_OPERAND_DSP_32_U24, BFD_RELOC_24, 4 },
     { M32C_OPERAND_DSP_40_U24, BFD_RELOC_24, 5 },
+    { M32C_OPERAND_DSP_48_U24, BFD_RELOC_24, 6 },
+    { M32C_OPERAND_DSP_16_U20, BFD_RELOC_24, 2 },
+    { M32C_OPERAND_DSP_24_U20, BFD_RELOC_24, 3 },
+    { M32C_OPERAND_DSP_32_U20, BFD_RELOC_24, 4 },
+    { M32C_OPERAND_BITBASE32_16_U27_UNPREFIXED, BFD_RELOC_24, 2 },
+    { M32C_OPERAND_BITBASE32_24_U27_PREFIXED, BFD_RELOC_24, 3 },
 
     /* Absolute relocs for 32-bit fields.  */
     { M32C_OPERAND_IMM_16_SI,  BFD_RELOC_32, 2 },
@@ -776,18 +1053,86 @@ md_cgen_lookup_reloc (const CGEN_INSN *    insn ATTRIBUTE_UNUSED,
         {
           fixP->fx_where += or->offset;
           fixP->fx_size -= or->offset;
+
+         if (fixP->fx_cgen.opinfo
+             && fixP->fx_cgen.opinfo != BFD_RELOC_NONE)
+           return fixP->fx_cgen.opinfo;
+
           return or->reloc;
         }
     }
 
   fprintf
     (stderr,
-     "Error: tc-m32c.c:md_cgen_lookup_reloc Unimplemented relocation %d\n",
-     operand->type);
+     "Error: tc-m32c.c:md_cgen_lookup_reloc Unimplemented relocation for operand %s\n",
+     operand->name);
 
   return BFD_RELOC_NONE;
 }
 
+void
+m32c_cons_fix_new (fragS *     frag,
+                  int          where,
+                  int          size,
+                  expressionS *exp)
+{
+  bfd_reloc_code_real_type type;
+
+  switch (size)
+    {
+    case 1:
+      type = BFD_RELOC_8;
+      break;
+    case 2:
+      type = BFD_RELOC_16;
+      break;
+    case 3:
+      type = BFD_RELOC_24;
+      break;
+    case 4:
+    default:
+      type = BFD_RELOC_32;
+      break;
+    case 8:
+      type = BFD_RELOC_64;
+      break;
+    }
+
+  fix_new_exp (frag, where, (int) size, exp, 0, type);
+}
+
+void
+m32c_apply_fix (struct fix *f, valueT *t, segT s)
+{
+  if (f->fx_r_type == BFD_RELOC_M32C_RL_JUMP
+      || f->fx_r_type == BFD_RELOC_M32C_RL_1ADDR
+      || f->fx_r_type == BFD_RELOC_M32C_RL_2ADDR)
+    return;
+  gas_cgen_md_apply_fix (f, t, s);
+}
+
+arelent *
+tc_gen_reloc (asection *sec, fixS *fx)
+{
+  if (fx->fx_r_type == BFD_RELOC_M32C_RL_JUMP
+      || fx->fx_r_type == BFD_RELOC_M32C_RL_1ADDR
+      || fx->fx_r_type == BFD_RELOC_M32C_RL_2ADDR)
+    {
+      arelent * reloc;
+      reloc = xmalloc (sizeof (* reloc));
+      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fx->fx_addsy);
+      reloc->address = fx->fx_frag->fr_address + fx->fx_where;
+      reloc->howto = bfd_reloc_type_lookup (stdoutput, fx->fx_r_type);
+      reloc->addend = fx->fx_offset;
+      return reloc;
+
+    }
+  return gas_cgen_tc_gen_reloc (sec, fx);
+}
+
 /* See whether we need to force a relocation into the output file.
    This is used to force out switch and PC relative relocations when
    relaxing.  */
@@ -812,12 +1157,40 @@ m32c_force_relocation (fixS * fixp)
        case M32C_OPERAND_DSP_24_U16:
        case M32C_OPERAND_IMM_24_HI:
          return 1;
+
+        /* If we're doing linker relaxing, we need to keep all the
+          pc-relative jumps in case we need to fix them due to
+          deleted bytes between the jump and its destination.  */
+       case M32C_OPERAND_LAB_8_8:
+       case M32C_OPERAND_LAB_8_16:
+       case M32C_OPERAND_LAB_8_24:
+       case M32C_OPERAND_LAB_16_8:
+       case M32C_OPERAND_LAB_24_8:
+       case M32C_OPERAND_LAB_32_8:
+       case M32C_OPERAND_LAB_40_8:
+         if (m32c_relax)
+           return 1;
+       default:
+         break;
        }
     }
   else
     {
-      if (fixp->fx_r_type == BFD_RELOC_16)
-       return 1;
+      switch (fixp->fx_r_type)
+       {
+       case BFD_RELOC_16:
+         return 1;
+
+       case BFD_RELOC_M32C_RL_JUMP:
+       case BFD_RELOC_M32C_RL_1ADDR:
+       case BFD_RELOC_M32C_RL_2ADDR:
+       case BFD_RELOC_8_PCREL:
+       case BFD_RELOC_16_PCREL:
+         if (m32c_relax)
+           return 1;
+       default:
+         break;
+       }
     }
 
   return generic_force_reloc (fixp);
@@ -841,47 +1214,7 @@ md_number_to_chars (char * buf, valueT val, int n)
 char *
 md_atof (int type, char * litP, int * sizeP)
 {
-  int              i;
-  int              prec;
-  LITTLENUM_TYPE   words [MAX_LITTLENUMS];
-  char *           t;
-
-  switch (type)
-    {
-    case 'f':
-    case 'F':
-    case 's':
-    case 'S':
-      prec = 2;
-      break;
-
-    case 'd':
-    case 'D':
-    case 'r':
-    case 'R':
-      prec = 4;
-      break;
-
-   /* FIXME: Some targets allow other format chars for bigger sizes here.  */
-
-    default:
-      * sizeP = 0;
-      return _("Bad call to md_atof()");
-    }
-
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-  * sizeP = prec * sizeof (LITTLENUM_TYPE);
-
-  for (i = 0; i < prec; i++)
-    {
-      md_number_to_chars (litP, (valueT) words[i],
-                         sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
-    }
-     
-  return 0;
+  return ieee_md_atof (type, litP, sizeP, TRUE);
 }
 
 bfd_boolean
@@ -963,12 +1296,13 @@ m32c_fix_adjustable (fixS * fixP)
   if (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE)
     return 0;
 
+  if (m32c_relax)
+    return 0;
+
   return 1;
 }
 
 /* Worker function for m32c_is_colon_insn().  */
-static char restore_colon PARAMS ((int));
-
 static char
 restore_colon (int advance_i_l_p_by)
 {
@@ -1014,4 +1348,3 @@ m32c_is_colon_insn (char *start ATTRIBUTE_UNUSED)
 
   return 0;
 }
-