2003-09-26 Matt Thomas <matt@3am-software.com>
[deliverable/binutils-gdb.git] / gas / config / tc-m68hc11.c
index b7b2116c742efcd12bc00f6788c69a508a768e9a..db6d5c1726385997ed0b5dc3bd1ecfed2e13cd78 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-m68hc11.c -- Assembler code for the Motorola 68HC11 & 68HC12.
-   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Written by Stephane Carrez (stcarrez@nerim.fr)
 
    This file is part of GAS, the GNU Assembler.
@@ -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 "safe-ctype.h"
 #include "subsegs.h"
@@ -37,8 +36,9 @@ const char FLT_CHARS[] = "dD";
 #define STATE_CONDITIONAL_BRANCH       (1)
 #define STATE_PC_RELATIVE              (2)
 #define STATE_INDEXED_OFFSET            (3)
-#define STATE_XBCC_BRANCH               (4)
-#define STATE_CONDITIONAL_BRANCH_6812  (5)
+#define STATE_INDEXED_PCREL             (4)
+#define STATE_XBCC_BRANCH               (5)
+#define STATE_CONDITIONAL_BRANCH_6812  (6)
 
 #define STATE_BYTE                     (0)
 #define STATE_BITS5                     (0)
@@ -90,6 +90,14 @@ relax_typeS md_relax_table[] = {
   {0, 0, 2, 0},
   {1, 1, 0, 0},
 
+  /* Relax for PC relative offset: 5-bits, 9-bits, 16-bits.
+     For the 9-bit case, there will be a -1 correction to take into
+     account the new byte that's why the range is -255..256.  */
+  {(15), (-16), 0, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9)},
+  {(256), (-255), 1, ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16)},
+  {0, 0, 2, 0},
+  {1, 1, 0, 0},
+
   /* Relax for dbeq/ibeq/tbeq r,<L>:
      These insns are translated into db!cc +3 jmp L.  */
   {(255), (-256), 0, ENCODE_RELAX (STATE_XBCC_BRANCH, STATE_WORD)},
@@ -242,7 +250,7 @@ static int num_opcodes;
 static struct m68hc11_opcode *m68hc11_sorted_opcodes;
 
 /* ELF flags to set in the output file header.  */
-static int elf_flags = 0;
+static int elf_flags = E_M68HC11_F64;
 
 /* These are the machine dependent pseudo-ops.  These are included so
    the assembler can work on the output from the SUN C compiler, which
@@ -260,10 +268,6 @@ const pseudo_typeS md_pseudo_table[] = {
   {"fcc", stringer, 1},
   {"rmb", s_space, 0},
 
-  /* Dwarf2 support for Gcc.  */
-  {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
-  {"loc", dwarf2_directive_loc, 0},
-
   /* Motorola ALIS.  */
   {"xrefb", s_ignore, 0}, /* Same as xref  */
 
@@ -305,6 +309,18 @@ struct option md_longopts[] = {
 #define OPTION_GENERATE_EXAMPLE  (OPTION_MD_BASE + 5)
   {"generate-example", no_argument, NULL, OPTION_GENERATE_EXAMPLE},
 
+#define OPTION_MSHORT  (OPTION_MD_BASE + 6)
+  {"mshort", no_argument, NULL, OPTION_MSHORT},
+
+#define OPTION_MLONG  (OPTION_MD_BASE + 7)
+  {"mlong", no_argument, NULL, OPTION_MLONG},
+
+#define OPTION_MSHORT_DOUBLE  (OPTION_MD_BASE + 8)
+  {"mshort-double", no_argument, NULL, OPTION_MSHORT_DOUBLE},
+
+#define OPTION_MLONG_DOUBLE  (OPTION_MD_BASE + 9)
+  {"mlong-double", no_argument, NULL, OPTION_MLONG_DOUBLE},
+
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
@@ -354,8 +370,13 @@ md_show_usage (stream)
 {
   get_default_target ();
   fprintf (stream, _("\
-Motorola 68HC11/68HC12 options:\n\
-  -m68hc11 | -m68hc12     specify the processor [default %s]\n\
+Motorola 68HC11/68HC12/68HCS12 options:\n\
+  -m68hc11 | -m68hc12 |\n\
+  -m68hcs12               specify the processor [default %s]\n\
+  -mshort                 use 16-bit int ABI (default)\n\
+  -mlong                  use 32-bit int ABI\n\
+  -mshort-double          use 32-bit double ABI\n\
+  -mlong-double           use 64-bit double ABI (default)\n\
   --force-long-branchs    always turn relative branchs into absolute ones\n\
   -S,--short-branchs      do not turn relative branchs into absolute ones\n\
                           when the offset is out of range\n\
@@ -457,11 +478,29 @@ md_parse_option (c, arg)
       flag_print_opcodes = 2;
       break;
 
+    case OPTION_MSHORT:
+      elf_flags &= ~E_M68HC11_I32;
+      break;
+
+    case OPTION_MLONG:
+      elf_flags |= E_M68HC11_I32;
+      break;
+
+    case OPTION_MSHORT_DOUBLE:
+      elf_flags &= ~E_M68HC11_F64;
+      break;
+
+    case OPTION_MLONG_DOUBLE:
+      elf_flags |= E_M68HC11_F64;
+      break;
+
     case 'm':
       if (strcasecmp (arg, "68hc11") == 0)
        current_architecture = cpu6811;
       else if (strcasecmp (arg, "68hc12") == 0)
        current_architecture = cpu6812;
+      else if (strcasecmp (arg, "68hcs12") == 0)
+       current_architecture = cpu6812 | cpu6812s;
       else
        as_bad (_("Option `%s' is not recognized."), arg);
       break;
@@ -606,7 +645,8 @@ md_begin ()
              }
        }
     }
-  qsort (opcodes, num_opcodes, sizeof (struct m68hc11_opcode), cmp_opcode);
+  qsort (opcodes, num_opcodes, sizeof (struct m68hc11_opcode),
+         (int (*) PARAMS ((const PTR, const PTR))) cmp_opcode);
 
   opc = (struct m68hc11_opcode_def *)
     xmalloc (num_opcodes * sizeof (struct m68hc11_opcode_def));
@@ -945,6 +985,8 @@ register_name ()
 
   return reg_number;
 }
+#define M6811_OP_CALL_ADDR    0x00800000
+#define M6811_OP_PAGE_ADDR    0x04000000
 
 /* Parse a string of operands and return an array of expressions.
 
@@ -1010,6 +1052,24 @@ get_operand (oper, which, opmode)
          p += 3;
          mode |= M6811_OP_LOW_ADDR;
        }
+      /* %page modifier is used to obtain only the page number
+         of the address of a function.  */
+      else if (strncmp (p, "%page", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_PAGE_ADDR;
+       }
+
+      /* %addr modifier is used to obtain the physical address part
+         of the function (16-bit).  For 68HC12 the function will be
+         mapped in the 16K window at 0x8000 and the value will be
+         within that window (although the function address may not fit
+         in 16-bit).  See bfd/elf32-m68hc12.c for the translation.  */
+      else if (strncmp (p, "%addr", 5) == 0)
+       {
+         p += 5;
+         mode |= M6811_OP_CALL_ADDR;
+       }
     }
   else if (*p == '.' && (p[1] == '+' || p[1] == '-'))
     {
@@ -1042,6 +1102,12 @@ get_operand (oper, which, opmode)
       as_bad (_("Spurious `,' or bad indirect register addressing mode."));
       return -1;
     }
+  /* Handle 68HC12 page specification in 'call foo,%page(bar)'.  */
+  else if ((opmode & M6812_OP_PAGE) && strncmp (p, "%page", 5) == 0)
+    {
+      p += 5;
+      mode = M6811_OP_PAGE_ADDR | M6812_OP_PAGE | M6811_OP_IND16;
+    }
   input_line_pointer = p;
 
   if (mode == M6811_OP_NONE || mode == M6812_OP_D_IDX)
@@ -1373,21 +1439,29 @@ fixup8 (oper, mode, opmode)
          fixS *fixp;
 
          fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
-                             oper, true, BFD_RELOC_8_PCREL);
+                             oper, TRUE, BFD_RELOC_8_PCREL);
          fixp->fx_pcrel_adjust = 1;
        }
       else
        {
-         /* Now create an 8-bit fixup.  If there was some %hi or %lo
-            modifier, generate the reloc accordingly.  */
-         fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
-                      oper, false,
-                      ((opmode & M6811_OP_HIGH_ADDR)
-                       ? BFD_RELOC_M68HC11_HI8
-                       : ((opmode & M6811_OP_LOW_ADDR)
-                          ? BFD_RELOC_M68HC11_LO8
-                           : ((mode & M6812_OP_PAGE)
-                              ? BFD_RELOC_M68HC11_PAGE : BFD_RELOC_8))));
+         fixS *fixp;
+          int reloc;
+
+         /* Now create an 8-bit fixup.  If there was some %hi, %lo
+            or %page modifier, generate the reloc accordingly.  */
+          if (opmode & M6811_OP_HIGH_ADDR)
+            reloc = BFD_RELOC_M68HC11_HI8;
+          else if (opmode & M6811_OP_LOW_ADDR)
+            reloc = BFD_RELOC_M68HC11_LO8;
+          else if (opmode & M6811_OP_PAGE_ADDR)
+            reloc = BFD_RELOC_M68HC11_PAGE;
+          else
+            reloc = BFD_RELOC_8;
+
+         fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1,
+                              oper, FALSE, reloc);
+          if (reloc != BFD_RELOC_8)
+            fixp->fx_no_overflow = 1;
        }
       number_to_chars_bigendian (f, 0, 1);
     }
@@ -1421,18 +1495,27 @@ fixup16 (oper, mode, opmode)
   else if (oper->X_op != O_register)
     {
       fixS *fixp;
+      int reloc;
+
+      if ((opmode & M6811_OP_CALL_ADDR) && (mode & M6811_OP_IMM16))
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else if (mode & M6812_OP_JUMP_REL16)
+        reloc = BFD_RELOC_16_PCREL;
+      else if (mode & M6812_OP_PAGE)
+        reloc = BFD_RELOC_M68HC11_LO16;
+      else
+        reloc = BFD_RELOC_16;
 
       /* Now create a 16-bit fixup.  */
       fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
                          oper,
-                         (mode & M6812_OP_JUMP_REL16 ? true : false),
-                         (mode & M6812_OP_JUMP_REL16
-                          ? BFD_RELOC_16_PCREL
-                           : (mode & M6812_OP_PAGE)
-                           ? BFD_RELOC_M68HC11_LO16 : BFD_RELOC_16));
+                         reloc == BFD_RELOC_16_PCREL,
+                          reloc);
       number_to_chars_bigendian (f, 0, 2);
-      if (mode & M6812_OP_JUMP_REL16)
+      if (reloc == BFD_RELOC_16_PCREL)
        fixp->fx_pcrel_adjust = 2;
+      if (reloc == BFD_RELOC_M68HC11_LO16)
+        fixp->fx_no_overflow = 1;
     }
   else
     {
@@ -1467,7 +1550,7 @@ fixup24 (oper, mode, opmode)
 
       /* Now create a 24-bit fixup.  */
       fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
-                         oper, false, BFD_RELOC_M68HC11_24);
+                         oper, FALSE, BFD_RELOC_M68HC11_24);
       number_to_chars_bigendian (f, 0, 3);
     }
   else
@@ -1901,21 +1984,28 @@ build_indexed_byte (op, format, move_insn)
         }
       else if (op->reg1 != REG_PC)
        {
-         byte = (byte << 3) | 0xe2;
+          symbolS *sym;
+          offsetT off;
+
          f = frag_more (1);
          number_to_chars_bigendian (f, byte, 1);
-
-         f = frag_more (2);
-         fix_new_exp (frag_now, f - frag_now->fr_literal, 2,
-                      &op->exp, false, BFD_RELOC_16);
-         number_to_chars_bigendian (f, 0, 2);
+          sym = op->exp.X_add_symbol;
+          off = op->exp.X_add_number;
+          if (op->exp.X_op != O_symbol)
+            {
+              sym = make_expr_symbol (&op->exp);
+              off = 0;
+            }
+         frag_var (rs_machine_dependent, 2, 2,
+                   ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF),
+                   sym, off, f);
        }
       else
        {
          f = frag_more (1);
          number_to_chars_bigendian (f, byte, 1);
          frag_var (rs_machine_dependent, 2, 2,
-                   ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_UNDF),
+                   ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_UNDF),
                    op->exp.X_add_symbol,
                    op->exp.X_add_number, f);
        }
@@ -2028,17 +2118,12 @@ build_insn (opcode, operands, nb_operands)
   char *f;
   long format;
   int move_insn = 0;
-  fragS *frag;
-  int where;
 
   /* Put the page code instruction if there is one.  */
   format = opcode->format;
 
-  frag = frag_now;
-  where = frag_now_fix ();
-
   if (format & M6811_OP_BRANCH)
-    fix_new (frag, where, 1,
+    fix_new (frag_now, frag_now_fix (), 1,
              &abs_symbol, 0, 1, BFD_RELOC_M68HC11_RL_JUMP);
 
   if (format & OP_EXTENDED)
@@ -2359,6 +2444,11 @@ find_opcode (opc, operands, nb_operands)
       if (i >= opc->min_operands)
        {
          opcode = find (opc, operands, i);
+
+          /* Another special case for 'call foo,page' instructions.
+             Since we support 'call foo' and 'call foo,page' we must look
+             if the optional page specification is present otherwise we will
+             assemble immediately and treat the page spec as garbage.  */
           if (opcode && !(opcode->format & M6812_OP_PAGE))
              return opcode;
 
@@ -2644,7 +2734,7 @@ s_m68hc11_relax (ignore)
       return;
     }
 
-  fix_new_exp (frag_now, frag_now_fix (), 1, &ex, 1,
+  fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1,
                BFD_RELOC_M68HC11_RL_GROUP);
 
   demand_empty_rest_of_line ();
@@ -2670,7 +2760,7 @@ md_pcrel_from (fixP)
    then it is done here.  */
 arelent *
 tc_gen_reloc (section, fixp)
-     asection *section;
+     asection *section ATTRIBUTE_UNUSED;
      fixS *fixp;
 {
   arelent *reloc;
@@ -2691,17 +2781,109 @@ tc_gen_reloc (section, fixp)
       return NULL;
     }
 
-  if (!fixp->fx_pcrel)
-    reloc->addend = fixp->fx_addnumber;
-  else
-    reloc->addend = (section->vma
-                    /*+ (fixp->fx_pcrel_adjust == 64
-                       ? -1 : fixp->fx_pcrel_adjust)*/
-                    + fixp->fx_addnumber
-                    + md_pcrel_from (fixp));
+  /* Since we use Rel instead of Rela, encode the vtable entry to be
+     used in the relocation's section offset.  */
+  if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+    reloc->address = fixp->fx_offset;
+
+  reloc->addend = 0;
   return reloc;
 }
 
+/* We need a port-specific relaxation function to cope with sym2 - sym1
+   relative expressions with both symbols in the same segment (but not
+   necessarily in the same frag as this insn), for example:
+     ldab sym2-(sym1-2),pc
+    sym1:
+   The offset can be 5, 9 or 16 bits long.  */
+
+long
+m68hc11_relax_frag (seg, fragP, stretch)
+     segT seg ATTRIBUTE_UNUSED;
+     fragS *fragP;
+     long stretch ATTRIBUTE_UNUSED;
+{
+  long growth;
+  offsetT aim = 0;
+  symbolS *symbolP;
+  const relax_typeS *this_type;
+  const relax_typeS *start_type;
+  relax_substateT next_state;
+  relax_substateT this_state;
+  const relax_typeS *table = TC_GENERIC_RELAX_TABLE;
+
+  /* We only have to cope with frags as prepared by
+     md_estimate_size_before_relax.  The STATE_BITS16 case may geet here
+     because of the different reasons that it's not relaxable.  */
+  switch (fragP->fr_subtype)
+    {
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
+      /* When we get to this state, the frag won't grow any more.  */
+      return 0;
+
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS5):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9):
+    case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
+      if (fragP->fr_symbol == NULL
+         || S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+       as_fatal (_("internal inconsistency problem in %s: fr_symbol %lx"),
+                 __FUNCTION__, (long) fragP->fr_symbol);
+      symbolP = fragP->fr_symbol;
+      if (symbol_resolved_p (symbolP))
+       as_fatal (_("internal inconsistency problem in %s: resolved symbol"),
+                 __FUNCTION__);
+      aim = S_GET_VALUE (symbolP);
+      break;
+
+    default:
+      as_fatal (_("internal inconsistency problem in %s: fr_subtype %d"),
+                 __FUNCTION__, fragP->fr_subtype);
+    }
+
+  /* The rest is stolen from relax_frag.  There's no obvious way to
+     share the code, but fortunately no requirement to keep in sync as
+     long as fragP->fr_symbol does not have its segment changed.  */
+
+  this_state = fragP->fr_subtype;
+  start_type = this_type = table + this_state;
+
+  if (aim < 0)
+    {
+      /* Look backwards.  */
+      for (next_state = this_type->rlx_more; next_state;)
+       if (aim >= this_type->rlx_backward)
+         next_state = 0;
+       else
+         {
+           /* Grow to next state.  */
+           this_state = next_state;
+           this_type = table + this_state;
+           next_state = this_type->rlx_more;
+         }
+    }
+  else
+    {
+      /* Look forwards.  */
+      for (next_state = this_type->rlx_more; next_state;)
+       if (aim <= this_type->rlx_forward)
+         next_state = 0;
+       else
+         {
+           /* Grow to next state.  */
+           this_state = next_state;
+           this_type = table + this_state;
+           next_state = this_type->rlx_more;
+         }
+    }
+
+  growth = this_type->rlx_length - start_type->rlx_length;
+  if (growth != 0)
+    fragP->fr_subtype = this_state;
+  return growth;
+}
+
 void
 md_convert_frag (abfd, sec, fragP)
      bfd *abfd ATTRIBUTE_UNUSED;
@@ -2768,31 +2950,44 @@ md_convert_frag (abfd, sec, fragP)
       fragP->fr_fix += 2;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS5):
+      if (fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+        value = disp;
+      /* fall through  */
+
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS5):
       fragP->fr_opcode[0] = fragP->fr_opcode[0] << 6;
-      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0c0)
-       fragP->fr_opcode[0] |= disp & 0x1f;
-      else
-       fragP->fr_opcode[0] |= value & 0x1f;
+      fragP->fr_opcode[0] |= value & 0x1f;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS9):
+      /* For a PC-relative offset, use the displacement with a -1 correction
+         to take into account the additional byte of the insn.  */
+      if (fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+        value = disp - 1;
+      /* fall through  */
+
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS9):
       fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
       fragP->fr_opcode[0] |= 0xE0;
-      fix_new (fragP, fragP->fr_fix, 1,
-              fragP->fr_symbol, fragP->fr_offset, 0, BFD_RELOC_8);
+      fragP->fr_opcode[0] |= (value >> 8) & 1;
+      fragP->fr_opcode[1] = value;
       fragP->fr_fix += 1;
       break;
 
+    case ENCODE_RELAX (STATE_INDEXED_PCREL, STATE_BITS16):
     case ENCODE_RELAX (STATE_INDEXED_OFFSET, STATE_BITS16):
       fragP->fr_opcode[0] = (fragP->fr_opcode[0] << 3);
       fragP->fr_opcode[0] |= 0xe2;
-      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa)
+      if ((fragP->fr_opcode[0] & 0x0ff) == 0x0fa
+          && fragP->fr_symbol != 0
+          && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
        {
          fixp = fix_new (fragP, fragP->fr_fix, 2,
                          fragP->fr_symbol, fragP->fr_offset,
                          1, BFD_RELOC_16_PCREL);
-         fixp->fx_pcrel_adjust = 2;
        }
       else
        {
@@ -2845,7 +3040,9 @@ md_estimate_size_before_relax (fragP, segment)
   if (RELAX_LENGTH (fragP->fr_subtype) == STATE_UNDF)
     {
       if (S_GET_SEGMENT (fragP->fr_symbol) != segment
-         || !relaxable_symbol (fragP->fr_symbol))
+         || !relaxable_symbol (fragP->fr_symbol)
+          || (segment != absolute_section
+              && RELAX_STATE (fragP->fr_subtype) == STATE_INDEXED_OFFSET))
        {
          /* Non-relaxable cases.  */
          int old_fr_fix;
@@ -2897,13 +3094,46 @@ md_estimate_size_before_relax (fragP, segment)
            case STATE_INDEXED_OFFSET:
              assert (current_architecture & cpu6812);
 
-             /* Switch the indexed operation to 16-bit mode.  */
-             fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
-             fragP->fr_opcode[0] |= 0xe2;
-             fragP->fr_fix++;
-             fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-                      fragP->fr_offset, 0, BFD_RELOC_16);
-             fragP->fr_fix++;
+              if (fragP->fr_symbol
+                  && S_GET_SEGMENT (fragP->fr_symbol) == absolute_section)
+                {
+                   fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_OFFSET,
+                                                     STATE_BITS5);
+                   /* Return the size of the variable part of the frag. */
+                   return md_relax_table[fragP->fr_subtype].rlx_length;
+                }
+              else
+                {
+                   /* Switch the indexed operation to 16-bit mode.  */
+                   fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
+                   fragP->fr_opcode[0] |= 0xe2;
+                   fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
+                            fragP->fr_offset, 0, BFD_RELOC_16);
+                   fragP->fr_fix += 2;
+                }
+             break;
+
+           case STATE_INDEXED_PCREL:
+             assert (current_architecture & cpu6812);
+
+              if (fragP->fr_symbol
+                  && S_GET_SEGMENT (fragP->fr_symbol) == absolute_section)
+                {
+                   fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_PCREL,
+                                                     STATE_BITS5);
+                   /* Return the size of the variable part of the frag. */
+                   return md_relax_table[fragP->fr_subtype].rlx_length;
+                }
+              else
+                {
+                   fixS* fixp;
+
+                   fragP->fr_opcode[0] = fragP->fr_opcode[0] << 3;
+                   fragP->fr_opcode[0] |= 0xe2;
+                   fixp = fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
+                                   fragP->fr_offset, 1, BFD_RELOC_16_PCREL);
+                   fragP->fr_fix += 2;
+                }
              break;
 
            case STATE_XBCC_BRANCH:
@@ -2969,6 +3199,13 @@ md_estimate_size_before_relax (fragP, segment)
                                            STATE_BITS5);
          break;
 
+       case STATE_INDEXED_PCREL:
+         assert (current_architecture & cpu6812);
+
+         fragP->fr_subtype = ENCODE_RELAX (STATE_INDEXED_PCREL,
+                                           STATE_BITS5);
+         break;
+
        case STATE_XBCC_BRANCH:
          assert (current_architecture & cpu6812);
 
@@ -2996,16 +3233,10 @@ int
 tc_m68hc11_force_relocation (fixP)
      fixS * fixP;
 {
-  switch (fixP->fx_r_type)
-    {
-    case BFD_RELOC_VTABLE_INHERIT:
-    case BFD_RELOC_VTABLE_ENTRY:
-    case BFD_RELOC_M68HC11_RL_GROUP:
-      return 1;
+  if (fixP->fx_r_type == BFD_RELOC_M68HC11_RL_GROUP)
+    return 1;
 
-    default:
-      return 0;
-    }
+  return generic_force_reloc (fixP);
 }
 
 /* Here we decide which fixups can be adjusted to make them relative
@@ -3017,23 +3248,24 @@ int
 tc_m68hc11_fix_adjustable (fixP)
      fixS *fixP;
 {
-  /* Prevent all adjustments to global symbols.  */
-  if (! relaxable_symbol (fixP->fx_addsy))
-    return 0;
-
   switch (fixP->fx_r_type)
     {
       /* For the linker relaxation to work correctly, these relocs
          need to be on the symbol itself.  */
     case BFD_RELOC_16:
-    case BFD_RELOC_LO16:
     case BFD_RELOC_M68HC11_RL_JUMP:
     case BFD_RELOC_M68HC11_RL_GROUP:
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
+    case BFD_RELOC_32:
+
+      /* The memory bank addressing translation also needs the original
+         symbol.  */
+    case BFD_RELOC_M68HC11_LO16:
+    case BFD_RELOC_M68HC11_PAGE:
+    case BFD_RELOC_M68HC11_24:
       return 0;
 
-    case BFD_RELOC_32:
     default:
       return 1;
     }
@@ -3052,23 +3284,9 @@ md_apply_fix3 (fixP, valP, seg)
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
 
-  else if (fixP->fx_pcrel)
-    ;
-
-  else
-    {
-      value = fixP->fx_offset;
-
-      if (fixP->fx_subsy != (symbolS *) NULL)
-       {
-         if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
-           value -= S_GET_VALUE (fixP->fx_subsy);
-         else
-           /* We don't actually support subtracting a symbol.  */
-           as_bad_where (fixP->fx_file, fixP->fx_line,
-                         _("Expression too complex."));
-       }
-    }
+  /* We don't actually support subtracting a symbol.  */
+  if (fixP->fx_subsy != (symbolS *) NULL)
+    as_bad_where (fixP->fx_file, fixP->fx_line, _("Expression too complex."));
 
   op_type = fixP->fx_r_type;
 
@@ -3153,16 +3371,14 @@ md_apply_fix3 (fixP, valP, seg)
       as_fatal (_("Line %d: unknown relocation type: 0x%x."),
                fixP->fx_line, fixP->fx_r_type);
     }
-
-  /* Are we finished with this relocation now?  */
-  if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
-    fixP->fx_done = 1;
 }
 
 /* Set the ELF specific flags.  */
 void
 m68hc11_elf_final_processing ()
 {
+  if (current_architecture & cpu6812s)
+    elf_flags |= EF_M68HCS12_MACH;
   elf_elfheader (stdoutput)->e_flags &= ~EF_M68HC11_ABI;
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
 }
This page took 0.031515 seconds and 4 git commands to generate.