* config/tc-m68k.c (struct label_line): Define.
[deliverable/binutils-gdb.git] / gas / config / tc-m68k.c
index 660cfc23bdafd21d0e96ffcd4213dd4e06fc4253..1e82c90695b91ec73b6195972c34721fb045e01f 100644 (file)
@@ -1,5 +1,6 @@
 /* tc-m68k.c -- Assemble for the m68k family
-   Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1987, 91, 92, 93, 94, 95, 96, 1997
+   Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -19,7 +20,6 @@
    02111-1307, USA.  */
 
 #include <ctype.h>
-#define  NO_RELOC 0
 #include "as.h"
 #include "obstack.h"
 #include "subsegs.h"
 #include "opcode/m68k.h"
 #include "m68k-parse.h"
 
-/* This array holds the chars that always start a comment.  If the
-   pre-processor is disabled, these aren't very useful */
-#if defined (OBJ_ELF) || defined (TE_DELTA)
-const char comment_chars[] = "|#";
+/* This string holds the chars that always start a comment.  If the
+   pre-processor is disabled, these aren't very useful.  The macro
+   tc_comment_chars points to this.  We use this, rather than the
+   usual comment_chars, so that the --bitwise-or option will work.  */
+#if (defined (OBJ_ELF) && ! defined (TE_PSOS) && ! defined (TE_LINUX)) || defined (TE_DELTA)
+const char *m68k_comment_chars = "|#";
 #else
-const char comment_chars[] = "|";
+const char *m68k_comment_chars = "|";
 #endif
 
 /* This array holds the chars that only start a comment at the beginning of
@@ -62,7 +64,8 @@ const int md_reloc_size = 8;  /* Size of relocation record */
 
 /* Are we trying to generate PIC code?  If so, absolute references
    ought to be made into linkage table references or pc-relative
-   references.  */
+   references.  Not implemented.  For ELF there are other means 
+   to denote pic relocations.  */
 int flag_want_pic;
 
 static int flag_short_refs;    /* -l option */
@@ -74,6 +77,9 @@ int flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
 int flag_reg_prefix_optional;
 #endif
 
+/* Whether --register-prefix-optional was used on the command line.  */
+static int reg_prefix_optional_seen;
+
 /* The floating point coprocessor to use by default.  */
 static enum m68k_register m68k_float_copnum = COP1;
 
@@ -90,6 +96,34 @@ static int m68k_quick = 1;
    be 32 bits.  */
 static int m68k_rel32 = 1;
 
+/* This is non-zero if m68k_rel32 was set from the command line.  */
+static int m68k_rel32_from_cmdline;
+
+/* The default width to use for an index register when using a base
+   displacement.  */
+static enum m68k_size m68k_index_width_default = SIZE_LONG;
+
+/* We want to warn if any text labels are misaligned.  In order to get
+   the right line number, we need to record the line number for each
+   label.  */
+
+struct label_line
+{
+  struct label_line *next;
+  symbolS *label;
+  char *file;
+  unsigned int line;
+  int text;
+};
+
+/* The list of labels.  */
+
+static struct label_line *labels;
+
+/* The current label.  */
+
+static struct label_line *current_label;
+
 /* Its an arbitrary name:  This means I don't approve of it */
 /* See flames below */
 static struct obstack robyn;
@@ -155,6 +189,11 @@ static const enum m68k_register m68060_control_regs[] = {
   USP, VBR, URP, SRP, PCR,
   0
 };
+static const enum m68k_register mcf5200_control_regs[] = {
+  CACR, TC, ITT0, ITT1, DTT0, DTT1, VBR, ROMBAR, 
+  RAMBAR0, RAMBAR1, MBAR,
+  0
+};
 #define cpu32_control_regs m68010_control_regs
 
 static const enum m68k_register *control_regs;
@@ -199,11 +238,16 @@ struct m68k_it
         significance of some values (in the branch instruction, for
         example).  */
       int pcrel_fix;
+#ifdef OBJ_ELF
+      /* Whether this expression needs special pic relocation, and if
+        so, which.  */
+      enum pic_relocation pic_reloc;
+#endif
     }
   reloc[5];                    /* Five is enough??? */
 };
 
-#define cpu_of_arch(x)         ((x) & m68000up)
+#define cpu_of_arch(x)         ((x) & (m68000up|mcf5200))
 #define float_of_arch(x)       ((x) & mfloat)
 #define mmu_of_arch(x)         ((x) & mmmu)
 
@@ -244,7 +288,7 @@ add_fix (width, exp, pc_rel, pc_fix)
      int pc_rel;
      int pc_fix;
 {
-  the_ins.reloc[the_ins.nrel].n = (((width)=='B')
+  the_ins.reloc[the_ins.nrel].n = ((width == 'B' || width == '3')
                                   ? (the_ins.numo*2-1)
                                   : (((width)=='b')
                                      ? (the_ins.numo*2+1)
@@ -252,6 +296,9 @@ add_fix (width, exp, pc_rel, pc_fix)
   the_ins.reloc[the_ins.nrel].exp = exp->exp;
   the_ins.reloc[the_ins.nrel].wid = width;
   the_ins.reloc[the_ins.nrel].pcrel_fix = pc_fix;
+#ifdef OBJ_ELF
+  the_ins.reloc[the_ins.nrel].pic_reloc = exp->pic_reloc;
+#endif
   the_ins.reloc[the_ins.nrel++].pcrel = pc_rel;
 }
 
@@ -315,36 +362,39 @@ static int current_architecture;
 struct m68k_cpu {
   unsigned long arch;
   const char *name;
+  int alias;
 };
 
 static const struct m68k_cpu archs[] = {
-  { m68000, "68000" },
-  { m68010, "68010" },
-  { m68020, "68020" },
-  { m68030, "68030" },
-  { m68040, "68040" },
-  { m68060, "68060" },
-  { cpu32,  "cpu32" },
-  { m68881, "68881" },
-  { m68851, "68851" },
+  { m68000, "68000", 0 },
+  { m68010, "68010", 0 },
+  { m68020, "68020", 0 },
+  { m68030, "68030", 0 },
+  { m68040, "68040", 0 },
+  { m68060, "68060", 0 },
+  { cpu32,  "cpu32", 0 },
+  { m68881, "68881", 0 },
+  { m68851, "68851", 0 },
+  { mcf5200, "5200", 0 },
   /* Aliases (effectively, so far as gas is concerned) for the above
      cpus.  */
-  { m68020, "68k" },
-  { m68000, "68302" },
-  { m68000, "68008" },
-  { m68000, "68ec000" },
-  { m68000, "68hc000" },
-  { m68000, "68hc001" },
-  { m68020, "68ec020" },
-  { m68030, "68ec030" },
-  { m68040, "68ec040" },
-  { cpu32,  "68330" },
-  { cpu32,  "68331" },
-  { cpu32,  "68332" },
-  { cpu32,  "68333" },
-  { cpu32,  "68340" },
-  { cpu32,  "68360" },
-  { m68881, "68882" },
+  { m68020, "68k", 1 },
+  { m68000, "68302", 1 },
+  { m68000, "68008", 1 },
+  { m68000, "68ec000", 1 },
+  { m68000, "68hc000", 1 },
+  { m68000, "68hc001", 1 },
+  { m68020, "68ec020", 1 },
+  { m68030, "68ec030", 1 },
+  { m68040, "68ec040", 1 },
+  { m68060, "68ec060", 1 },
+  { cpu32,  "68330", 1 },
+  { cpu32,  "68331", 1 },
+  { cpu32,  "68332", 1 },
+  { cpu32,  "68333", 1 },
+  { cpu32,  "68340", 1 },
+  { cpu32,  "68360", 1 },
+  { m68881, "68882", 1 },
 };
 
 static const int n_archs = sizeof (archs) / sizeof (archs[0]);
@@ -427,12 +477,14 @@ const pseudo_typeS md_pseudo_table[] =
   {"even", s_even, 0},
   {"skip", s_space, 0},
   {"proc", s_proc, 0},
-#ifdef TE_SUN3
+#if defined (TE_SUN3) || defined (OBJ_ELF)
   {"align", s_align_bytes, 0},
 #endif
 #ifdef OBJ_ELF
   {"swbeg", s_ignore, 0},
 #endif
+  {"extend", float_cons, 'x'},
+  {"ldouble", float_cons, 'x'},
 
   /* The following pseudo-ops are supported for MRI compatibility.  */
   {"chip", s_chip, 0},
@@ -497,7 +549,11 @@ CONST pseudo_typeS mote_pseudo_table[] =
   {"dsb", s_space, 1},
 
   {"xdef", s_globl, 0},
+#ifdef OBJ_ELF
+  {"align", s_align_bytes, 0},
+#else
   {"align", s_align_ptwo, 0},
+#endif
 #ifdef M68KCOFF
   {"sect", obj_coff_section, 0},
   {"section", obj_coff_section, 0},
@@ -582,6 +638,145 @@ tc_coff_fix2rtype (fixP)
 
 #endif
 
+#ifdef OBJ_ELF
+
+/* Compute the relocation code for a fixup of SIZE bytes, using pc
+   relative relocation if PCREL is non-zero.  PIC says whether a special
+   pic relocation was requested.  */
+
+static bfd_reloc_code_real_type get_reloc_code
+  PARAMS ((int, int, enum pic_relocation));
+
+static bfd_reloc_code_real_type
+get_reloc_code (size, pcrel, pic)
+     int size;
+     int pcrel;
+     enum pic_relocation pic;
+{
+  switch (pic)
+    {
+    case pic_got_pcrel:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_GOT_PCREL;
+       case 2:
+         return BFD_RELOC_16_GOT_PCREL;
+       case 4:
+         return BFD_RELOC_32_GOT_PCREL;
+       }
+      break;
+
+    case pic_got_off:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_GOTOFF;
+       case 2:
+         return BFD_RELOC_16_GOTOFF;
+       case 4:
+         return BFD_RELOC_32_GOTOFF;
+       }
+      break;
+
+    case pic_plt_pcrel:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_PLT_PCREL;
+       case 2:
+         return BFD_RELOC_16_PLT_PCREL;
+       case 4:
+         return BFD_RELOC_32_PLT_PCREL;
+       }
+      break;
+
+    case pic_plt_off:
+      switch (size)
+       {
+       case 1:
+         return BFD_RELOC_8_PLTOFF;
+       case 2:
+         return BFD_RELOC_16_PLTOFF;
+       case 4:
+         return BFD_RELOC_32_PLTOFF;
+       }
+      break;
+
+    case pic_none:
+      if (pcrel)
+       {
+         switch (size)
+           {
+           case 1:
+             return BFD_RELOC_8_PCREL;
+           case 2:
+             return BFD_RELOC_16_PCREL;
+           case 4:
+             return BFD_RELOC_32_PCREL;
+           }
+       }
+      else
+       {
+         switch (size)
+           {
+           case 1:
+             return BFD_RELOC_8;
+           case 2:
+             return BFD_RELOC_16;
+           case 4:
+             return BFD_RELOC_32;
+           }
+       }
+    }
+
+  as_bad ("Can not do %d byte %s%srelocation", size,
+         pcrel ? "pc-relative " : "",
+         pic == pic_none ? "" : "pic ");
+  return BFD_RELOC_NONE;
+}
+
+/* Here we decide which fixups can be adjusted to make them relative
+   to the beginning of the section instead of the symbol.  Basically
+   we need to make sure that the dynamic relocations are done
+   correctly, so in some cases we force the original symbol to be
+   used.  */
+int
+tc_m68k_fix_adjustable (fixP)
+     fixS *fixP;
+{
+  /* Prevent all adjustments to global symbols. */
+  if (S_IS_EXTERNAL (fixP->fx_addsy))
+    return 0;
+
+  /* adjust_reloc_syms doesn't know about the GOT */
+  switch (fixP->fx_r_type)
+    {
+    case BFD_RELOC_8_GOT_PCREL:
+    case BFD_RELOC_16_GOT_PCREL:
+    case BFD_RELOC_32_GOT_PCREL:
+    case BFD_RELOC_8_GOTOFF:
+    case BFD_RELOC_16_GOTOFF:
+    case BFD_RELOC_32_GOTOFF:
+    case BFD_RELOC_8_PLT_PCREL:
+    case BFD_RELOC_16_PLT_PCREL:
+    case BFD_RELOC_32_PLT_PCREL:
+    case BFD_RELOC_8_PLTOFF:
+    case BFD_RELOC_16_PLTOFF:
+    case BFD_RELOC_32_PLTOFF:
+      return 0;
+
+    default:
+      return 1;
+    }
+}
+
+#else /* !OBJ_ELF */
+
+#define get_reloc_code(SIZE,PCREL,OTHER) NO_RELOC
+
+#endif /* OBJ_ELF */
+
 #ifdef BFD_ASSEMBLER
 
 arelent *
@@ -592,31 +787,91 @@ tc_gen_reloc (section, fixp)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  if (fixP->fx_tcbit)
+  if (fixp->fx_tcbit)
     abort ();
 
-#define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
-  switch (F (fixp->fx_size, fixp->fx_pcrel))
+  if (fixp->fx_r_type != BFD_RELOC_NONE)
     {
+      code = fixp->fx_r_type;
+
+      /* Since DIFF_EXPR_OK is defined in tc-m68k.h, it is possible
+         that fixup_segment converted a non-PC relative reloc into a
+         PC relative reloc.  In such a case, we need to convert the
+         reloc code.  */
+      if (fixp->fx_pcrel)
+       {
+         switch (code)
+           {
+           case BFD_RELOC_8:
+             code = BFD_RELOC_8_PCREL;
+             break;
+           case BFD_RELOC_16:
+             code = BFD_RELOC_16_PCREL;
+             break;
+           case BFD_RELOC_32:
+             code = BFD_RELOC_32_PCREL;
+             break;
+           case BFD_RELOC_8_PCREL:
+           case BFD_RELOC_16_PCREL:
+           case BFD_RELOC_32_PCREL:
+           case BFD_RELOC_8_GOT_PCREL:
+           case BFD_RELOC_16_GOT_PCREL:
+           case BFD_RELOC_32_GOT_PCREL:
+           case BFD_RELOC_8_GOTOFF:
+           case BFD_RELOC_16_GOTOFF:
+           case BFD_RELOC_32_GOTOFF:
+           case BFD_RELOC_8_PLT_PCREL:
+           case BFD_RELOC_16_PLT_PCREL:
+           case BFD_RELOC_32_PLT_PCREL:
+           case BFD_RELOC_8_PLTOFF:
+           case BFD_RELOC_16_PLTOFF:
+           case BFD_RELOC_32_PLTOFF:
+             break;
+           default:
+             as_bad_where (fixp->fx_file, fixp->fx_line,
+                           "Cannot make %s relocation PC relative",
+                           bfd_get_reloc_code_name (code));
+           }
+       }
+    }
+  else
+    {
+#define F(SZ,PCREL)            (((SZ) << 1) + (PCREL))
+      switch (F (fixp->fx_size, fixp->fx_pcrel))
+       {
 #define MAP(SZ,PCREL,TYPE)     case F(SZ,PCREL): code = (TYPE); break
-      MAP (1, 0, BFD_RELOC_8);
-      MAP (2, 0, BFD_RELOC_16);
-      MAP (4, 0, BFD_RELOC_32);
-      MAP (1, 1, BFD_RELOC_8_PCREL);
-      MAP (2, 1, BFD_RELOC_16_PCREL);
-      MAP (4, 1, BFD_RELOC_32_PCREL);
-    default:
-      abort ();
+         MAP (1, 0, BFD_RELOC_8);
+         MAP (2, 0, BFD_RELOC_16);
+         MAP (4, 0, BFD_RELOC_32);
+         MAP (1, 1, BFD_RELOC_8_PCREL);
+         MAP (2, 1, BFD_RELOC_16_PCREL);
+         MAP (4, 1, BFD_RELOC_32_PCREL);
+       default:
+         abort ();
+       }
     }
+#undef F
+#undef MAP
 
   reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
   assert (reloc != 0);
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+#ifndef OBJ_ELF
   if (fixp->fx_pcrel)
     reloc->addend = fixp->fx_addnumber;
   else
     reloc->addend = 0;
+#else
+  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));
+#endif
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
   assert (reloc->howto != 0);
@@ -766,12 +1021,10 @@ m68k_ip (instring)
       /* If we didn't get the right number of ops, or we have no
         common model with this pattern then reject this pattern. */
 
+      ok_arch |= opcode->m_arch;
       if (opsfound != opcode->m_opnum
          || ((opcode->m_arch & current_architecture) == 0))
-       {
-         ++losing;
-         ok_arch |= opcode->m_arch;
-       }
+       ++losing;
       else
        {
          for (s = opcode->m_operands, opP = &the_ins.operands[0];
@@ -822,6 +1075,96 @@ m68k_ip (instring)
                    }
                  break;
 
+               case '<':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case ADEC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   default:
+                     break;
+                   }
+                 break;
+
+               case '>':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case FPREG:
+                   case CONTROL:
+                   case IMMED:
+                   case AINC:
+                   case REGLST:
+                     losing++;
+                     break;
+                   case ABSL:
+                     break;
+                   default:
+                     if (opP->reg == PC
+                         || opP->reg == ZPC)
+                       losing++;
+                     break;
+                   }
+                 break;
+
+               case 'm':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case AINDR:
+                   case AINC:
+                   case ADEC:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'n':
+                 switch (opP->mode)
+                   {
+                   case DISP:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'o':
+                 switch (opP->mode)
+                   {
+                   case BASE:
+                   case ABSL:
+                   case IMMED:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
+               case 'p':
+                 switch (opP->mode)
+                   {
+                   case DREG:
+                   case AREG:
+                   case AINDR:
+                   case AINC:
+                   case ADEC:
+                   case DISP:
+                     break;
+                   default:
+                     losing++;
+                   }
+                  break;
+
                case '#':
                  if (opP->mode != IMMED)
                    losing++;
@@ -830,11 +1173,21 @@ m68k_ip (instring)
                           && (opP->disp.exp.X_op != O_constant
                               || ! isbyte (opP->disp.exp.X_add_number)))
                    losing++;
+                 else if (s[1] == 'B'
+                          && ! isvar (&opP->disp)
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! issbyte (opP->disp.exp.X_add_number)))
+                   losing++;
                  else if (s[1] == 'w'
                           && ! isvar (&opP->disp)
                           && (opP->disp.exp.X_op != O_constant
                               || ! isword (opP->disp.exp.X_add_number)))
                    losing++;
+                 else if (s[1] == 'W'
+                          && ! isvar (&opP->disp)
+                          && (opP->disp.exp.X_op != O_constant
+                              || ! issword (opP->disp.exp.X_add_number)))
+                   losing++;
                  break;
 
                case '^':
@@ -1147,7 +1500,9 @@ m68k_ip (instring)
                  break;
 
                case 'O':
-                 if (opP->mode != DREG && opP->mode != IMMED)
+                 if (opP->mode != DREG
+                     && opP->mode != IMMED
+                     && opP->mode != ABSL)
                    losing++;
                  break;
 
@@ -1328,7 +1683,7 @@ m68k_ip (instring)
              && !(ok_arch & current_architecture))
            {
              char buf[200], *cp;
-             int len;
+
              strcpy (buf,
                      "invalid instruction for this architecture; needs ");
              cp = buf + strlen (buf);
@@ -1355,7 +1710,8 @@ m68k_ip (instring)
                    for (idx = 0; idx < sizeof (archs) / sizeof (archs[0]);
                         idx++)
                      {
-                       if (archs[idx].arch & ok_arch)
+                       if ((archs[idx].arch & ok_arch)
+                           && ! archs[idx].alias)
                          {
                            if (got_one)
                              {
@@ -1369,8 +1725,7 @@ m68k_ip (instring)
                      }
                  }
                }
-             len = cp - buf + 1;
-             cp = malloc (len);
+             cp = xmalloc (strlen (buf) + 1);
              strcpy (cp, buf);
              the_ins.error = cp;
            }
@@ -1408,6 +1763,12 @@ m68k_ip (instring)
        case '?':
        case '/':
        case '`':
+       case '<':
+       case '>':
+       case 'm':
+       case 'n':
+       case 'o':
+       case 'p':
 #ifndef NO_68851
        case '|':
 #endif
@@ -1435,6 +1796,12 @@ m68k_ip (instring)
                  addword (nextword);
                  baseo = 0;
                  break;
+               case 'W':
+                 if (!issword (nextword))
+                   opP->error = "operand out of range";
+                 addword (nextword);
+                 baseo = 0;
+                 break;
                case 'l':
                  addword (nextword >> 16);
                  addword (nextword);
@@ -1552,6 +1919,9 @@ m68k_ip (instring)
                           && cpu_of_arch (current_architecture) >= m68020)
                          || opP->disp.size == SIZE_LONG)))
                {
+                 if (cpu_of_arch (current_architecture) < m68020)
+                   opP->error =
+                     "displacement too large for this architecture; needs 68020 or higher";
                  if (opP->reg == PC)
                    tmpreg = 0x3B;      /* 7.3 */
                  else
@@ -1560,16 +1930,24 @@ m68k_ip (instring)
                    {
                      if (opP->reg == PC)
                        {
-#if 0
-                         addword (0x0170);
-                         add_fix ('l', &opP->disp, 1, 2);
-                         addword (0), addword (0);
-#else
-                         add_frag (adds (&opP->disp),
-                                   offs (&opP->disp),
-                                   TAB (PCLEA, SZ_UNDEF));
+                         if (opP->disp.size == SIZE_LONG
+#ifdef OBJ_ELF
+                             /* If the displacement needs pic
+                                relocation it cannot be relaxed.  */
+                             || opP->disp.pic_reloc != pic_none
 #endif
-                         break;
+                             )
+                           {
+                             addword (0x0170);
+                             add_fix ('l', &opP->disp, 1, 2);
+                           }
+                         else
+                           {
+                             add_frag (adds (&opP->disp),
+                                       offs (&opP->disp),
+                                       TAB (PCLEA, SZ_UNDEF));
+                             break;
+                           }
                        }
                      else
                        {
@@ -1642,17 +2020,18 @@ m68k_ip (instring)
                {
                  nextword |= (opP->index.reg - DATA) << 12;
 
-                 if (opP->index.size == SIZE_UNSPEC
-                     || opP->index.size == SIZE_LONG)
+                 if (opP->index.size == SIZE_LONG
+                     || (opP->index.size == SIZE_UNSPEC
+                         && m68k_index_width_default == SIZE_LONG))
                    nextword |= 0x800;
 
-                 if (cpu_of_arch (current_architecture) < m68020)
+                 if ((opP->index.scale != 1 
+                      && cpu_of_arch (current_architecture) < m68020)
+                     || (opP->index.scale == 8 
+                         && current_architecture == mcf5200))
                    {
-                     if (opP->index.scale != 1)
-                       {
-                         opP->error =
-                           "scale factor invalid on this architecture; needs 68020 or higher";
-                       }
+                     opP->error =
+                       "scale factor invalid on this architecture; needs cpu32 or 68020 or higher";
                    }
 
                  switch (opP->index.scale)
@@ -1715,8 +2094,20 @@ m68k_ip (instring)
                      else if (siz1 == SIZE_UNSPEC
                               && opP->reg == PC
                               && isvar (&opP->disp)
-                              && subs (&opP->disp) == NULL)
+                              && subs (&opP->disp) == NULL
+#ifdef OBJ_ELF
+                              /* If the displacement needs pic
+                                 relocation it cannot be relaxed.  */
+                              && opP->disp.pic_reloc == pic_none
+#endif
+                              )
                        {
+                         /* The code in md_convert_frag_1 needs to be
+                             able to adjust nextword.  Call frag_grow
+                             to ensure that we have enough space in
+                             the frag obstack to make all the bytes
+                             contiguous.  */
+                         frag_grow (14);
                          nextword += baseo & 0xff;
                          addword (nextword);
                          add_frag (adds (&opP->disp), offs (&opP->disp),
@@ -1778,6 +2169,8 @@ m68k_ip (instring)
              /* Figure out innner displacement stuff */
              if (opP->mode == POST || opP->mode == PRE)
                {
+                 if (cpu_of_arch (current_architecture) & cpu32)
+                   opP->error = "invalid operand mode for this architecture; needs 68020 or higher";
                  switch (siz2)
                    {
                    case SIZE_UNSPEC:
@@ -1851,6 +2244,11 @@ m68k_ip (instring)
                  if (isvar (&opP->disp)
                      && !subs (&opP->disp)
                      && adds (&opP->disp)
+#ifdef OBJ_ELF
+                     /* If the displacement needs pic relocation it
+                        cannot be relaxed.  */
+                     && opP->disp.pic_reloc == pic_none
+#endif
                      && S_GET_SEGMENT (adds (&opP->disp)) == now_seg
                      && cpu_of_arch (current_architecture) >= m68020
                      && !flag_long_jumps
@@ -1920,7 +2318,15 @@ m68k_ip (instring)
                opP->error = "out of range";
              insop (tmpreg, opcode);
              if (isvar (&opP->disp))
-               the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+               the_ins.reloc[the_ins.nrel - 1].n =
+                 (opcode->m_codenum) * 2 + 1;
+             break;
+           case 'B':
+             if (!issbyte (tmpreg))
+               opP->error = "out of range";
+             opcode->m_opcode |= tmpreg;
+             if (isvar (&opP->disp))
+               the_ins.reloc[the_ins.nrel - 1].n = opcode->m_codenum * 2 - 1;
              break;
            case 'w':
              if (!isword (tmpreg))
@@ -1929,6 +2335,13 @@ m68k_ip (instring)
              if (isvar (&opP->disp))
                the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
              break;
+           case 'W':
+             if (!issword (tmpreg))
+               opP->error = "out of range";
+             insop (tmpreg, opcode);
+             if (isvar (&opP->disp))
+               the_ins.reloc[the_ins.nrel - 1].n = (opcode->m_codenum) * 2;
+             break;
            case 'l':
              /* Because of the way insop works, we put these two out
                 backwards.  */
@@ -1983,6 +2396,13 @@ m68k_ip (instring)
              if (subs (&opP->disp))    /* We can't relax it */
                goto long_branch;
 
+#ifdef OBJ_ELF
+             /* If the displacement needs pic relocation it cannot be
+                relaxed.  */
+             if (opP->disp.pic_reloc != pic_none)
+               goto long_branch;
+#endif
+
              /* This could either be a symbol, or an absolute
                 address.  No matter, the frag hacking will finger it
                 out.  Not quite: it can't switch from BRANCH to
@@ -2131,6 +2551,18 @@ m68k_ip (instring)
            case PCR:
              tmpreg = 0x808;
              break;
+            case ROMBAR:
+             tmpreg = 0xC00;
+             break;
+           case RAMBAR0:
+             tmpreg = 0xC04;
+             break;
+           case RAMBAR1:
+             tmpreg = 0xC05;
+             break;
+           case MBAR:
+             tmpreg = 0xC0F;
+             break;
            default:
              abort ();
            }
@@ -2510,6 +2942,7 @@ install_operand (mode, val)
       break;
     case 'b':
     case 'w':
+    case 'W':
     case 'l':
       break;
     case 'e':
@@ -2711,29 +3144,54 @@ static const struct init_entry init_table[] =
   { "ccr", CCR },
   { "cc", CCR },
 
-  { "usp", USP },
-  { "isp", ISP },
-  { "sfc", SFC },
+  /* control registers */
+  { "sfc", SFC },              /* Source Function Code */
   { "sfcr", SFC },
-  { "dfc", DFC },
+  { "dfc", DFC },              /* Destination Function Code */
   { "dfcr", DFC },
-  { "cacr", CACR },
-  { "caar", CAAR },
-
-  { "vbr", VBR },
-
-  { "msp", MSP },
-  { "itt0", ITT0 },
-  { "itt1", ITT1 },
-  { "dtt0", DTT0 },
-  { "dtt1", DTT1 },
-  { "mmusr", MMUSR },
-  { "tc", TC },
-  { "srp", SRP },
-  { "urp", URP },
+  { "cacr", CACR },            /* Cache Control Register */
+  { "caar", CAAR },            /* Cache Address Register */
+
+  { "usp", USP },              /* User Stack Pointer */
+  { "vbr", VBR },              /* Vector Base Register */
+  { "msp", MSP },              /* Master Stack Pointer */
+  { "isp", ISP },              /* Interrupt Stack Pointer */
+
+  { "itt0", ITT0 },            /* Instruction Transparent Translation Reg 0 */
+  { "itt1", ITT1 },            /* Instruction Transparent Translation Reg 1 */
+  { "dtt0", DTT0 },            /* Data Transparent Translation Register 0 */
+  { "dtt1", DTT1 },            /* Data Transparent Translation Register 1 */
+
+  /* 68ec040 versions of same */
+  { "iacr0", ITT0 },           /* Instruction Access Control Register 0 */
+  { "iacr1", ITT1 },           /* Instruction Access Control Register 0 */
+  { "dacr0", DTT0 },           /* Data Access Control Register 0 */
+  { "dacr1", DTT1 },           /* Data Access Control Register 0 */
+
+  /* mcf5200 versions of same.  The ColdFire programmer's reference
+     manual indicated that the order is 2,3,0,1, but Ken Rose
+     <rose@netcom.com> says that 0,1,2,3 is the correct order.  */
+  { "acr0", ITT0 },            /* Access Control Unit 0 */
+  { "acr1", ITT1 },            /* Access Control Unit 1 */
+  { "acr2", DTT0 },            /* Access Control Unit 2 */
+  { "acr3", DTT1 },            /* Access Control Unit 3 */
+
+  { "tc", TC },                        /* MMU Translation Control Register */
+  { "tcr", TC },
+
+  { "mmusr", MMUSR },          /* MMU Status Register */
+  { "srp", SRP },              /* User Root Pointer */
+  { "urp", URP },              /* Supervisor Root Pointer */
+
   { "buscr", BUSCR },
   { "pcr", PCR },
 
+  { "rombar", ROMBAR },                /* ROM Base Address Register */
+  { "rambar0", RAMBAR0 },      /* ROM Base Address Register */
+  { "rambar1", RAMBAR1 },      /* ROM Base Address Register */
+  { "mbar", MBAR },            /* Module Base Address Register */
+  /* end of control registers */
+
   { "ac", AC },
   { "bc", BC },
   { "cal", CAL },
@@ -2873,6 +3331,13 @@ md_assemble (str)
       return;
     }
 
+  /* If there is a current label, record that it marks an instruction.  */
+  if (current_label != NULL)
+    {
+      current_label->text = 1;
+      current_label = NULL;
+    }
+
   if (the_ins.nfrag == 0)
     {
       /* No frag hacking involved; just put it out */
@@ -2896,7 +3361,7 @@ md_assemble (str)
              n = 1;
              break;
            case '3':
-             n = 2;
+             n = 1;
              break;
            case 'w':
              n = 2;
@@ -2915,8 +3380,11 @@ md_assemble (str)
                              n,
                              &the_ins.reloc[m].exp,
                              the_ins.reloc[m].pcrel,
-                             NO_RELOC);
+                             get_reloc_code (n, the_ins.reloc[m].pcrel,
+                                             the_ins.reloc[m].pic_reloc));
          fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
+         if (the_ins.reloc[m].wid == 'B')
+           fixP->fx_signed = 1;
        }
       return;
     }
@@ -2959,7 +3427,8 @@ md_assemble (str)
                              wid,
                              &the_ins.reloc[m].exp,
                              the_ins.reloc[m].pcrel,
-                             NO_RELOC);
+                             get_reloc_code (wid, the_ins.reloc[m].pcrel,
+                                             the_ins.reloc[m].pic_reloc));
          fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
        }
       (void) frag_var (rs_machine_dependent, 10, 0,
@@ -2995,7 +3464,8 @@ md_assemble (str)
                          wid,
                          &the_ins.reloc[m].exp,
                          the_ins.reloc[m].pcrel,
-                         NO_RELOC);
+                         get_reloc_code (wid, the_ins.reloc[m].pcrel,
+                                         the_ins.reloc[m].pic_reloc));
       fixP->fx_pcrel_adjust = the_ins.reloc[m].pcrel_fix;
     }
 }
@@ -3024,7 +3494,8 @@ md_begin ()
     {
       flag_reg_prefix_optional = 1;
       m68k_abspcadd = 1;
-      m68k_rel32 = 0;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 0;
     }
 
   op_hash = hash_new ();
@@ -3143,6 +3614,20 @@ md_begin ()
      */
   alt_notend_table['@'] = 1;
 
+  /* We need to put digits in alt_notend_table to handle
+       bfextu %d0{24:1},%d0
+     */
+  alt_notend_table['0'] = 1;
+  alt_notend_table['1'] = 1;
+  alt_notend_table['2'] = 1;
+  alt_notend_table['3'] = 1;
+  alt_notend_table['4'] = 1;
+  alt_notend_table['5'] = 1;
+  alt_notend_table['6'] = 1;
+  alt_notend_table['7'] = 1;
+  alt_notend_table['8'] = 1;
+  alt_notend_table['9'] = 1;
+
 #ifndef MIT_SYNTAX_ONLY
   /* Insert pseudo ops, these have to go into the opcode table since
      gas expects pseudo ops to start with a dot */
@@ -3162,6 +3647,45 @@ md_begin ()
 #endif
 
   init_regtable ();
+
+#ifdef OBJ_ELF
+  record_alignment (text_section, 2);
+  record_alignment (data_section, 2);
+  record_alignment (bss_section, 2);
+#endif
+}
+
+static void
+select_control_regs ()
+{
+  /* Note which set of "movec" control registers is available.  */
+  switch (cpu_of_arch (current_architecture))
+    {
+    case m68000:
+      control_regs = m68000_control_regs;
+      break;
+    case m68010:
+      control_regs = m68010_control_regs;
+      break;
+    case m68020:
+    case m68030:
+      control_regs = m68020_control_regs;
+      break;
+    case m68040:
+      control_regs = m68040_control_regs;
+      break;
+    case m68060:
+      control_regs = m68060_control_regs;
+      break;
+    case cpu32:
+      control_regs = cpu32_control_regs;
+      break;
+    case mcf5200:
+      control_regs = mcf5200_control_regs;
+      break;
+    default:
+      abort ();
+    }
 }
 
 void
@@ -3228,34 +3752,100 @@ m68k_init_after_args ()
 #endif
 
   /* Note which set of "movec" control registers is available.  */
-  switch (cpu_of_arch (current_architecture))
-    {
-    case m68000:
-      control_regs = m68000_control_regs;
-      break;
-    case m68010:
-      control_regs = m68010_control_regs;
-      break;
-    case m68020:
-    case m68030:
-      control_regs = m68020_control_regs;
-      break;
-    case m68040:
-      control_regs = m68040_control_regs;
-      break;
-    case m68060:
-      control_regs = m68060_control_regs;
-      break;
-    case cpu32:
-      control_regs = cpu32_control_regs;
-      break;
-    default:
-      abort ();
-    }
+  select_control_regs ();
 
   if (cpu_of_arch (current_architecture) < m68020)
     md_relax_table[TAB (PCINDEX, BYTE)].rlx_more = 0;
 }
+\f
+/* This is called when a label is defined.  */
+
+void
+m68k_frob_label (sym)
+     symbolS *sym;
+{
+  struct label_line *n;
+
+  n = (struct label_line *) xmalloc (sizeof *n);
+  n->next = labels;
+  n->label = sym;
+  as_where (&n->file, &n->line);
+  labels = n;
+  current_label = n;
+}
+
+/* This is called when a value that is not an instruction is emitted.  */
+
+void
+m68k_flush_pending_output ()
+{
+  current_label = NULL;
+}
+
+/* This is called at the end of the assembly, when the final value of
+   the label is known.  We warn if this is a text symbol aligned at an
+   odd location.  */
+
+void
+m68k_frob_symbol (sym)
+     symbolS *sym;
+{
+  if ((S_GET_VALUE (sym) & 1) != 0)
+    {
+      struct label_line *l;
+
+      for (l = labels; l != NULL; l = l->next)
+       {
+         if (l->label == sym)
+           {
+             if (l->text)
+               as_warn_where (l->file, l->line,
+                              "text label `%s' aligned to odd boundary",
+                              S_GET_NAME (sym));
+             break;
+           }
+       }
+    }
+}
+\f
+/* This is called if we go in or out of MRI mode because of the .mri
+   pseudo-op.  */
+
+void
+m68k_mri_mode_change (on)
+     int on;
+{
+  if (on)
+    {
+      if (! flag_reg_prefix_optional)
+       {
+         flag_reg_prefix_optional = 1;
+#ifdef REGISTER_PREFIX
+         init_regtable ();
+#endif
+       }
+      m68k_abspcadd = 1;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 0;
+    }
+  else
+    {
+      if (! reg_prefix_optional_seen)
+       {
+#ifdef REGISTER_PREFIX_OPTIONAL
+         flag_reg_prefix_optional = REGISTER_PREFIX_OPTIONAL;
+#else
+         flag_reg_prefix_optional = 0;
+#endif
+#ifdef REGISTER_PREFIX
+         init_regtable ();
+#endif
+       }
+      m68k_abspcadd = 0;
+      if (! m68k_rel32_from_cmdline)
+       m68k_rel32 = 1;
+    }
+}
 
 /* Equal to MAX_PRECISION in atof-ieee.c */
 #define MAX_LITTLENUMS 6
@@ -3348,6 +3938,15 @@ md_apply_fix_2 (fixP, val)
   else
     val &= 0x7fffffff;
 
+#ifdef OBJ_ELF
+  if (fixP->fx_addsy)
+    {
+      memset (buf, 0, fixP->fx_size);
+      fixP->fx_addnumber = val;        /* Remember value for emit_reloc */
+      return;
+    }
+#endif
+
   switch (fixP->fx_size)
     {
       /* The cast to offsetT below are necessary to make code correct for
@@ -3387,7 +3986,7 @@ md_apply_fix_2 (fixP, val)
      like "0xff" for a byte field.  So extend the upper part of the range
      to accept such numbers.  We arbitrarily disallow "-0xff" or "0xff+0xff",
      so that we can do any range checking at all.  */
-  if (!fixP->fx_pcrel)
+  if (! fixP->fx_pcrel && ! fixP->fx_signed)
     upper_limit = upper_limit * 2 + 1;
 
   if ((addressT) val > upper_limit
@@ -3878,13 +4477,27 @@ md_estimate_size_before_relax (fragP, segment)
     {
     case TAB (BCC68000, BYTE):
     case TAB (ABRANCH, BYTE):
-      /* We can't do a short jump to the next instruction,
-          so we force word mode.  */
-      if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0 &&
-         fragP->fr_symbol->sy_frag == fragP->fr_next)
+      /* We can't do a short jump to the next instruction, so in that
+        case we force word mode.  At this point S_GET_VALUE should
+        return the offset of the symbol within its frag.  If the
+        symbol is at the start of a frag, and it is the next frag
+        with any data in it (usually this is just the next frag, but
+        assembler listings may introduce empty frags), we must use
+        word mode.  */
+      if (fragP->fr_symbol && S_GET_VALUE (fragP->fr_symbol) == 0)
        {
-         fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
-         fragP->fr_var += 2;
+         fragS *l;
+
+         for (l = fragP->fr_next;
+              l != fragP->fr_symbol->sy_frag;
+              l = l->fr_next)
+           if (l->fr_fix + l->fr_var != 0)
+             break;
+         if (l == fragP->fr_symbol->sy_frag)
+           {
+             fragP->fr_subtype = TAB (TABTYPE (fragP->fr_subtype), SHORT);
+             fragP->fr_var += 2;
+           }
        }
       break;
     default:
@@ -4189,6 +4802,7 @@ s_even (ignore)
   if (!need_pass_2)            /* Never make frag if expect extra pass. */
     frag_align (temp, (int) temp_fill);
   demand_empty_rest_of_line ();
+  record_alignment (now_seg, temp);
 }
 
 static void
@@ -4200,6 +4814,18 @@ s_proc (ignore)
 \f
 /* Pseudo-ops handled for MRI compatibility.  */
 
+/* This function returns non-zero if the argument is a conditional
+   pseudo-op.  This is called when checking whether a pending
+   alignment is needed.  */
+
+int
+m68k_conditional_pseudoop (pop)
+     pseudo_typeS *pop;
+{
+  return (pop->poc_handler == s_mri_if
+         || pop->poc_handler == s_mri_else);
+}
+
 /* Handle an MRI style chip specification.  */
 
 static void
@@ -4240,6 +4866,9 @@ mri_chip ()
        current_architecture |= m68851;
       *input_line_pointer = c;
     }
+
+  /* Update info about available control registers.  */
+  select_control_regs ();
 }
 
 /* The MRI CHIP pseudo-op.  */
@@ -5718,6 +6347,8 @@ s_mri_until (qual)
 
   input_line_pointer = s;
 
+  pop_mri_control ();
+
   if (flag_mri)
     {
       while (! is_end_of_line[(unsigned char) *input_line_pointer])
@@ -5829,6 +6460,9 @@ s_mri_endw (ignore)
  *     -pic    Indicates PIC.
  *     -k      Indicates PIC.  (Sun 3 only.)
  *
+ *     --bitwise-or
+ *             Permit `|' to be used in expressions.
+ *
  */
 
 #ifdef OBJ_ELF
@@ -5843,6 +6477,16 @@ struct option md_longopts[] = {
 #define OPTION_REGISTER_PREFIX_OPTIONAL (OPTION_MD_BASE + 1)
   {"register-prefix-optional", no_argument, NULL,
      OPTION_REGISTER_PREFIX_OPTIONAL},
+#define OPTION_BITWISE_OR (OPTION_MD_BASE + 2)
+  {"bitwise-or", no_argument, NULL, OPTION_BITWISE_OR},
+#define OPTION_BASE_SIZE_DEFAULT_16 (OPTION_MD_BASE + 3)
+  {"base-size-default-16", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_16},
+#define OPTION_BASE_SIZE_DEFAULT_32 (OPTION_MD_BASE + 4)
+  {"base-size-default-32", no_argument, NULL, OPTION_BASE_SIZE_DEFAULT_32},
+#define OPTION_DISP_SIZE_DEFAULT_16 (OPTION_MD_BASE + 5)
+  {"disp-size-default-16", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_16},
+#define OPTION_DISP_SIZE_DEFAULT_32 (OPTION_MD_BASE + 6)
+  {"disp-size-default-32", no_argument, NULL, OPTION_DISP_SIZE_DEFAULT_32},
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof(md_longopts);
@@ -5947,10 +6591,50 @@ md_parse_option (c, arg)
 
     case OPTION_REGISTER_PREFIX_OPTIONAL:
       flag_reg_prefix_optional = 1;
+      reg_prefix_optional_seen = 1;
       break;
 
-    case 'Q':
+      /* -V: SVR4 argument to print version ID.  */
     case 'V':
+      print_version_id ();
+      break;
+
+      /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section
+        should be emitted or not.  FIXME: Not implemented.  */
+    case 'Q':
+      break;
+
+    case OPTION_BITWISE_OR:
+      {
+       char *n, *t;
+       const char *s;
+
+       n = (char *) xmalloc (strlen (m68k_comment_chars) + 1);
+       t = n;
+       for (s = m68k_comment_chars; *s != '\0'; s++)
+         if (*s != '|')
+           *t++ = *s;
+       *t = '\0';
+       m68k_comment_chars = n;
+      }
+      break;
+
+    case OPTION_BASE_SIZE_DEFAULT_16:
+      m68k_index_width_default = SIZE_WORD;
+      break;
+
+    case OPTION_BASE_SIZE_DEFAULT_32:
+      m68k_index_width_default = SIZE_LONG;
+      break;
+
+    case OPTION_DISP_SIZE_DEFAULT_16:
+      m68k_rel32 = 0;
+      m68k_rel32_from_cmdline = 1;
+      break;
+
+    case OPTION_DISP_SIZE_DEFAULT_32:
+      m68k_rel32 = 1;
+      m68k_rel32_from_cmdline = 1;
       break;
 
     default:
@@ -5969,7 +6653,7 @@ md_show_usage (stream)
 -l                     use 1 word for refs to undefined symbols [default 2]\n\
 -m68000 | -m68008 | -m68010 | -m68020 | -m68030 | -m68040 | -m68060\n\
  | -m68302 | -m68331 | -m68332 | -m68333 | -m68340 | -m68360\n\
- | -mcpu32\n\
+ | -mcpu32 | -m5200\n\
                        specify variant of 680X0 architecture [default 68020]\n\
 -m68881 | -m68882 | -mno-68881 | -mno-68882\n\
                        target has/lacks floating-point coprocessor\n\
@@ -5981,7 +6665,13 @@ md_show_usage (stream)
 -pic, -k               generate position independent code\n\
 -S                     turn jbsr into jsr\n\
 --register-prefix-optional\n\
-                       recognize register names without prefix character\n");
+                       recognize register names without prefix character\n\
+--bitwise-or           do not treat `|' as a comment character\n");
+  fprintf (stream, "\
+--base-size-default-16 base reg without size is 16 bits\n\
+--base-size-default-32 base reg without size is 32 bits (default)\n\
+--disp-size-default-16 displacement with unknown size is 16 bits\n\
+--disp-size-default-32 displacement with unknown size is 32 bits (default)\n");
 }
 \f
 #ifdef TEST2
This page took 0.056725 seconds and 4 git commands to generate.