* as.h (bfd_alloc_by_size_t): Don't declare.
authorIan Lance Taylor <ian@airs.com>
Mon, 17 Mar 1997 16:29:29 +0000 (16:29 +0000)
committerIan Lance Taylor <ian@airs.com>
Mon, 17 Mar 1997 16:29:29 +0000 (16:29 +0000)
* Many files: Use xmalloc rather than bfd_alloc_by_size_t.

gas/ChangeLog
gas/as.h
gas/config/obj-coff.c
gas/config/tc-alpha.c
gas/config/tc-arm.c
gas/config/tc-d10v.c
gas/config/tc-i386.c
gas/config/tc-m68k.c
gas/config/tc-mn10300.c
gas/config/tc-sparc.c
gas/write.c

index 9a924d1878b553cffcc6c413ced168bce802b049..3b0390a18061f65a938b59a0edab7e501bae4ca1 100644 (file)
@@ -1,3 +1,8 @@
+Mon Mar 17 11:21:09 1997  Ian Lance Taylor  <ian@cygnus.com>
+
+       * as.h (bfd_alloc_by_size_t): Don't declare.
+       * Many files: Use xmalloc rather than bfd_alloc_by_size_t.
+
 Sun Mar 16 13:49:21 1997  Philippe De Muyter <phdm@info.ucl.ac.be>
 
        * symbols.c (symbol_new): Don't call debug_verify_symchain.
index 66d385c7dfb345c04d6bc0e90bbbe41fb4313e5e..f24b0729adcf97ca260b1d460abc929ce0c09464 100644 (file)
--- a/gas/as.h
+++ b/gas/as.h
@@ -1,5 +1,5 @@
 /* as.h - global header file
-   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 1996
+   Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -15,8 +15,9 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #ifndef GAS
 #define GAS 1
@@ -135,6 +136,7 @@ void *alloca ();
 #ifdef BFD_ASSEMBLER
 #include <bfd.h>
 #endif
+#include <libiberty.h>
 
 /* Define the standard progress macros.  */
 #include <progress.h>
@@ -161,8 +163,8 @@ extern void free ();
 extern int errno;
 #endif
 
-/* This is needed for VMS.  */
-#if ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE)
+/* This is needed for VMS with DEC C.  */
+#if ! defined (__GNUC__) && ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE)
 #define unlink remove
 #endif
 
@@ -171,13 +173,6 @@ extern int errno;
 #define bcopy(src,dest,size)   memcpy(dest,src,size)
 #endif
 
-#ifdef BFD_ASSEMBLER
-/* This one doesn't get declared, but we're using it anyways.  This
-   should be fixed -- either it's part of the external interface or
-   it's not.  */
-extern PTR bfd_alloc_by_size_t PARAMS ((bfd *abfd, size_t sz));
-#endif
-
 /* Make Saber happier on obstack.h.  */
 #ifdef SABER
 #undef  __PTR_TO_INT
@@ -348,11 +343,17 @@ enum _relax_state
        constant length frag. */
     rs_fill = 1,
 
-    /* Align: Fr_offset: power of 2.  Variable chars: fill pattern. */
+    /* Align.  The fr_offset field holds the power of 2 to which to
+       align.  The fr_var field holds the number of characters in the
+       fill pattern.  The fr_subtype field holds the maximum number of
+       bytes to skip when aligning, or 0 if there is no maximum.  */
     rs_align,
 
-    /* Align code: fr_offset: power of 2.  Fill pattern is machine
-       specific, defaulting to all zeros.  */
+    /* Align code.  The fr_offset field holds the power of 2 to which
+       to align.  This type is only generated by machine specific
+       code, which is normally responsible for handling the fill
+       pattern.  The fr_subtype field holds the maximum number of
+       bytes to skip when aligning, or 0 if there is no maximum.  */
     rs_align_code,
 
     /* Org: Fr_offset, fr_symbol: address. 1 variable char: fill
@@ -498,6 +499,9 @@ COMMON unsigned char flag_print_statistics;
 /* name of emitted object file */
 COMMON char *out_file_name;
 
+/* name of file defining extensions to the basic instruction set */
+COMMON char *insttbl_file_name;
+
 /* TRUE if we need a second pass. */
 COMMON int need_pass_2;
 
@@ -541,7 +545,7 @@ typedef struct _pseudo_type pseudo_typeS;
 #endif
 
 #ifdef USE_STDARG
-#if __GNUC__ >= 2
+#if (__GNUC__ >= 2) && !defined(VMS)
 /* for use with -Wformat */
 #define PRINTF_LIKE(FCN)       void FCN (const char *format, ...) \
                                        __attribute__ ((format (printf, 1, 2)))
@@ -580,8 +584,6 @@ char *atof_ieee PARAMS ((char *str, int what_kind, LITTLENUM_TYPE * words));
 char *input_scrub_include_file PARAMS ((char *filename, char *position));
 char *input_scrub_new_file PARAMS ((char *filename));
 char *input_scrub_next_buffer PARAMS ((char **bufp));
-PTR xmalloc PARAMS ((unsigned long size));
-PTR xrealloc PARAMS ((PTR ptr, unsigned long n));
 int do_scrub_chars PARAMS ((int (*get) (char **), char *to, int tolen));
 int gen_to_words PARAMS ((LITTLENUM_TYPE * words, int precision,
                          long exponent_bits));
index 93ac0ad592ce0143ace74eb7e10d5c4499b1e41f..315597cb5d20799c661e817697047526d6fec340 100644 (file)
@@ -19,6 +19,8 @@
    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    02111-1307, USA.  */
 
+#define OBJ_HEADER "obj-coff.h"
+
 #include "as.h"
 #include "obstack.h"
 #include "subsegs.h"
@@ -327,14 +329,14 @@ static symbolS *line_fsym;
 
 \f
 void
-obj_symbol_new_hook (symbolP)
+coff_obj_symbol_new_hook (symbolP)
      symbolS *symbolP;
 {
   char underscore = 0;         /* Symbol has leading _ */
 
   {
     long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type);
-    char *s = (char *) bfd_alloc_by_size_t (stdoutput, sz);
+    char *s = (char *) xmalloc (sz);
     memset (s, 0, sz);
     coffsymbol (symbolP->bsym)->native = (combined_entry_type *) s;
   }
@@ -364,8 +366,8 @@ add_lineno (frag, offset, num)
      int offset;
      int num;
 {
-  struct line_no *new_line = (struct line_no *) bfd_alloc_by_size_t (stdoutput,
-                                                                    sizeof (struct line_no));
+  struct line_no *new_line =
+    (struct line_no *) xmalloc (sizeof (struct line_no));
   if (!current_lineno_sym)
     {
       abort ();
@@ -882,7 +884,7 @@ obj_coff_val (ignore)
 }
 
 void
-obj_read_begin_hook ()
+coff_obj_read_begin_hook ()
 {
   /* These had better be the same.  Usually 18 bytes. */
 #ifndef BFD_HEADERS
@@ -1047,7 +1049,7 @@ coff_frob_symbol (symp, punt)
       /* We need i entries for line numbers, plus 1 for the first
         entry which BFD will override, plus 1 for the last zero
         entry (a marker for BFD).  */
-      l = (alent *) bfd_alloc_by_size_t (stdoutput, (i + 2) * sizeof (alent));
+      l = (alent *) xmalloc ((i + 2) * sizeof (alent));
       coffsymbol (symp->bsym)->lineno = l;
       l[i + 1].line_number = 0;
       l[i + 1].u.sym = NULL;
@@ -1120,6 +1122,7 @@ coff_frob_file ()
  *                                               'w' for data
  *                                              'd' (apparently m88k for data)
  *                                               'x' for text
+ *                                              'r' for read-only data
  * But if the argument is not a quoted string, treat it as a
  * subsegment number.
  */
@@ -1176,6 +1179,7 @@ obj_coff_section (ignore)
                case 'd':
                case 'w': flags &=~ SEC_READONLY; break;
                case 'x': flags |= SEC_CODE; break;
+               case 'r': flags |= SEC_READONLY; break;
 
                case 'i': /* STYP_INFO */
                case 'l': /* STYP_LIB */
@@ -2000,7 +2004,7 @@ symbol_to_chars (abfd, where, symbolP)
 }
 
 void
-obj_symbol_new_hook (symbolP)
+coff_obj_symbol_new_hook (symbolP)
      symbolS *symbolP;
 {
   char underscore = 0;         /* Symbol has leading _ */
@@ -2571,7 +2575,7 @@ obj_coff_pe_handle_link_once (type)
 #endif /* TE_PE */
 
 void
-obj_read_begin_hook ()
+coff_obj_read_begin_hook ()
 {
   /* These had better be the same.  Usually 18 bytes. */
 #ifndef BFD_HEADERS
@@ -2921,7 +2925,7 @@ crawl_symbols (h, abfd)
    * order :
    * . .file symbol
    * . debug entries for functions
-   * . fake symbols for the sections, including.text .data and .bss
+   * . fake symbols for the sections, including .text .data and .bss
    * . defined symbols
    * . undefined symbols
    * But this is not mandatory. The only important point is to put the
@@ -3356,6 +3360,7 @@ obj_coff_add_segment (name)
  *                                               'w' for data
  *                                              'd' (apparently m88k for data)
  *                                               'x' for text
+ *                                              'r' for read-only data
  * But if the argument is not a quoted string, treat it as a
  * subsegment number.
  */
@@ -3420,6 +3425,7 @@ obj_coff_section (ignore)
                case 'd':
                case 'w': flags |= STYP_DATA;   break;
                case 'x': flags |= STYP_TEXT;   break;
+               case 'r': flags |= STYP_LIT;    break;
                default:
                  as_warn("unknown section attribute '%c'",
                          *input_line_pointer);
@@ -4312,6 +4318,7 @@ const pseudo_typeS obj_pseudo_table[] =
   {"optim", s_ignore, 0},      /* For sun386i cc (?) */
   {"ident", s_ignore, 0},      /* we don't yet handle this. */
 #endif
+  {"version", s_ignore, 0},
   {"ABORT", s_abort, 0},
 #ifdef TC_M88K
   /* The m88k uses sdef instead of def.  */
@@ -4319,3 +4326,60 @@ const pseudo_typeS obj_pseudo_table[] =
 #endif
   {NULL}                       /* end sentinel */
 };                             /* obj_pseudo_table */
+\f
+#ifdef BFD_ASSEMBLER
+
+/* Support for a COFF emulation.  */
+
+static void
+coff_pop_insert ()
+{
+  pop_insert (obj_pseudo_table);
+}
+
+static int
+coff_sec_sym_ok_for_reloc (sec)
+     asection *sec;
+{
+  return 0;
+}
+
+static void
+no_func ()
+{
+  abort ();
+}
+
+const struct format_ops coff_format_ops =
+{
+  bfd_target_coff_flavour,
+  0,
+  1,
+  coff_frob_symbol,
+  coff_frob_file,
+  no_func,
+  0, 0,
+  0, 0,
+  0,
+#if 0
+  obj_generate_asm_lineno,
+#else
+  no_func,
+#endif
+#if 0
+  obj_stab,
+#else
+  no_func,
+#endif
+  coff_sec_sym_ok_for_reloc,
+  coff_pop_insert,
+#if 0
+  obj_set_ext,
+#else
+  no_func,
+#endif
+  coff_obj_read_begin_hook,
+  coff_obj_symbol_new_hook,
+};
+
+#endif
index 91879bd0636396ebb9cfc288f795254a63190271..9a1744451c9d3b1f2321edd069215d96bc597701 100644 (file)
@@ -1,10 +1,10 @@
 /* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
-   Copyright (C) 1989, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1989, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Carnegie Mellon University, 1993.
    Written by Alessandro Forin, based on earlier gas-1.38 target CPU files.
    Modified by Ken Raeburn for gas-2.x and ECOFF support.
    Modified by Richard Henderson for ELF support.
-   Modified by Klaus Kaempf for EVAX (openVMS/Alpha) support.
+   Modified by Klaus K"ampf for EVAX (openVMS/Alpha) support.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -87,8 +87,8 @@ enum alpha_macro_arg
 struct alpha_macro
 {
   const char *name;
-  void (*emit) PARAMS((const expressionS *, int, void *));
-  void *arg;
+  void (*emit) PARAMS ((const expressionS *, int, const PTR));
+  const PTR arg;
   enum alpha_macro_arg argsets[16];
 };
 
@@ -154,70 +154,73 @@ struct alpha_macro
 \f
 /* Prototypes for all local functions */
 
-static int tokenize_arguments PARAMS((char *, expressionS*, int));
+static int tokenize_arguments PARAMS ((char *, expressionS *, int));
 static const struct alpha_opcode *find_opcode_match
-       PARAMS((const struct alpha_opcode*, const expressionS*, int*, int*));
+  PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *));
 static const struct alpha_macro *find_macro_match
-       PARAMS((const struct alpha_macro*, const expressionS*, int*));
-static unsigned insert_operand PARAMS((unsigned, const struct alpha_operand*,
-                                     offsetT, char *, unsigned));
-static void assemble_insn PARAMS((const struct alpha_opcode*,
-                                 const expressionS*, int,
-                                 struct alpha_insn*));
-static void emit_insn PARAMS((struct alpha_insn *));
-static void assemble_tokens_to_insn PARAMS((const char *, const expressionS*,
-                                           int, struct alpha_insn *));
-static void assemble_tokens PARAMS((const char *, const expressionS*,
-                                   int, int));
-
-static int load_expression PARAMS((int, const expressionS*, int *,
-                                  expressionS*));
-
-static void emit_ldgp PARAMS((const expressionS*, int, void*));
-static void emit_division PARAMS((const expressionS*, int, void*));
-static void emit_lda PARAMS((const expressionS*, int, void*));
-static void emit_ldah PARAMS((const expressionS*, int, void*));
-static void emit_ir_load PARAMS((const expressionS*, int, void*));
-static void emit_loadstore PARAMS((const expressionS*, int, void*));
-static void emit_jsrjmp PARAMS((const expressionS*, int, void*));
-static void emit_ldX PARAMS((const expressionS*, int, void*));
-static void emit_ldXu PARAMS((const expressionS*, int, void*));
-static void emit_uldX PARAMS((const expressionS*, int, void*));
-static void emit_uldXu PARAMS((const expressionS*, int, void*));
-static void emit_ldil PARAMS((const expressionS*, int, void*));
-static void emit_stX PARAMS((const expressionS*, int, void*));
-static void emit_ustX PARAMS((const expressionS*, int, void*));
-static void emit_sextX PARAMS((const expressionS*, int, void*));
-static void emit_retjcr PARAMS((const expressionS*, int, void*));
-
-static void s_alpha_text PARAMS((int));
-static void s_alpha_data PARAMS((int));
+  PARAMS ((const struct alpha_macro *, const expressionS *, int *));
+static unsigned insert_operand
+  PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned));
+static void assemble_insn
+  PARAMS ((const struct alpha_opcode *, const expressionS *, int,
+          struct alpha_insn *));
+static void emit_insn PARAMS ((struct alpha_insn *));
+static void assemble_tokens_to_insn
+  PARAMS ((const char *, const expressionS *, int, struct alpha_insn *));
+static void assemble_tokens
+  PARAMS ((const char *, const expressionS *, int, int));
+
+static int load_expression
+  PARAMS ((int, const expressionS *, int *, expressionS *));
+
+static void emit_ldgp PARAMS ((const expressionS *, int, const PTR));
+static void emit_division PARAMS ((const expressionS *, int, const PTR));
+static void emit_lda PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldah PARAMS ((const expressionS *, int, const PTR));
+static void emit_ir_load PARAMS ((const expressionS *, int, const PTR));
+static void emit_loadstore PARAMS ((const expressionS *, int, const PTR));
+static void emit_jsrjmp PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldX PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldXu PARAMS ((const expressionS *, int, const PTR));
+static void emit_uldX PARAMS ((const expressionS *, int, const PTR));
+static void emit_uldXu PARAMS ((const expressionS *, int, const PTR));
+static void emit_ldil PARAMS ((const expressionS *, int, const PTR));
+static void emit_stX PARAMS ((const expressionS *, int, const PTR));
+static void emit_ustX PARAMS ((const expressionS *, int, const PTR));
+static void emit_sextX PARAMS ((const expressionS *, int, const PTR));
+static void emit_retjcr PARAMS ((const expressionS *, int, const PTR));
+
+static void s_alpha_text PARAMS ((int));
+static void s_alpha_data PARAMS ((int));
 #ifndef OBJ_ELF
-static void s_alpha_comm PARAMS((int));
+static void s_alpha_comm PARAMS ((int));
 #endif
 #if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
-static void s_alpha_rdata PARAMS((int));
+static void s_alpha_rdata PARAMS ((int));
 #endif
 #ifdef OBJ_ECOFF
-static void s_alpha_sdata PARAMS((int));
+static void s_alpha_sdata PARAMS ((int));
 #endif
 #ifdef OBJ_ELF
-static void s_alpha_section PARAMS((int));
+static void s_alpha_section PARAMS ((int));
 #endif
-static void s_alpha_gprel32 PARAMS((int));
-static void s_alpha_float_cons PARAMS((int));
-static void s_alpha_proc PARAMS((int));
-static void s_alpha_set PARAMS((int));
-static void s_alpha_base PARAMS((int));
-static void s_alpha_align PARAMS((int));
-static void s_alpha_stringer PARAMS((int));
-static void s_alpha_space PARAMS((int));
-
-static void create_literal_section PARAMS((const char *, segT*, symbolS**));
+#ifdef OBJ_EVAX
+static void s_alpha_section PARAMS ((int));
+#endif
+static void s_alpha_gprel32 PARAMS ((int));
+static void s_alpha_float_cons PARAMS ((int));
+static void s_alpha_proc PARAMS ((int));
+static void s_alpha_set PARAMS ((int));
+static void s_alpha_base PARAMS ((int));
+static void s_alpha_align PARAMS ((int));
+static void s_alpha_stringer PARAMS ((int));
+static void s_alpha_space PARAMS ((int));
+
+static void create_literal_section PARAMS ((const char *, segT *, symbolS **));
 #ifndef OBJ_ELF
-static void select_gp_value PARAMS((void));
+static void select_gp_value PARAMS ((void));
 #endif
-static void alpha_align PARAMS((int, char *, symbolS *));
+static void alpha_align PARAMS ((int, char *, symbolS *));
 
 \f
 /* Generic assembler global variables which must be defined by all
@@ -287,7 +290,7 @@ size_t md_longopts_size = sizeof(md_longopts);
 #endif /* OBJ_EVAX  */
 
 /* The cpu for which we are generating code */
-static unsigned alpha_target = AXP_OPCODE_ALL;
+static unsigned alpha_target = AXP_OPCODE_BASE;
 static const char *alpha_target_name = "<all>";
 
 /* The hash table of instruction opcodes */
@@ -317,6 +320,8 @@ static segT alpha_lit4_section;
 #endif
 #ifdef OBJ_EVAX
 static segT alpha_link_section;
+static segT alpha_ctors_section;
+static segT alpha_dtors_section;
 #endif
 static segT alpha_lit8_section;
 
@@ -327,9 +332,17 @@ static symbolS *alpha_lit4_symbol;
 #endif
 #ifdef OBJ_EVAX
 static symbolS *alpha_link_symbol;
+static symbolS *alpha_ctors_symbol;
+static symbolS *alpha_dtors_symbol;
 #endif
 static symbolS *alpha_lit8_symbol;
 
+/* Literal for .litX+0x8000 within .lita */
+#ifdef OBJ_ECOFF
+static offsetT alpha_lit4_literal;
+static offsetT alpha_lit8_literal;
+#endif
+
 /* Is the assembler not allowed to use $at? */
 static int alpha_noat_on = 0;
 
@@ -377,21 +390,10 @@ static struct {
 
 static int alpha_flag_hash_long_names = 0;             /* -+ */
 static int alpha_flag_show_after_trunc = 0;            /* -H */
-static int alpha_flag_no_hash_mixed_case = 0;          /* -h NUM */
-
-/* Flag that determines how we map names.  This takes several values, and
- * is set with the -h switch.  A value of zero implies names should be
- * upper case, and the presence of the -h switch inhibits the case hack.
- * No -h switch at all sets alpha_vms_name_mapping to 0, and allows case hacking.
- * A value of 2 (set with -h2) implies names should be
- * all lower case, with no case hack.  A value of 3 (set with -h3) implies
- * that case should be preserved.  */
-
-/* If the -+ switch is given, then the hash is appended to any name that is
- * longer than 31 characters, regardless of the setting of the -h switch.
- */
 
-static char alpha_vms_name_mapping = 0;
+/* If the -+ switch is given, then a hash is appended to any name that is
+ * longer than 64 characters, else longer symbol names are truncated.
+ */
 
 static int alpha_basereg_clobbered;
 #endif
@@ -434,32 +436,32 @@ static const struct alpha_macro alpha_macros[] = {
     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
 
-  { "ldb",     emit_ldX, (void *)0,
+  { "ldb",     emit_ldX, (PTR)0,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ldbu",    emit_ldXu, (void *)0,
+  { "ldbu",    emit_ldXu, (PTR)0,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ldw",     emit_ldX, (void *)1,
+  { "ldw",     emit_ldX, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ldwu",    emit_ldXu, (void *)1,
+  { "ldwu",    emit_ldXu, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
 
-  { "uldw",    emit_uldX, (void*)1,
+  { "uldw",    emit_uldX, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "uldwu",   emit_uldXu, (void*)1,
+  { "uldwu",   emit_uldXu, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "uldl",    emit_uldX, (void*)2,
+  { "uldl",    emit_uldX, (PTR)2,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "uldlu",   emit_uldXu, (void*)2,
+  { "uldlu",   emit_uldXu, (PTR)2,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "uldq",    emit_uldXu, (void*)3,
+  { "uldq",    emit_uldXu, (PTR)3,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
 
@@ -513,19 +515,19 @@ static const struct alpha_macro alpha_macros[] = {
     { MACRO_FPR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_FPR, MACRO_EXP, MACRO_EOA } },
 
-  { "stb",     emit_stX, (void*)0,
+  { "stb",     emit_stX, (PTR)0,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "stw",     emit_stX, (void*)1,
+  { "stw",     emit_stX, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ustw",    emit_ustX, (void*)1,
+  { "ustw",    emit_ustX, (PTR)1,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ustl",    emit_ustX, (void*)2,
+  { "ustl",    emit_ustX, (PTR)2,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
-  { "ustq",    emit_ustX, (void*)3,
+  { "ustq",    emit_ustX, (PTR)3,
     { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA,
       MACRO_IR, MACRO_EXP, MACRO_EOA } },
 
@@ -539,11 +541,11 @@ static const struct alpha_macro alpha_macros[] = {
   { "absq"     emit_absq, 2, { EXP, IR } },
 #endif
 
-  { "sextb",   emit_sextX, (void *)0,
+  { "sextb",   emit_sextX, (PTR)0,
     { MACRO_IR, MACRO_IR, MACRO_EOA,
       MACRO_IR, MACRO_EOA,
       /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
-  { "sextw",   emit_sextX, (void *)1,
+  { "sextw",   emit_sextX, (PTR)1,
     { MACRO_IR, MACRO_IR, MACRO_EOA,
       MACRO_IR, MACRO_EOA,
       /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } },
@@ -744,7 +746,7 @@ md_begin ()
       sec = subseg_new(".reginfo", (subsegT)0);
       /* The ABI says this section should be loaded so that the running
         program can access it.  */
-      bfd_set_section_flags(stdoutput, sec, 
+      bfd_set_section_flags(stdoutput, sec,
                            SEC_ALLOC|SEC_LOAD|SEC_READONLY|SEC_DATA);
       bfd_set_section_alignement(stdoutput, sec, 3);
 #endif
@@ -894,18 +896,34 @@ md_parse_option (c, arg)
          unsigned flags;
        } *p, m[] =
        {
-         { "21064", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
-         { "21066", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
-         { "21164", AXP_OPCODE_EV5|AXP_OPCODE_ALL },
-         { "21164a", AXP_OPCODE_EV56|AXP_OPCODE_ALL },
-         { "ev4", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
-         { "ev45", AXP_OPCODE_EV4|AXP_OPCODE_ALL },
-         { "ev5", AXP_OPCODE_EV5|AXP_OPCODE_ALL },
-         { "ev56", AXP_OPCODE_EV56|AXP_OPCODE_ALL },
-         { "all", AXP_OPCODE_ALL },
+         { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
+         /* Do we have CIX extension here? */
+         { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
+         /* Still same PALcodes? */
+         { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
+                       |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+         /* All new PALcodes?  Extras? */
+         { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_BWX
+                     |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+
+         { "ev4", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "ev45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "lca45", AXP_OPCODE_BASE|AXP_OPCODE_EV4 },
+         { "ev5", AXP_OPCODE_BASE|AXP_OPCODE_EV5 },
+         { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX },
+         { "pca56", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX
+                     |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+         { "ev6", (AXP_OPCODE_BASE|AXP_OPCODE_BWX
+                   |AXP_OPCODE_CIX|AXP_OPCODE_MAX) },
+
+         { "all", AXP_OPCODE_BASE },
          { 0 }
        };
-       
+
        for (p = m; p->name; ++p)
          if (strcmp(arg, p->name) == 0)
            {
@@ -917,8 +935,8 @@ md_parse_option (c, arg)
       }
       break;
 
-#if OBJ_EVAX
-    case '+':                  /* For g++.  Hash any name > 31 chars long. */
+#ifdef OBJ_EVAX
+    case '+':                  /* For g++.  Hash any name > 63 chars long. */
       alpha_flag_hash_long_names = 1;
       break;
 
@@ -926,11 +944,7 @@ md_parse_option (c, arg)
       alpha_flag_show_after_trunc = 1;
       break;
 
-    case 'h':                  /* No hashing of mixed-case names */
-      {
-       alpha_vms_name_mapping = atoi (arg);
-       alpha_flag_no_hash_mixed_case = 1;
-      }
+    case 'h':                  /* for gnu-c/vax compatibility.  */
       break;
 #endif
 
@@ -958,10 +972,8 @@ Alpha options:\n\
 #ifdef OBJ_EVAX
   fputs ("\
 VMS options:\n\
--+                     hash encode names longer than 31 characters\n\
--H                     show new symbol after hash truncation\n\
--h NUM                 don't hash mixed-case names, and adjust case:\n\
-                       0 = upper, 2 = lower, 3 = preserve case\n",
+-+                     hash encode (don't truncate) names longer than 64 characters\n\
+-H                     show new symbol after hash truncation\n",
        stream);
 #endif
 }
@@ -1015,7 +1027,7 @@ md_apply_fix (fixP, valueP)
        fixS *next = fixP->fx_next;
        assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16);
 
-       fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where 
+       fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where
                           - fixP->fx_frag->fr_address - fixP->fx_where);
 
        value = (value - sign_extend_16 (value)) >> 16;
@@ -1093,12 +1105,13 @@ md_apply_fix (fixP, valueP)
       return 1;
 #endif
 #ifdef OBJ_ELF
-    case BFD_RELOC_ALPHA_LITERAL:
+    case BFD_RELOC_ALPHA_ELF_LITERAL:
     case BFD_RELOC_ALPHA_LITUSE:
       return 1;
 #endif
 #ifdef OBJ_EVAX
     case BFD_RELOC_ALPHA_LINKAGE:
+    case BFD_RELOC_ALPHA_CODEADDR:
       return 1;
 #endif
 
@@ -1106,15 +1119,15 @@ md_apply_fix (fixP, valueP)
       {
        const struct alpha_operand *operand;
 
-       if (fixP->fx_r_type <= BFD_RELOC_UNUSED)
+       if ((int)fixP->fx_r_type >= 0)
          as_fatal ("unhandled relocation type %s",
                    bfd_get_reloc_code_name (fixP->fx_r_type));
 
-       assert (fixP->fx_r_type < BFD_RELOC_UNUSED + alpha_num_operands);
-       operand = &alpha_operands[fixP->fx_r_type - BFD_RELOC_UNUSED];
+       assert (-(int)fixP->fx_r_type < alpha_num_operands);
+       operand = &alpha_operands[-(int)fixP->fx_r_type];
 
        /* The rest of these fixups only exist internally during symbol
-          resolution and have no representation in the object file.  
+          resolution and have no representation in the object file.
           Therefore they must be completely resolved as constants.  */
 
        if (fixP->fx_addsy != 0
@@ -1134,10 +1147,10 @@ md_apply_fix (fixP, valueP)
   else
     {
       as_warn_where(fixP->fx_file, fixP->fx_line,
-                   "type %d reloc done?\n", fixP->fx_r_type);
+                   "type %d reloc done?\n", (int)fixP->fx_r_type);
       goto done;
     }
-      
+
 write_done:
   md_number_to_chars(fixpos, image, 4);
 
@@ -1146,7 +1159,7 @@ done:
   return 0;
 }
 
-/* 
+/*
  * Look for a register name in the given symbol.
  */
 
@@ -1177,7 +1190,7 @@ md_undefined_symbol(name)
            num = name[0] - '0';
          else if (name[0] != '0' && isdigit(name[1]) && name[2] == '\0')
            {
-             num = (name[0] - '0')*10 + name[1] - '0';
+             num = (name[0] - '0') * 10 + name[1] - '0';
              if (num >= 32)
                break;
            }
@@ -1247,11 +1260,17 @@ alpha_force_relocation (f)
     case BFD_RELOC_ALPHA_GPDISP_HI16:
     case BFD_RELOC_ALPHA_GPDISP_LO16:
     case BFD_RELOC_ALPHA_GPDISP:
+#ifdef OBJ_ECOFF
     case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+    case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
     case BFD_RELOC_ALPHA_LITUSE:
     case BFD_RELOC_GPREL32:
 #ifdef OBJ_EVAX
     case BFD_RELOC_ALPHA_LINKAGE:
+    case BFD_RELOC_ALPHA_CODEADDR:
 #endif
       return 1;
 
@@ -1262,8 +1281,7 @@ alpha_force_relocation (f)
       return 0;
 
     default:
-      assert(f->fx_r_type > BFD_RELOC_UNUSED &&
-            f->fx_r_type < BFD_RELOC_UNUSED + alpha_num_operands);
+      assert((int)f->fx_r_type < 0 && -(int)f->fx_r_type < alpha_num_operands);
       return 0;
     }
 }
@@ -1284,10 +1302,37 @@ alpha_fix_adjustable (f)
      but we can adjust the values contained within it?  */
   switch (f->fx_r_type)
     {
+    case BFD_RELOC_ALPHA_GPDISP_HI16:
+    case BFD_RELOC_ALPHA_GPDISP_LO16:
+    case BFD_RELOC_ALPHA_GPDISP:
+      return 0;
+
+#ifdef OBJ_ECOFF
+    case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+    case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
+#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_LINKAGE:
+    case BFD_RELOC_ALPHA_CODEADDR:
+#endif
+      return 1;
+
+    case BFD_RELOC_ALPHA_LITUSE:
+      return 0;
+
     case BFD_RELOC_GPREL32:
+    case BFD_RELOC_23_PCREL_S2:
+    case BFD_RELOC_32:
+    case BFD_RELOC_64:
+    case BFD_RELOC_ALPHA_HINT:
       return 1;
+
     default:
-      return !alpha_force_relocation (f);
+      assert ((int)f->fx_r_type < 0
+             && - (int)f->fx_r_type < alpha_num_operands);
+      return 1;
     }
   /*NOTREACHED*/
 }
@@ -1302,13 +1347,13 @@ tc_gen_reloc (sec, fixp)
 {
   arelent *reloc;
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  reloc = (arelent *) xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 
   /* Make sure none of our internal relocations make it this far.
      They'd better have been fully resolved by this point.  */
-  assert (fixp->fx_r_type < BFD_RELOC_UNUSED);
+  assert ((int)fixp->fx_r_type > 0);
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == NULL)
@@ -1337,7 +1382,7 @@ tc_gen_reloc (sec, fixp)
     {
       reloc->addend = fixp->fx_offset;
 #ifdef OBJ_ELF
-      /* 
+      /*
        * Ohhh, this is ugly.  The problem is that if this is a local global
        * symbol, the relocation will entirely be performed at link time, not
        * at assembly time.  bfd_perform_reloc doesn't know about this sort
@@ -1394,12 +1439,12 @@ tokenize_arguments (str, tok, ntok)
   char *old_input_line_pointer;
   int saw_comma = 0, saw_arg = 0;
 
-  memset (tok, 0, sizeof(*tok)*ntok);
+  memset (tok, 0, sizeof (*tok) * ntok);
 
-  /* Save and restore input_line_pointer around this function */ 
+  /* Save and restore input_line_pointer around this function */
   old_input_line_pointer = input_line_pointer;
   input_line_pointer = str;
-  
+
   while (tok < end_tok && *input_line_pointer)
     {
       SKIP_WHITESPACE ();
@@ -1555,7 +1600,7 @@ find_opcode_match(first_opcode, tok, pntok, pcpumatch)
 
     match_failed:;
     }
-  while (++opcode-alpha_opcodes < alpha_num_opcodes 
+  while (++opcode-alpha_opcodes < alpha_num_opcodes
         && !strcmp(opcode->name, first_opcode->name));
 
   if (*pcpumatch)
@@ -1631,7 +1676,7 @@ find_macro_match(first_macro, tok, pntok)
                }
              ++tokidx;
              break;
-               
+
            match_failed:
              while (*arg != MACRO_EOA)
                ++arg;
@@ -1641,7 +1686,7 @@ find_macro_match(first_macro, tok, pntok)
          ++arg;
        }
     }
-  while (++macro-alpha_macros < alpha_num_macros 
+  while (++macro-alpha_macros < alpha_num_macros
         && !strcmp(macro->name, first_macro->name));
 
   return NULL;
@@ -1674,9 +1719,9 @@ insert_operand(insn, operand, val, file, line)
 
       if (val < min || val > max)
        {
-         const char *err = 
+         const char *err =
            "operand out of range (%s not between %d and %d)";
-         char buf[sizeof(val)*3+2];
+         char buf[sizeof (val) * 3 + 2];
 
          sprint_value(buf, val);
          if (file)
@@ -1690,9 +1735,9 @@ insert_operand(insn, operand, val, file, line)
     {
       const char *errmsg = NULL;
 
-      insn = (*operand->insert)(insn, val, &errmsg);
+      insn = (*operand->insert) (insn, val, &errmsg);
       if (errmsg)
-       as_warn(errmsg);
+       as_warn (errmsg);
     }
   else
     insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
@@ -1700,7 +1745,7 @@ insert_operand(insn, operand, val, file, line)
   return insn;
 }
 
-/* 
+/*
  * Turn an opcode description and a set of arguments into
  * an instruction and a fixup.
  */
@@ -1716,7 +1761,7 @@ assemble_insn(opcode, tok, ntok, insn)
   unsigned image;
   int tokidx = 0;
 
-  memset(insn, 0, sizeof(*insn));
+  memset (insn, 0, sizeof (*insn));
   image = opcode->opcode;
 
   for (argidx = opcode->operands; *argidx; ++argidx)
@@ -1786,7 +1831,7 @@ assemble_insn(opcode, tok, ntok, insn)
   insn->insn = image;
 }
 
-/* 
+/*
  * Actually output an instruction with its fixup.
  */
 
@@ -1816,7 +1861,7 @@ emit_insn (insn)
       fixS *fixP;
 
       /* Some fixups are only used internally and so have no howto */
-      if (fixup->reloc > BFD_RELOC_UNUSED)
+      if ((int)fixup->reloc < 0)
        size = 4, pcrel = 0;
 #ifdef OBJ_ELF
       /* These relocation types are only used internally. */
@@ -1828,7 +1873,7 @@ emit_insn (insn)
 #endif
       else
        {
-         reloc_howto_type *reloc_howto 
+         reloc_howto_type *reloc_howto
            = bfd_reloc_type_lookup (stdoutput, fixup->reloc);
          assert (reloc_howto);
 
@@ -1844,7 +1889,12 @@ emit_insn (insn)
       switch (fixup->reloc)
        {
        case BFD_RELOC_ALPHA_GPDISP_LO16:
+#ifdef OBJ_ECOFF
        case BFD_RELOC_ALPHA_LITERAL:
+#endif
+#ifdef OBJ_ELF
+       case BFD_RELOC_ALPHA_ELF_LITERAL:
+#endif
        case BFD_RELOC_GPREL32:
          fixP->fx_no_overflow = 1;
          break;
@@ -1936,7 +1986,7 @@ assemble_tokens (opname, tok, ntok, local_macros_on)
          return;
        }
     }
-  
+
   if (found_something)
     if (cpumatch)
       as_bad ("inappropriate arguments for opcode `%s'", opname);
@@ -1956,14 +2006,17 @@ static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" };
 static const char * const extXh_op[] = { NULL,    "extwh", "extlh", "extqh" };
 static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" };
 static const char * const mskXh_op[] = { NULL,    "mskwh", "msklh", "mskqh" };
+static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
+static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" };
+static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
 
 /* Implement the ldgp macro.  */
 
-static void 
+static void
 emit_ldgp (tok, ntok, unused)
      const expressionS *tok;
      int ntok;
-     void *unused;
+     const PTR unused;
 {
 #ifdef OBJ_AOUT
 FIXME
@@ -2004,7 +2057,7 @@ FIXME
   emit_insn (&insn);
 
   set_tok_preg (newtok[2], tok[0].X_add_number);
-  
+
   assemble_tokens_to_insn ("lda", newtok, 3, &insn);
 
 #ifdef OBJ_ECOFF
@@ -2140,7 +2193,7 @@ load_expression (targreg, exp, pbasereg, poffset)
              as_bad ("macro requires $at register while noat in effect");
            if (targreg == AXP_REG_AT)
              as_bad ("macro requires $at while $at in use");
-           
+
            set_tok_reg (newtok[0], AXP_REG_AT);
          }
        else
@@ -2162,7 +2215,7 @@ load_expression (targreg, exp, pbasereg, poffset)
              as_bad ("macro requires $at register while noat in effect");
            if (targreg == AXP_REG_AT)
              as_bad ("macro requires $at while $at in use");
-           
+
            set_tok_reg (newtok[0], AXP_REG_AT);
          }
        else
@@ -2184,7 +2237,7 @@ load_expression (targreg, exp, pbasereg, poffset)
        assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
        assert (insn.nfixups == 1);
-       insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
+       insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
 #endif /* OBJ_ELF */
 #ifdef OBJ_EVAX
        offsetT link;
@@ -2240,6 +2293,7 @@ load_expression (targreg, exp, pbasereg, poffset)
 #endif /* OBJ_EVAX */
 
        emit_insn(&insn);
+
 #ifndef OBJ_EVAX
        emit_lituse = 1;
 
@@ -2252,6 +2306,7 @@ load_expression (targreg, exp, pbasereg, poffset)
            assemble_tokens ("addq", newtok, 3, 0);
          }
 #endif
+
        basereg = targreg;
       }
       break;
@@ -2283,7 +2338,6 @@ load_expression (targreg, exp, pbasereg, poffset)
       /* for 64-bit addends, just put it in the literal pool */
 
 #ifdef OBJ_EVAX
-
       /* emit "ldq targreg, lit(basereg)"  */
       lit = add_to_link_pool (alpha_evax_proc.symbol,
                              section_symbol (absolute_section), addend);
@@ -2291,7 +2345,6 @@ load_expression (targreg, exp, pbasereg, poffset)
       set_tok_const (newtok[1], lit);
       set_tok_preg (newtok[2], alpha_gp_register);
       assemble_tokens ("ldq", newtok, 3, 0);
-
 #else
 
       if (alpha_lit8_section == NULL)
@@ -2299,14 +2352,20 @@ load_expression (targreg, exp, pbasereg, poffset)
          create_literal_section (".lit8",
                                  &alpha_lit8_section,
                                  &alpha_lit8_symbol);
-         S_SET_VALUE (alpha_lit8_symbol, 0x8000);
+
+#ifdef OBJ_ECOFF
+         alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000,
+                                                   alpha_lita_section, 8);
+         if (alpha_lit8_literal >= 0x8000)
+           as_fatal ("overflow in literal (.lita) table");
+#endif
        }
 
       lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000;
       if (lit >= 0x8000)
        as_fatal ("overflow in literal (.lit8) table");
 
-      /* emit "ldq litreg, .lit8+lit" */
+      /* emit "lda litreg, .lit8+0x8000" */
 
       if (targreg == basereg)
        {
@@ -2319,9 +2378,46 @@ load_expression (targreg, exp, pbasereg, poffset)
        }
       else
        set_tok_reg (newtok[0], targreg);
-      set_tok_sym (newtok[1], alpha_lit8_symbol, lit);
+#ifdef OBJ_ECOFF
+      set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal);
+#endif
+#ifdef OBJ_ELF
+      set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000);
+#endif
+      set_tok_preg (newtok[2], alpha_gp_register);
+
+      assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+
+      assert (insn.nfixups == 1);
+#ifdef OBJ_ECOFF
+      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
+#endif
+#ifdef OBJ_ELF
+      insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
+#endif
+
+      emit_insn (&insn);
+
+      /* emit "ldq litreg, lit(litreg)" */
+
+      set_tok_const (newtok[1], lit);
+      set_tok_preg (newtok[2], newtok[0].X_add_number);
+
+      assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+
+      assert (insn.nfixups < MAX_INSN_FIXUPS);
+      if (insn.nfixups > 0)
+       {
+         memmove (&insn.fixups[1], &insn.fixups[0],
+                  sizeof(struct alpha_fixup) * insn.nfixups);
+       }
+      insn.nfixups++;
+      insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE;
+      insn.fixups[0].exp.X_op = O_constant;
+      insn.fixups[0].exp.X_add_number = 1;
+      emit_lituse = 0;
 
-      assemble_tokens ("ldq", newtok, 2, 1); /* note this does recurse */
+      emit_insn (&insn);
 
       /* emit "addq litreg, base, target" */
 
@@ -2401,7 +2497,7 @@ static void
 emit_lda (tok, ntok, unused)
      const expressionS *tok;
      int ntok;
-     void *unused;
+     const PTR unused;
 {
   int basereg;
 
@@ -2420,7 +2516,7 @@ static void
 emit_ldah (tok, ntok, unused)
      const expressionS *tok;
      int ntok;
-     void *unused;
+     const PTR unused;
 {
   expressionS newtok[3];
 
@@ -2439,7 +2535,7 @@ static void
 emit_ir_load (tok, ntok, opname)
      const expressionS *tok;
      int ntok;
-     void *opname;
+     const PTR opname;
 {
   int basereg, lituse;
   expressionS newtok[3];
@@ -2473,8 +2569,8 @@ emit_ir_load (tok, ntok, opname)
     }
 
   emit_insn (&insn);
-#if OBJ_EVAX
-    /* special hack. If the basereg is clobbered for a call  
+#ifdef OBJ_EVAX
+    /* special hack. If the basereg is clobbered for a call
        all lda's before the call don't have a basereg.  */
   if ((tok[0].X_op == O_register)
      && (tok[0].X_add_number == alpha_gp_register))
@@ -2491,12 +2587,12 @@ static void
 emit_loadstore (tok, ntok, opname)
      const expressionS *tok;
      int ntok;
-     void *opname;
+     const PTR opname;
 {
   int basereg, lituse;
   expressionS newtok[3];
   struct alpha_insn insn;
-  
+
   if (ntok == 2)
     basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
   else
@@ -2539,44 +2635,49 @@ emit_loadstore (tok, ntok, opname)
 
 /* Load a half-word or byte as an unsigned value.  */
 
-static void 
+static void
 emit_ldXu (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
-  expressionS newtok[3];
+  if (alpha_target & AXP_OPCODE_BWX)
+    emit_ir_load (tok, ntok, ldXu_op[(long)vlgsize]);
+  else
+    {
+      expressionS newtok[3];
 
-  if (alpha_noat_on)
-    as_bad ("macro requires $at register while noat in effect");
-  
-  /* emit "lda $at, exp" */
+      if (alpha_noat_on)
+       as_bad ("macro requires $at register while noat in effect");
 
-  memcpy (newtok, tok, sizeof(expressionS)*ntok);
-  newtok[0].X_add_number = AXP_REG_AT;
-  assemble_tokens ("lda", newtok, ntok, 1);
+      /* emit "lda $at, exp" */
 
-  /* emit "ldq_u targ, 0($at)" */
+      memcpy (newtok, tok, sizeof (expressionS) * ntok);
+      newtok[0].X_add_number = AXP_REG_AT;
+      assemble_tokens ("lda", newtok, ntok, 1);
 
-  newtok[0] = tok[0];
-  set_tok_const (newtok[1], 0);
-  set_tok_preg (newtok[2], AXP_REG_AT);
-  assemble_tokens ("ldq_u", newtok, 3, 1);
+      /* emit "ldq_u targ, 0($at)" */
 
-  /* emit "extXl targ, $at, targ" */
+      newtok[0] = tok[0];
+      set_tok_const (newtok[1], 0);
+      set_tok_preg (newtok[2], AXP_REG_AT);
+      assemble_tokens ("ldq_u", newtok, 3, 1);
 
-  set_tok_reg (newtok[1], AXP_REG_AT);
-  newtok[2] = newtok[0];
-  assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1);
+      /* emit "extXl targ, $at, targ" */
+
+      set_tok_reg (newtok[1], AXP_REG_AT);
+      newtok[2] = newtok[0];
+      assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1);
+    }
 }
 
 /* Load a half-word or byte as a signed value.  */
 
-static void 
+static void
 emit_ldX (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
   emit_ldXu (tok, ntok, vlgsize);
   assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1);
@@ -2589,7 +2690,7 @@ static void
 emit_uldXu (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
   long lgsize = (long)vlgsize;
   expressionS newtok[3];
@@ -2599,7 +2700,7 @@ emit_uldXu (tok, ntok, vlgsize)
 
   /* emit "lda $at, exp" */
 
-  memcpy (newtok, tok, sizeof(expressionS)*ntok);
+  memcpy (newtok, tok, sizeof (expressionS) * ntok);
   newtok[0].X_add_number = AXP_REG_AT;
   assemble_tokens ("lda", newtok, ntok, 1);
 
@@ -2636,7 +2737,7 @@ emit_uldXu (tok, ntok, vlgsize)
   newtok[2] = tok[0];
   assemble_tokens ("or", newtok, 3, 1);
 }
-  
+
 /* Load an integral value from an unaligned address as a signed value.
    Note that quads should get funneled to the unsigned load since we
    don't have to do the sign extension.  */
@@ -2645,7 +2746,7 @@ static void
 emit_uldX (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
   emit_uldXu (tok, ntok, vlgsize);
   assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1);
@@ -2657,7 +2758,7 @@ static void
 emit_ldil (tok, ntok, unused)
      const expressionS *tok;
      int ntok;
-     void *unused;
+     const PTR unused;
 {
   expressionS newtok[2];
 
@@ -2672,50 +2773,57 @@ emit_ldil (tok, ntok, unused)
 static void
 emit_stX (tok, ntok, vlgsize)
      const expressionS *tok;
-     void *vlgsize;
+     int ntok;
+     const PTR vlgsize;
 {
   int lgsize = (int)(long)vlgsize;
-  expressionS newtok[3];
 
-  if (alpha_noat_on)
-    as_bad("macro requires $at register while noat in effect");
+  if (alpha_target & AXP_OPCODE_BWX)
+    emit_loadstore (tok, ntok, stX_op[lgsize]);
+  else
+    {
+      expressionS newtok[3];
 
-  /* emit "lda $at, exp" */
+      if (alpha_noat_on)
+       as_bad("macro requires $at register while noat in effect");
 
-  memcpy (newtok, tok, sizeof(expressionS)*ntok);
-  newtok[0].X_add_number = AXP_REG_AT;
-  assemble_tokens ("lda", newtok, ntok, 1);
+      /* emit "lda $at, exp" */
 
-  /* emit "ldq_u $t9, 0($at)" */
+      memcpy (newtok, tok, sizeof (expressionS) * ntok);
+      newtok[0].X_add_number = AXP_REG_AT;
+      assemble_tokens ("lda", newtok, ntok, 1);
 
-  set_tok_reg (newtok[0], AXP_REG_T9);
-  set_tok_const (newtok[1], 0);
-  set_tok_preg (newtok[2], AXP_REG_AT);
-  assemble_tokens ("ldq_u", newtok, 3, 1);
+      /* emit "ldq_u $t9, 0($at)" */
 
-  /* emit "insXl src, $at, $t10" */
+      set_tok_reg (newtok[0], AXP_REG_T9);
+      set_tok_const (newtok[1], 0);
+      set_tok_preg (newtok[2], AXP_REG_AT);
+      assemble_tokens ("ldq_u", newtok, 3, 1);
 
-  newtok[0] = tok[0];
-  set_tok_reg (newtok[1], AXP_REG_AT);
-  set_tok_reg (newtok[2], AXP_REG_T10);
-  assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
+      /* emit "insXl src, $at, $t10" */
 
-  /* emit "mskXl $t9, $at, $t9" */
+      newtok[0] = tok[0];
+      set_tok_reg (newtok[1], AXP_REG_AT);
+      set_tok_reg (newtok[2], AXP_REG_T10);
+      assemble_tokens (insXl_op[lgsize], newtok, 3, 1);
 
-  set_tok_reg (newtok[0], AXP_REG_T9);
-  newtok[2] = newtok[0];
-  assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
+      /* emit "mskXl $t9, $at, $t9" */
 
-  /* emit "or $t9, $t10, $t9" */
+      set_tok_reg (newtok[0], AXP_REG_T9);
+      newtok[2] = newtok[0];
+      assemble_tokens (mskXl_op[lgsize], newtok, 3, 1);
 
-  set_tok_reg (newtok[1], AXP_REG_T10);
-  assemble_tokens ("or", newtok, 3, 1);
+      /* emit "or $t9, $t10, $t9" */
 
-  /* emit "stq_u $t9, 0($at) */
+      set_tok_reg (newtok[1], AXP_REG_T10);
+      assemble_tokens ("or", newtok, 3, 1);
 
-  set_tok_const (newtok[1], 0);
-  set_tok_preg (newtok[2], AXP_REG_AT);
-  assemble_tokens ("stq_u", newtok, 3, 1);
+      /* emit "stq_u $t9, 0($at) */
+
+      set_tok_const (newtok[1], 0);
+      set_tok_preg (newtok[2], AXP_REG_AT);
+      assemble_tokens ("stq_u", newtok, 3, 1);
+    }
 }
 
 /* Store an integer to an unaligned address.  */
@@ -2724,14 +2832,14 @@ static void
 emit_ustX (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
   int lgsize = (int)(long)vlgsize;
   expressionS newtok[3];
 
   /* emit "lda $at, exp" */
 
-  memcpy (newtok, tok, sizeof(expressionS)*ntok);
+  memcpy (newtok, tok, sizeof (expressionS) * ntok);
   newtok[0].X_add_number = AXP_REG_AT;
   assemble_tokens ("lda", newtok, ntok, 1);
 
@@ -2807,22 +2915,29 @@ static void
 emit_sextX (tok, ntok, vlgsize)
      const expressionS *tok;
      int ntok;
-     void *vlgsize;
+     const PTR vlgsize;
 {
-  int bitshift = 64 - 8*(1 << (long)vlgsize);
-  expressionS newtok[3];
+  long lgsize = (long)vlgsize;
 
-  /* emit "sll src,bits,dst" */
+  if (alpha_target & AXP_OPCODE_BWX)
+    assemble_tokens (sextX_op[lgsize], tok, ntok, 0);
+  else
+    {
+      int bitshift = 64 - 8 * (1 << lgsize);
+      expressionS newtok[3];
 
-  newtok[0] = tok[0];
-  set_tok_const (newtok[1], bitshift);
-  newtok[2] = tok[ntok - 1];
-  assemble_tokens ("sll", newtok, 3, 1);
+      /* emit "sll src,bits,dst" */
+
+      newtok[0] = tok[0];
+      set_tok_const (newtok[1], bitshift);
+      newtok[2] = tok[ntok - 1];
+      assemble_tokens ("sll", newtok, 3, 1);
 
-  /* emit "sra dst,bits,dst" */
+      /* emit "sra dst,bits,dst" */
 
-  newtok[0] = newtok[2];
-  assemble_tokens ("sra", newtok, 3, 1);
+      newtok[0] = newtok[2];
+      assemble_tokens ("sra", newtok, 3, 1);
+    }
 }
 
 /* Implement the division and modulus macros.  */
@@ -2832,11 +2947,11 @@ emit_sextX (tok, ntok, vlgsize)
 /* Make register usage like in normal procedure call.
    Don't clobber PV and RA.  */
 
-static void 
+static void
 emit_division (tok, ntok, symname)
      const expressionS *tok;
      int ntok;
-     void *symname;
+     const PTR symname;
 {
   /* DIVISION and MODULUS. Yech.
    *
@@ -2850,7 +2965,7 @@ emit_division (tok, ntok, symname)
    *    mov R0,result
    *
    * with appropriate optimizations if R0,R16,R17 are the registers
-   * specified by the compiler. 
+   * specified by the compiler.
    */
 
   int xr, yr, rr;
@@ -2859,7 +2974,7 @@ emit_division (tok, ntok, symname)
 
   xr = regno (tok[0].X_add_number);
   yr = regno (tok[1].X_add_number);
-    
+
   if (ntok < 3)
     rr = xr;
   else
@@ -2932,11 +3047,11 @@ emit_division (tok, ntok, symname)
 
 #else /* !OBJ_EVAX */
 
-static void 
+static void
 emit_division (tok, ntok, symname)
      const expressionS *tok;
      int ntok;
-     void *symname;
+     const PTR symname;
 {
   /* DIVISION and MODULUS. Yech.
    * Convert
@@ -2949,7 +3064,7 @@ emit_division (tok, ntok, symname)
    *    mov t12,result
    *
    * with appropriate optimizations if t10,t11,t12 are the registers
-   * specified by the compiler. 
+   * specified by the compiler.
    */
 
   int xr, yr, rr;
@@ -2958,7 +3073,7 @@ emit_division (tok, ntok, symname)
 
   xr = regno (tok[0].X_add_number);
   yr = regno (tok[1].X_add_number);
-    
+
   if (ntok < 3)
     rr = xr;
   else
@@ -3045,7 +3160,7 @@ static void
 emit_jsrjmp (tok, ntok, vopname)
      const expressionS *tok;
      int ntok;
-     void *vopname;
+     const PTR vopname;
 {
   const char *opname = (const char *) vopname;
   struct alpha_insn insn;
@@ -3102,7 +3217,7 @@ emit_jsrjmp (tok, ntok, vopname)
 
   emit_insn (&insn);
 
-#if OBJ_EVAX
+#ifdef OBJ_EVAX
   alpha_basereg_clobbered = 0;
 
   /* reload PV from 0(FP) if it is our current base register.  */
@@ -3123,7 +3238,7 @@ static void
 emit_retjcr (tok, ntok, vopname)
      const expressionS *tok;
      int ntok;
-     void *vopname;
+     const PTR vopname;
 {
   const char *opname = (const char *)vopname;
   expressionS newtok[3];
@@ -3166,7 +3281,7 @@ s_alpha_text (i)
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
   alpha_current_align = 0;
-}  
+}
 
 /* Handle the .data pseudo-op.  This is like the usual one, but it
    clears alpha_insn_label and restores auto alignment.  */
@@ -3179,9 +3294,9 @@ s_alpha_data (i)
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
   alpha_current_align = 0;
-}  
+}
 
-#ifndef OBJ_ELF
+#ifdef OBJ_ECOFF
 
 /* Handle the OSF/1 .comm pseudo quirks.  */
 
@@ -3228,27 +3343,6 @@ s_alpha_comm (ignore)
       return;
     }
 
-#if OBJ_EVAX
-  {
-    /* Fill common area with zeros.  */
-    char *pfrag;
-    segT current_seg = now_seg;
-    subsegT current_subseg = now_subseg;
-  
-    subseg_set (bss_section, 1);
-    frag_align (3, 0);
-  
-    symbolP->sy_frag = frag_now;
-    pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
-                     temp, (char *)0);
-      
-    *pfrag = 0;
-    S_SET_SEGMENT (symbolP, bss_section);
-
-    subseg_set (current_seg, current_subseg);
-  }
-#endif
-
   if (S_GET_VALUE (symbolP))
     {
       if (S_GET_VALUE (symbolP) != (valueT) temp)
@@ -3263,16 +3357,14 @@ s_alpha_comm (ignore)
       S_SET_EXTERNAL (symbolP);
     }
 
-#ifndef OBJ_EVAX
   know (symbolP->sy_frag == &zero_address_frag);
-#endif
 
   demand_empty_rest_of_line ();
 }
 
 #endif /* ! OBJ_ELF */
 
-#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
+#ifdef OBJ_ECOFF
 
 /* Handle the .rdata pseudo-op.  This is like the usual one, but it
    clears alpha_insn_label and restores auto alignment.  */
@@ -3318,7 +3410,7 @@ s_alpha_sdata (ignore)
 /* Handle the .section pseudo-op.  This is like the usual one, but it
    clears alpha_insn_label and restores auto alignment.  */
 
-static void 
+static void
 s_alpha_section (ignore)
      int ignore;
 {
@@ -3329,17 +3421,29 @@ s_alpha_section (ignore)
   alpha_current_align = 0;
 }
 
-#endif  
+#endif
 
 #ifdef OBJ_EVAX
+  
+/* Handle the section specific pseudo-op.  */
+  
 static void
-s_alpha_link (ignore)
-     int ignore;
+s_alpha_section (secid)
+     int secid;
 {
   int temp;
+#define EVAX_SECTION_COUNT 6
+  static char *section_name[EVAX_SECTION_COUNT+1] =
+    { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors", ".lcomm" };
 
+  if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
+    {
+      as_fatal ("Unknown section directive");
+      demand_empty_rest_of_line ();
+      return;
+    }
   temp = get_absolute_expression ();
-  subseg_new (".link", 0);
+  subseg_new (section_name[secid], 0);
   demand_empty_rest_of_line ();
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
@@ -3514,7 +3618,7 @@ s_alpha_pdesc (ignore)
   md_flush_pending_output ();
 #endif
 
-  frag_align (3, 0);
+  frag_align (3, 0, 0);
   p = frag_more (16);
   fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
   fixp->fx_done = 1;
@@ -3585,6 +3689,47 @@ s_alpha_pdesc (ignore)
 }
 
 
+/* Support for crash debug on vms.  */
+
+static void
+s_alpha_name (ignore)
+     int ignore;
+{
+  register char *p;
+  expressionS exp;
+  segment_info_type *seginfo = seg_info (alpha_link_section);
+
+  if (now_seg != alpha_link_section)
+    {
+      as_bad (".name directive not in link (.link) section");
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  expression (&exp);
+  if (exp.X_op != O_symbol)
+    {
+      as_warn (".name directive has no symbol");
+      demand_empty_rest_of_line ();
+      return;
+    }
+
+  demand_empty_rest_of_line ();
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  frag_align (3, 0, 0);
+  p = frag_more (8);
+  seginfo->literal_pool_size += 8;
+
+  fix_new_exp (frag_now, p-frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64);
+
+  return;
+}
+
+
 static void
 s_alpha_linkage (ignore)
      int ignore;
@@ -3614,6 +3759,35 @@ s_alpha_linkage (ignore)
 }
 
 
+static void
+s_alpha_code_address (ignore)
+     int ignore;
+{
+  expressionS exp;
+  char *p;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  expression (&exp);
+  if (exp.X_op != O_symbol)
+    {
+      as_fatal ("No symbol after .code_address");
+    }
+  else
+    {
+      p = frag_more (8);
+      memset (p, 0, 8);
+      fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\
+                  BFD_RELOC_ALPHA_CODEADDR);
+    }
+  demand_empty_rest_of_line ();
+
+  return;
+}
+
+
 static void
 s_alpha_fp_save (ignore)
      int ignore;
@@ -3689,17 +3863,14 @@ static void
 s_alpha_file (ignore)
      int ignore;
 {
-  symbolSs;
+  symbolS *s;
   int length;
   static char case_hack[32];
 
   extern char *demand_copy_string PARAMS ((int *lenP));
 
-  sprintf (case_hack, "<CASE:%01d%01d%01d%01d>",
-           alpha_flag_hash_long_names,
-           alpha_flag_show_after_trunc,
-           alpha_flag_no_hash_mixed_case,
-           alpha_vms_name_mapping);
+  sprintf (case_hack, "<CASE:%01d%01d>",
+           alpha_flag_hash_long_names, alpha_flag_show_after_trunc);
 
   s = symbol_find_or_make (case_hack);
   s->bsym->flags |= BSF_FILE;
@@ -4004,19 +4175,48 @@ alpha_cons_align (size)
   alpha_insn_label = NULL;
 }
 \f
+
+#ifdef DEBUG1
+/* print token expression with alpha specific extension.  */
+
+static void
+alpha_print_token(f, exp)
+    FILE *f;
+    const expressionS *exp;
+{
+  switch (exp->X_op)
+    {
+      case O_cpregister:
+       putc (',', f);
+       /* FALLTHRU */
+      case O_pregister:
+       putc ('(', f);
+       {
+         expressionS nexp = *exp;
+         nexp.X_op = O_register;
+         print_expr (f, &nexp);
+       }
+       putc (')', f);
+       break;
+      default:
+       print_expr (f, exp);
+       break;
+    }
+  return;
+}
+#endif
+\f
 /* The target specific pseudo-ops which we support.  */
 
 const pseudo_typeS md_pseudo_table[] =
 {
   {"common", s_comm, 0},       /* is this used? */
-#ifndef OBJ_ELF
+#ifdef OBJ_ECOFF
   {"comm", s_alpha_comm, 0},   /* osf1 compiler does this */
+  {"rdata", s_alpha_rdata, 0},
 #endif
   {"text", s_alpha_text, 0},
   {"data", s_alpha_data, 0},
-#if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
-  {"rdata", s_alpha_rdata, 0},
-#endif
 #ifdef OBJ_ECOFF
   {"sdata", s_alpha_sdata, 0},
 #endif
@@ -4028,15 +4228,22 @@ const pseudo_typeS md_pseudo_table[] =
 #endif
 #ifdef OBJ_EVAX
   { "pdesc", s_alpha_pdesc, 0},
+  { "name", s_alpha_name, 0},
   { "linkage", s_alpha_linkage, 0},
+  { "code_address", s_alpha_code_address, 0},
   { "ent", s_alpha_ent, 0},
   { "frame", s_alpha_frame, 0},
   { "fp_save", s_alpha_fp_save, 0},
   { "mask", s_alpha_mask, 0},
   { "fmask", s_alpha_fmask, 0},
-  { "link", s_alpha_link, 0},
   { "end", s_alpha_end, 0},
   { "file", s_alpha_file, 0},
+  { "rdata", s_alpha_section, 1},
+  { "comm", s_alpha_section, 2},
+  { "link", s_alpha_section, 3},
+  { "ctors", s_alpha_section, 4},
+  { "dtors", s_alpha_section, 5},
+  { "lcomm", s_alpha_section, 6},
 #endif
   {"gprel32", s_alpha_gprel32, 0},
   {"t_floating", s_alpha_float_cons, 'd'},
@@ -4173,14 +4380,14 @@ alpha_align (n, pfill, label)
             no-op instructions.  This will zero-fill, then nop-fill
             with proper alignment.  */
          if (alpha_current_align < 2)
-           frag_align (2, 0);
-         frag_align_pattern (n, nop, sizeof nop);
+           frag_align (2, 0, 0);
+         frag_align_pattern (n, nop, sizeof nop, 0);
        }
       else
-       frag_align (n, 0);
+       frag_align (n, 0, 0);
     }
   else
-    frag_align (n, *pfill);
+    frag_align (n, *pfill, 0);
 
   alpha_current_align = n;
 
index 2ea147d152a7c9181ccaca3cf4275f054ef5a9c2..644d89b2ce2058d294111dab5f0900adaafbc95d 100644 (file)
@@ -1,10 +1,8 @@
-/* tc-arm.c  All the arm specific stuff in one convenient, huge,
-   slow to compile, easy to find file.
+/* tc-arm.c -- Assemble for the ARM
+   Copyright (C) 1994, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
        Modified by David Taylor (dtaylor@armltd.co.uk)
 
-   Copyright (C) 1994, 1995 Free Software Foundation, Inc.
-
    This file is part of GAS, the GNU Assembler.
 
    GAS is free software; you can redistribute it and/or modify
@@ -18,8 +16,9 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GAS; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include <ctype.h>
 #include <string.h>
 #define ARM_1          0x00000001
 #define ARM_2          0x00000002
 #define ARM_3          0x00000004
-#define ARM_250                0x00000004      /* ARM3 instruction set */
+#define ARM_250                ARM_3
 #define ARM_6          0x00000008
-#define ARM_7          0x00000008
+#define ARM_7          ARM_6           /* same core instruction set */
 
 /* The following bitmasks control CPU extensions (ARM7 onwards): */
 #define ARM_LONGMUL    0x00000010      /* allow long multiplies */
-#define ARM_HALFWORD    0x00000020      /* allow ARM 16bit memory transfers */
+#define ARM_ARCH4       0x00000020
+#define ARM_THUMB       ARM_ARCH4
 
 /* Some useful combinations:  */
 #define ARM_ANY                0x00ffffff
@@ -103,13 +103,21 @@ CONST char EXP_CHARS[] = "eE";
 
 CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";
 
-const int md_reloc_size = 8;           /* Size of relocation record */
+CONST int md_reloc_size = 8;           /* Size of relocation record */
+
+static int thumb_mode = 0;      /* non-zero if assembling thumb instructions */
+
+typedef struct arm_fix
+{
+  int thumb_mode;
+} arm_fix_data;
 
 struct arm_it
 {
   CONST char *error;
   unsigned long instruction;
   int suffix;
+  int size;
   struct
     {
       bfd_reloc_code_real_type type;
@@ -171,6 +179,8 @@ LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
 #define CP_T_UD  0x00800000
 #define CP_T_WB  0x00200000
 
+#define CONDS_BIT       (0x00100000)
+#define LOAD_BIT        (0x00100000)
 #define TRANS_BIT      (0x00200000)
 
 struct asm_cond
@@ -202,102 +212,133 @@ static CONST struct asm_cond conds[] =
   {"nv", 0xf0000000}
 };
 
-
+/* Warning: If the top bit of the set_bits is set, then the standard
+   instruction bitmask is ignored, and the new bitmask is taken from
+   the set_bits: */
 struct asm_flg
 {
   CONST char *template;                /* Basic flag string */
   unsigned long set_bits;      /* Bits to set */
-  unsigned long variants;       /* Which CPU variants this exists for */
 };
 
 static CONST struct asm_flg s_flag[] =
 {
-  {"s", 0x00100000, ARM_ANY},
-  {NULL, 0, 0}
+  {"s", CONDS_BIT},
+  {NULL, 0}
+};
+
+static CONST struct asm_flg ldr_flags[] =
+{
+  {"b",  0x00400000},
+  {"t",  TRANS_BIT},
+  {"bt", 0x00400000 | TRANS_BIT},
+  {"h",  0x801000b0},
+  {"sh", 0x801000f0},
+  {"sb", 0x801000d0},
+  {NULL, 0}
 };
 
-static CONST struct asm_flg ldst_flags[] =
+static CONST struct asm_flg str_flags[] =
 {
-  {"b",  0x00400000, ARM_ANY},
-  {"t",  TRANS_BIT, ARM_ANY},
-  {"bt", 0x00400000 | TRANS_BIT, ARM_ANY},
-  {"h",  0x00000020, ARM_HALFWORD},
-  {"sb", 0x00000040, ARM_HALFWORD},
-  {"sh", 0x00000060, ARM_HALFWORD},
-  {NULL, 0, 0},
+  {"b",  0x00400000},
+  {"t",  TRANS_BIT},
+  {"bt", 0x00400000 | TRANS_BIT},
+  {"h",  0x800000b0},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg byte_flag[] =
 {
-  {"b", 0x00400000, ARM_3UP},
-  {NULL, 0, 0}
+  {"b", 0x00400000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg cmp_flags[] =
 {
-  {"s", 0x00100000, ARM_ANY},
-  {"p", 0x0010f000, ARM_ANY},
-  {NULL, 0, 0}
+  {"s", CONDS_BIT},
+  {"p", 0x0010f000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg ldm_flags[] =
 {
-  {"ed", 0x01800000, ARM_ANY},
-  {"fd", 0x00800000, ARM_ANY},
-  {"ea", 0x01000000, ARM_ANY},
-  {"fa", 0x08000000, ARM_ANY},
-  {"ib", 0x01800000, ARM_ANY},
-  {"ia", 0x00800000, ARM_ANY},
-  {"db", 0x01000000, ARM_ANY},
-  {"da", 0x08000000, ARM_ANY},
-  {NULL, 0, 0}
+  {"ed", 0x01800000},
+  {"fd", 0x00800000},
+  {"ea", 0x01000000},
+  {"fa", 0x08000000},
+  {"ib", 0x01800000},
+  {"ia", 0x00800000},
+  {"db", 0x01000000},
+  {"da", 0x08000000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg stm_flags[] =
 {
-  {"ed", 0x08000000, ARM_ANY},
-  {"fd", 0x01000000, ARM_ANY},
-  {"ea", 0x00800000, ARM_ANY},
-  {"fa", 0x01800000, ARM_ANY},
-  {"ib", 0x01800000, ARM_ANY},
-  {"ia", 0x00800000, ARM_ANY},
-  {"db", 0x01000000, ARM_ANY},
-  {"da", 0x08000000, ARM_ANY},
-  {NULL, 0, 0}
+  {"ed", 0x08000000},
+  {"fd", 0x01000000},
+  {"ea", 0x00800000},
+  {"fa", 0x01800000},
+  {"ib", 0x01800000},
+  {"ia", 0x00800000},
+  {"db", 0x01000000},
+  {"da", 0x08000000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg lfm_flags[] =
 {
-  {"fd", 0x00800000, FPU_MEMMULTI},
-  {"ea", 0x01000000, FPU_MEMMULTI},
-  {NULL, 0, 0}
+  {"fd", 0x00800000},
+  {"ea", 0x01000000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg sfm_flags[] =
 {
-  {"fd", 0x01000000, FPU_MEMMULTI},
-  {"ea", 0x00800000, FPU_MEMMULTI},
-  {NULL, 0, 0}
+  {"fd", 0x01000000},
+  {"ea", 0x00800000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg round_flags[] =
 {
-  {"p", 0x00000020, FPU_ALL},
-  {"m", 0x00000040, FPU_ALL},
-  {"z", 0x00000060, FPU_ALL},
-  {NULL, 0, 0}
+  {"p", 0x00000020},
+  {"m", 0x00000040},
+  {"z", 0x00000060},
+  {NULL, 0}
+};
+
+/* The implementation of the FIX instruction is broken on some assemblers,
+   in that it accepts a precision specifier as well as a rounding specifier,
+   despite the fact that this is meaningless.  To be more compatible, we
+   accept it as well, though of course it does not set any bits.  */
+static CONST struct asm_flg fix_flags[] =
+{
+  {"p", 0x00000020},
+  {"m", 0x00000040},
+  {"z", 0x00000060},
+  {"sp", 0x00000020},
+  {"sm", 0x00000040},
+  {"sz", 0x00000060},
+  {"dp", 0x00000020},
+  {"dm", 0x00000040},
+  {"dz", 0x00000060},
+  {"ep", 0x00000020},
+  {"em", 0x00000040},
+  {"ez", 0x00000060},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg except_flag[] =
 {
-  {"e", 0x00400000, FPU_ALL},
-  {NULL, 0, 0}
+  {"e", 0x00400000},
+  {NULL, 0}
 };
 
 static CONST struct asm_flg cplong_flag[] =
 {
-  {"l", 0x00400000, ARM_2UP},
-  {NULL, 0, 0}
+  {"l", 0x00400000},
+  {NULL, 0}
 };
 
 struct asm_psr
@@ -343,6 +384,8 @@ static void do_msr          PARAMS ((char *operands, unsigned long flags));
 static void do_mrs             PARAMS ((char *operands, unsigned long flags));
 /* ARM 7M */
 static void do_mull            PARAMS ((char *operands, unsigned long flags));
+/* ARM THUMB */
+static void do_bx               PARAMS ((char *operands, unsigned long flags));
 
 /* Coprocessor Instructions */
 static void do_cdp             PARAMS ((char *operands, unsigned long flags));
@@ -364,12 +407,12 @@ static int arm_reg_parse  PARAMS ((char **ccp));
 static int arm_psr_parse       PARAMS ((char **ccp));
 
 /* ARM instructions take 4bytes in the object file, Thumb instructions
-   take 2. The assembler defaults to ARM code generation: */
-static int insn_size = 4;
+   take 2: */
+#define INSN_SIZE       4
 
 /* LONGEST_INST is the longest basic instruction name without conditions or 
  * flags.
- * ARM7DM has 4 of length 5
+ * ARM7M has 4 of length 5
  */
 
 #define LONGEST_INST 5
@@ -403,13 +446,13 @@ static CONST struct asm_opcode insns[] =
   {"cmn",   0x01600000, NULL,   cmp_flags,   ARM_ANY,      do_cmp},
   {"mov",   0x01a00000, NULL,   s_flag,      ARM_ANY,      do_mov},
   {"mvn",   0x01e00000, NULL,   s_flag,      ARM_ANY,      do_mov},
-  {"str",   0x04000000, NULL,   ldst_flags,  ARM_ANY,      do_ldst},
-  {"ldr",   0x04100000, NULL,   ldst_flags,  ARM_ANY,      do_ldst},
+  {"str",   0x04000000, NULL,   str_flags,   ARM_ANY,      do_ldst},
+  {"ldr",   0x04100000, NULL,   ldr_flags,   ARM_ANY,      do_ldst},
   {"stm",   0x08000000, NULL,   stm_flags,   ARM_ANY,      do_ldmstm},
   {"ldm",   0x08100000, NULL,   ldm_flags,   ARM_ANY,      do_ldmstm},
   {"swi",   0x0f000000, NULL,   NULL,        ARM_ANY,      do_swi},
-  {"bl",    0x0b000000, NULL,   NULL,        ARM_ANY,      do_branch},
-  {"b",     0x0a000000, NULL,   NULL,        ARM_ANY,      do_branch},
+  {"bl",    0x0bfffffe, NULL,   NULL,        ARM_ANY,      do_branch},
+  {"b",     0x0afffffe, NULL,   NULL,        ARM_ANY,      do_branch},
 
 /* Pseudo ops */
   {"adr",   0x028f0000, NULL,   NULL,        ARM_ANY,      do_adr},
@@ -432,6 +475,9 @@ static CONST struct asm_opcode insns[] =
   {"smlal", 0x00e00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
   {"umlal", 0x00a00090, NULL,   s_flag,      ARM_LONGMUL,  do_mull},
 
+/* ARM THUMB interworking */
+  {"bx",    0x012fff10, NULL,   NULL,        ARM_THUMB,    do_bx},
+
 /* Floating point instructions */
   {"wfs",   0x0e200110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
   {"rfs",   0x0e300110, NULL,   NULL,        FPU_ALL,      do_fp_ctrl},
@@ -478,7 +524,7 @@ static CONST struct asm_opcode insns[] =
   {"cmfe",  0x0ed0f110, NULL,   NULL,        FPU_ALL,      do_fp_cmp},
   {"cnfe",  0x0ef0f110, NULL,   NULL,        FPU_ALL,      do_fp_cmp},
   {"flt",   0x0e000110, "sde",  round_flags, FPU_ALL,      do_fp_from_reg},
-  {"fix",   0x0e100110, NULL,   round_flags, FPU_ALL,      do_fp_to_reg},
+  {"fix",   0x0e100110, NULL,   fix_flags,   FPU_ALL,      do_fp_to_reg},
 
 /* Generic copressor instructions */
   {"cdp",   0x0e000000, NULL,  NULL,         ARM_2UP,      do_cdp},
@@ -523,6 +569,176 @@ static CONST struct asm_opcode insns[] =
 #define OPCODE_BIC     14
 #define OPCODE_MVN     15
 
+static void do_t_arit          PARAMS ((char *operands));
+static void do_t_add           PARAMS ((char *operands));
+static void do_t_asr           PARAMS ((char *operands));
+static void do_t_branch                PARAMS ((char *operands));
+static void do_t_bx            PARAMS ((char *operands));
+static void do_t_compare       PARAMS ((char *operands));
+static void do_t_ldmstm                PARAMS ((char *operands));
+static void do_t_ldr           PARAMS ((char *operands));
+static void do_t_ldrb          PARAMS ((char *operands));
+static void do_t_ldrh          PARAMS ((char *operands));
+static void do_t_lds           PARAMS ((char *operands));
+static void do_t_lsl           PARAMS ((char *operands));
+static void do_t_lsr           PARAMS ((char *operands));
+static void do_t_mov           PARAMS ((char *operands));
+static void do_t_push_pop      PARAMS ((char *operands));
+static void do_t_str           PARAMS ((char *operands));
+static void do_t_strb          PARAMS ((char *operands));
+static void do_t_strh          PARAMS ((char *operands));
+static void do_t_sub           PARAMS ((char *operands));
+static void do_t_swi           PARAMS ((char *operands));
+static void do_t_adr           PARAMS ((char *operands));
+
+#define T_OPCODE_MUL 0x4340
+#define T_OPCODE_TST 0x4200
+#define T_OPCODE_CMN 0x42c0
+#define T_OPCODE_NEG 0x4240
+#define T_OPCODE_MVN 0x43c0
+
+#define T_OPCODE_ADD_R3        0x1800
+#define T_OPCODE_SUB_R3 0x1a00
+#define T_OPCODE_ADD_HI 0x4400
+#define T_OPCODE_ADD_ST 0xb000
+#define T_OPCODE_SUB_ST 0xb080
+#define T_OPCODE_ADD_SP 0xa800
+#define T_OPCODE_ADD_PC 0xa000
+#define T_OPCODE_ADD_I8 0x3000
+#define T_OPCODE_SUB_I8 0x3800
+#define T_OPCODE_ADD_I3 0x1c00
+#define T_OPCODE_SUB_I3 0x1e00
+
+#define T_OPCODE_ASR_R 0x4100
+#define T_OPCODE_LSL_R 0x4080
+#define T_OPCODE_LSR_R  0x40c0
+#define T_OPCODE_ASR_I 0x1000
+#define T_OPCODE_LSL_I 0x0000
+#define T_OPCODE_LSR_I 0x0800
+
+#define T_OPCODE_MOV_I8        0x2000
+#define T_OPCODE_CMP_I8 0x2800
+#define T_OPCODE_CMP_LR 0x4280
+#define T_OPCODE_MOV_HR 0x4600
+#define T_OPCODE_CMP_HR 0x4500
+
+#define T_OPCODE_LDR_PC 0x4800
+#define T_OPCODE_LDR_SP 0x9800
+#define T_OPCODE_STR_SP 0x9000
+#define T_OPCODE_LDR_IW 0x6800
+#define T_OPCODE_STR_IW 0x6000
+#define T_OPCODE_LDR_IH 0x8800
+#define T_OPCODE_STR_IH 0x8000
+#define T_OPCODE_LDR_IB 0x7800
+#define T_OPCODE_STR_IB 0x7000
+#define T_OPCODE_LDR_RW 0x5800
+#define T_OPCODE_STR_RW 0x5000
+#define T_OPCODE_LDR_RH 0x5a00
+#define T_OPCODE_STR_RH 0x5200
+#define T_OPCODE_LDR_RB 0x5c00
+#define T_OPCODE_STR_RB 0x5400
+
+#define T_OPCODE_PUSH  0xb400
+#define T_OPCODE_POP   0xbc00
+
+#define T_OPCODE_BRANCH 0xe7fe
+
+static int thumb_reg           PARAMS ((char **str, int hi_lo));
+
+#define THUMB_SIZE     2       /* Size of thumb instruction */
+#define THUMB_REG_LO   0x1
+#define THUMB_REG_HI   0x2
+#define THUMB_REG_ANY  0x3
+
+#define THUMB_H1       0x0080
+#define THUMB_H2       0x0040
+
+#define THUMB_ASR 0
+#define THUMB_LSL 1
+#define THUMB_LSR 2
+
+#define THUMB_MOVE 0
+#define THUMB_COMPARE 1
+
+#define THUMB_LOAD 0
+#define THUMB_STORE 1
+
+#define THUMB_PP_PC_LR 0x0100
+
+/* These three are used for immediate shifts, do not alter */
+#define THUMB_WORD 2
+#define THUMB_HALFWORD 1
+#define THUMB_BYTE 0
+
+struct thumb_opcode 
+{
+  CONST char *template;                /* Basic string to match */
+  unsigned long value;         /* Basic instruction code */
+  int size;
+  void (*parms)();             /* Function to call to parse args */
+};
+
+static CONST struct thumb_opcode tinsns[] =
+{
+  {"adc",      0x4140,         2,      do_t_arit},
+  {"add",      0x0000,         2,      do_t_add},
+  {"and",      0x4000,         2,      do_t_arit},
+  {"asr",      0x0000,         2,      do_t_asr},
+  {"b",                T_OPCODE_BRANCH, 2,     do_t_branch},
+  {"beq",      0xd0fe,         2,      do_t_branch},
+  {"bne",      0xd1fe,         2,      do_t_branch},
+  {"bcs",      0xd2fe,         2,      do_t_branch},
+  {"bhs",      0xd2fe,         2,      do_t_branch},
+  {"bcc",      0xd3fe,         2,      do_t_branch},
+  {"bul",      0xd3fe,         2,      do_t_branch},
+  {"blo",      0xd3fe,         2,      do_t_branch},
+  {"bmi",      0xd4fe,         2,      do_t_branch},
+  {"bpl",      0xd5fe,         2,      do_t_branch},
+  {"bvs",      0xd6fe,         2,      do_t_branch},
+  {"bvc",      0xd7fe,         2,      do_t_branch},
+  {"bhi",      0xd8fe,         2,      do_t_branch},
+  {"bls",      0xd9fe,         2,      do_t_branch},
+  {"bge",      0xdafe,         2,      do_t_branch},
+  {"blt",      0xdbfe,         2,      do_t_branch},
+  {"bgt",      0xdcfe,         2,      do_t_branch},
+  {"ble",      0xddfe,         2,      do_t_branch},
+  {"bic",      0x4380,         2,      do_t_arit},
+  {"bl",       0xf7fffffe,     4,      do_t_branch},
+  {"bx",       0x4700,         2,      do_t_bx},
+  {"cmn",      T_OPCODE_CMN,   2,      do_t_arit},
+  {"cmp",      0x0000,         2,      do_t_compare},
+  {"eor",      0x4040,         2,      do_t_arit},
+  {"ldmia",    0xc800,         2,      do_t_ldmstm},
+  {"ldr",      0x0000,         2,      do_t_ldr},
+  {"ldrb",     0x0000,         2,      do_t_ldrb},
+  {"ldrh",     0x0000,         2,      do_t_ldrh},
+  {"ldrsb",    0x5600,         2,      do_t_lds},
+  {"ldrsh",    0x5e00,         2,      do_t_lds},
+  {"ldsb",     0x5600,         2,      do_t_lds},
+  {"ldsh",     0x5e00,         2,      do_t_lds},
+  {"lsl",      0x0000,         2,      do_t_lsl},
+  {"lsr",      0x0000,         2,      do_t_lsr},
+  {"mov",      0x0000,         2,      do_t_mov},
+  {"mul",      T_OPCODE_MUL,   2,      do_t_arit},
+  {"mvn",      T_OPCODE_MVN,   2,      do_t_arit},
+  {"neg",      T_OPCODE_NEG,   2,      do_t_arit},
+  {"orr",      0x4300,         2,      do_t_arit},
+  {"pop",      0xbc00,         2,      do_t_push_pop},
+  {"push",     0xb400,         2,      do_t_push_pop},
+  {"ror",      0x41c0,         2,      do_t_arit},
+  {"sbc",      0x4180,         2,      do_t_arit},
+  {"stmia",    0xc000,         2,      do_t_ldmstm},
+  {"str",      0x0000,         2,      do_t_str},
+  {"strb",     0x0000,         2,      do_t_strb},
+  {"strh",     0x0000,         2,      do_t_strh},
+  {"swi",      0xdf00,         2,      do_t_swi},
+  {"sub",      0x0000,         2,      do_t_sub},
+  {"tst",      T_OPCODE_TST,   2,      do_t_arit},
+  /* Pseudo ops: */
+  {"adr",       0x0000,         2,      do_t_adr},
+  {"nop",       0x0000,         2,      do_nop},
+};
+
 struct reg_entry
 {
   CONST char *name;
@@ -534,20 +750,22 @@ struct reg_entry
 #define fp_register(reg) ((reg) >= 16 && (reg) <= 23)
 
 #define REG_PC 15
+#define REG_LR  14
+#define REG_SP  13
 
 /* These are the standard names;  Users can add aliases with .req */
 static CONST struct reg_entry reg_table[] =
 {
   /* Processor Register Numbers */
-  {"r0", 0},    {"r1", 1},    {"r2", 2},    {"r3", 3},
-  {"r4", 4},    {"r5", 5},    {"r6", 6},    {"r7", 7},
-  {"r8", 8},    {"r9", 9},    {"r10", 10},  {"r11", 11},
-  {"r12", 12},  {"r13", 13},  {"r14", 14},  {"r15", REG_PC},
+  {"r0", 0},    {"r1", 1},      {"r2", 2},      {"r3", 3},
+  {"r4", 4},    {"r5", 5},      {"r6", 6},      {"r7", 7},
+  {"r8", 8},    {"r9", 9},      {"r10", 10},    {"r11", 11},
+  {"r12", 12},  {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC},
   /* APCS conventions */
-  {"a1", 0},   {"a2", 1},    {"a3", 2},    {"a4", 3},
-  {"v1", 4},   {"v2", 5},    {"v3", 6},    {"v4", 7},     {"v5", 8},
-  {"v6", 9},   {"sb", 9},    {"v7", 10},   {"sl", 10},
-  {"fp", 11},  {"ip", 12},   {"sp", 13},   {"lr", 14},    {"pc", REG_PC},
+  {"a1", 0},   {"a2", 1},    {"a3", 2},     {"a4", 3},
+  {"v1", 4},   {"v2", 5},    {"v3", 6},     {"v4", 7},     {"v5", 8},
+  {"v6", 9},   {"sb", 9},    {"v7", 10},    {"sl", 10},
+  {"fp", 11},  {"ip", 12},   {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC},
   /* FP Registers */
   {"f0", 16},   {"f1", 17},   {"f2", 18},   {"f3", 19},
   {"f4", 20},   {"f5", 21},   {"f6", 22},   {"f7", 23},
@@ -566,6 +784,7 @@ static CONST char *bad_args = "Bad arguments to instruction";
 static CONST char *bad_pc = "r15 not allowed here";
 
 static struct hash_control *arm_ops_hsh = NULL;
+static struct hash_control *arm_tops_hsh = NULL;
 static struct hash_control *arm_cond_hsh = NULL;
 static struct hash_control *arm_shift_hsh = NULL;
 static struct hash_control *arm_reg_hsh = NULL;
@@ -583,6 +802,9 @@ static void s_align PARAMS ((int));
 static void s_bss PARAMS ((int));
 static void s_even PARAMS ((int));
 static void s_ltorg PARAMS ((int));
+static void s_arm PARAMS ((int));
+static void s_thumb PARAMS ((int));
+static void s_code PARAMS ((int));
 
 static int my_get_expression PARAMS ((expressionS *, char **));
 
@@ -591,6 +813,9 @@ CONST pseudo_typeS md_pseudo_table[] =
   {"req", s_req, 0},   /* Never called becasue '.req' does not start line */
   {"bss", s_bss, 0},
   {"align", s_align, 0},
+  {"arm", s_arm, 0},
+  {"thumb", s_thumb, 0},
+  {"code", s_code, 0},
   {"even", s_even, 0},
   {"ltorg", s_ltorg, 0},
   {"pool", s_ltorg, 0},
@@ -668,7 +893,7 @@ add_to_lit_pool ()
 }
  
 /* Can't use symbol_new here, so have to create a symbol and them at
-   a later datete assign iot a value. Thats what these functions do */
+   a later date assign it a value. Thats what these functions do */
 static void
 symbol_locate (symbolP, name, segment, valu, frag)
      symbolS *symbolP; 
@@ -807,7 +1032,7 @@ s_even (ignore)
      int ignore;
 {
   if (!need_pass_2)            /* Never make frag if expect extra pass. */
-    frag_align (1, 0);
+    frag_align (1, 0, 0);
   record_alignment (now_seg, 1);
   demand_empty_rest_of_line ();
 }
@@ -830,7 +1055,7 @@ s_ltorg (internal)
   /* Align pool as you have word accesses */
   /* Only make a frag if we have to ... */
   if (!need_pass_2)
-    frag_align (2, 0);
+    frag_align (2, 0, 0);
 
   record_alignment (now_seg, 2);
 
@@ -859,7 +1084,7 @@ arm_align (power, fill)
 {
   /* Only make a frag if we HAVE to ... */
   if (power && !need_pass_2)
-    frag_align (power, fill);
+    frag_align (power, fill, 0);
 
   record_alignment (now_seg, power);
 }
@@ -895,12 +1120,82 @@ s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
 
   /* Only make a frag if we HAVE to. . . */
   if (temp && !need_pass_2)
-    frag_align (temp, (int) temp_fill);
+    frag_align (temp, (int) temp_fill, 0);
   demand_empty_rest_of_line ();
 
   record_alignment (now_seg, temp);
 }
 
+static void
+opcode_select (width)
+     int width;
+{
+  switch (width)
+    {
+    case 16:
+      if (! thumb_mode)
+       {
+         if (! (cpu_variant & ARM_THUMB))
+           as_bad ("selected processor does not support THUMB opcodes");
+         thumb_mode = 1;
+          /* No need to force the alignment, since we will have been
+             coming from ARM mode, which is word-aligned. */
+          record_alignment (now_seg, 1);
+       }
+      break;
+
+    case 32:
+      if (thumb_mode)
+       {
+          if ((cpu_variant & ARM_ANY) == ARM_THUMB)
+           as_bad ("selected processor does not support ARM opcodes");
+         thumb_mode = 0;
+          if (!need_pass_2)
+            frag_align (2, 0, 0);
+          record_alignment (now_seg, 1);
+       }
+      break;
+
+    default:
+      as_bad ("invalid instruction size selected (%d)", width);
+    }
+}
+
+static void
+s_arm (ignore)
+     int ignore;
+{
+  opcode_select (32);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_thumb (ignore)
+     int ignore;
+{
+  opcode_select (16);
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_code (unused)
+     int unused;
+{
+  register int temp;
+
+  temp = get_absolute_expression ();
+  switch (temp)
+    {
+    case 16:
+    case 32:
+      opcode_select(temp);
+      break;
+
+    default:
+      as_bad ("invalid operand to .code directive (%d)", temp);
+    }
+}
+
 static void
 end_of_line (str)
      char *str;
@@ -1724,7 +2019,8 @@ decode_shift (str, unrestrict)
   *p = c;
   if (shft)
     {
-      if (!strcmp (*str, "rrx"))
+      if (!strcmp (*str, "rrx")
+          || !strcmp (*str, "RRX"))
        {
          *str = p;
          inst.instruction |= shft->value;
@@ -1748,12 +2044,12 @@ decode_shift (str, unrestrict)
            return FAIL;
 
          /* Validate some simple #expressions */
-         if (! inst.reloc.exp.X_add_symbol)
+         if (inst.reloc.exp.X_op == O_constant)
            {
-             int num = inst.reloc.exp.X_add_number;
-             if (num < 0 || num > 32
-                 || (num == 32 
-                     && (shft->value == 0 || shft->value == 0x60)))
+             unsigned num = inst.reloc.exp.X_add_number;
+
+             /* Reject operations greater than 32, or lsl #32 */
+             if (num > 32 || (num == 32 && shft->value == 0))
                {
                  inst.error = "Invalid immediate shift";
                  return FAIL;
@@ -2060,8 +2356,8 @@ do_adr (str, flags)
      char *str;
      unsigned long flags;
 {
-  /* This is a pseudo-op of the form "adr rd, label" to be converted into
-     a relative address of the form add rd, pc, #label-.-8 */
+  /* This is a pseudo-op of the form "adr rd, label" to be converted
+     into a relative address of the form "add rd, pc, #label-.-8" */
 
   while (*str == ' ')
     str++;
@@ -2109,7 +2405,7 @@ do_cmp (str, flags)
 
   inst.instruction |= flags;
   if ((flags & 0x0000f000) == 0)
-    inst.instruction |= 0x00100000;
+    inst.instruction |= CONDS_BIT;
 
   end_of_line (str);
   return;
@@ -2208,12 +2504,12 @@ ldst_extend (str, hwse)
       if (hwse)
         inst.instruction |= add;
       else
-        inst.instruction |= add | OFFSET_REG;
+        {
+          inst.instruction |= add | OFFSET_REG;
+          if (skip_past_comma (str) == SUCCESS)
+            return decode_shift (str, SHIFT_RESTRICT);
+        }
 
-      /* Shifts are not allowed in the halfword and signextension
-         forms of single memory transfers: */
-      if (!hwse && skip_past_comma (str) == SUCCESS)
-       return decode_shift (str, SHIFT_RESTRICT);
       return SUCCESS;
     }
 }
@@ -2224,28 +2520,28 @@ do_ldst (str, flags)
      unsigned long flags;
 {
   int halfword = 0;
-  int signextend = 0;
   int pre_inc = 0;
   int conflict_reg;
   int value;
 
   /* This is not ideal, but it is the simplest way of dealing with the
-     ARM7T extension instructions (since they use a different
+     ARM7T halfword instructions (since they use a different
      encoding, but the same mnemonic): */
-  halfword = flags & 0x00000020;
-  signextend = flags & 0x00000040;
-  if (halfword || signextend)
+  if (halfword = ((flags & 0x80000000) != 0))
     {
       /* This is actually a load/store of a halfword, or a
          signed-extension load */
-      inst.instruction = (inst.instruction & COND_MASK)
-                         | 0x00000090
-                         | (inst.instruction & 0x00100000);
-      if (signextend && !(inst.instruction & 0x00100000))
+      if ((cpu_variant & ARM_ARCH4) == 0)
         {
-         inst.error = "Sign-extension not applicable to store instructions";
-         return;
+          inst.error
+           = "Processor does not support halfwords or signed bytes\n";
+          return;
         }
+
+      inst.instruction = (inst.instruction & COND_MASK)
+                         | (flags & ~COND_MASK);
+
+      flags = 0;
     }
 
   while (*str == ' ')
@@ -2279,7 +2575,7 @@ do_ldst (str, flags)
        }
 
       conflict_reg = (((conflict_reg == reg)
-                      && (inst.instruction & 0x00100000))
+                      && (inst.instruction & LOAD_BIT))
                      ? 1 : 0);
 
       while (*str == ' ')
@@ -2291,7 +2587,7 @@ do_ldst (str, flags)
          if (skip_past_comma (&str) == SUCCESS)
            {
              /* [Rn],... (post inc) */
-             if (ldst_extend (&str, halfword | signextend) == FAIL)
+             if (ldst_extend (&str, halfword) == FAIL)
                return;
              if (conflict_reg)
                as_warn ("destination register same as write-back base\n");
@@ -2299,7 +2595,7 @@ do_ldst (str, flags)
          else
            {
              /* [Rn] */
-              if (halfword | signextend)
+              if (halfword)
                 inst.instruction |= HWOFFSET_IMM;
 
               while (*str == ' ')
@@ -2328,7 +2624,7 @@ do_ldst (str, flags)
            }
 
          pre_inc = 1;
-         if (ldst_extend (&str, halfword | signextend) == FAIL)
+         if (ldst_extend (&str, halfword) == FAIL)
            return;
 
          while (*str == ' ')
@@ -2346,7 +2642,7 @@ do_ldst (str, flags)
          if (*str == '!')
            {
              if (conflict_reg)
-               as_warn ("destination register same as write-back base\n");
+               as_tsktsk ("destination register same as write-back base\n");
              str++;
              inst.instruction |= WRITE_BACK;
            }
@@ -2391,7 +2687,7 @@ do_ldst (str, flags)
            }
 
          /* Change the instruction exp to point to the pool */
-          if (halfword || signextend)
+          if (halfword)
             {
               inst.instruction |= HWOFFSET_IMM;
               inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
@@ -2408,7 +2704,7 @@ do_ldst (str, flags)
       if (my_get_expression (&inst.reloc.exp, &str))
        return;
 
-      if (halfword || signextend)
+      if (halfword)
         {
           inst.instruction |= HWOFFSET_IMM;
           inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
@@ -2429,155 +2725,175 @@ do_ldst (str, flags)
   return;
 }
 
-static void
-do_ldmstm (str, flags)
-     char *str;
-     unsigned long flags;
+static long
+reg_list (strp)
+     char **strp;
 {
-  int base_reg;
+  char *str = *strp;
+  long range = 0;
+  int another_range;
 
-  while (*str == ' ')
-    str++;
-
-  if ((base_reg = reg_required_here (&str, 16)) == FAIL)
+  /* We come back here if we get ranges concatenated by '+' or '|' */
+  do
     {
-      if (!inst.error)
-       inst.error = bad_args;
-      return;
-    }
+      another_range = 0;
 
-  if (base_reg == REG_PC)
-    {
-      inst.error = "r15 not allowed as base register";
-      return;
-    }
+      if (*str == '{')
+       {
+         int in_range = 0;
+         int cur_reg = -1;
+      
+         str++;
+         do
+           {
+             int reg;
+           
+             while (*str == ' ')
+               str++;
 
-  while (*str == ' ')
-    str++;
-  if (*str == '!')
-    {
-      flags |= WRITE_BACK;
-      str++;
-    }
+             if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg))
+               {
+                 inst.error = "Register expected";
+                 return FAIL;
+               }
 
-  if (skip_past_comma (&str) == FAIL)
-    {
-      inst.error = bad_args;
-      return;
-    }
+             if (in_range)
+               {
+                 int i;
+             
+                 if (reg <= cur_reg)
+                   {
+                     inst.error = "Bad range in register list";
+                     return FAIL;
+                   }
 
-  /* We come back here if we get ranges concatenated by '+' or '|' */
- another_range:
-  if (*str == '{')
-    {
-      int in_range = 0;
-      int cur_reg = -1;
-      
-      str++;
-      do
-       {
-         int reg;
-           
+                 for (i = cur_reg + 1; i < reg; i++)
+                   {
+                     if (range & (1 << i))
+                       as_tsktsk 
+                         ("Warning: Duplicated register (r%d) in register list",
+                          i);
+                     else
+                       range |= 1 << i;
+                   }
+                 in_range = 0;
+               }
+
+             if (range & (1 << reg))
+               as_tsktsk ("Warning: Duplicated register (r%d) in register list",
+                          reg);
+             else if (reg <= cur_reg)
+               as_tsktsk ("Warning: Register range not in ascending order");
+
+             range |= 1 << reg;
+             cur_reg = reg;
+           } while (skip_past_comma (&str) != FAIL
+                    || (in_range = 1, *str++ == '-'));
+         str--;
          while (*str == ' ')
            str++;
 
-         if ((reg = arm_reg_parse (&str)) == FAIL || !int_register (reg))
+         if (*str++ != '}')
            {
-             inst.error = "Register expected";
-             return;
+             inst.error = "Missing `}'";
+             return FAIL;
            }
+       }
+      else
+       {
+         expressionS expr;
+
+         if (my_get_expression (&expr, &str))
+           return FAIL;
 
-         if (in_range)
+         if (expr.X_op == O_constant)
            {
-             int i;
-             
-             if (reg <= cur_reg)
+             if (expr.X_add_number 
+                 != (expr.X_add_number & 0x0000ffff))
                {
-                 inst.error = "Bad range in register list";
-                 return;
+                 inst.error = "invalid register mask";
+                 return FAIL;
                }
 
-             for (i = cur_reg + 1; i < reg; i++)
+             if ((range & expr.X_add_number) != 0)
                {
-                 if (flags & (1 << i))
-                   as_tsktsk 
-                     ("Warning: Duplicated register (r%d) in register list",
-                      i);
-                 else
-                   flags |= 1 << i;
+                 int regno = range & expr.X_add_number;
+
+                 regno &= -regno;
+                 regno = (1 << regno) - 1;
+                 as_tsktsk 
+                   ("Warning: Duplicated register (r%d) in register list",
+                    regno);
+               }
+
+             range |= expr.X_add_number;
+           }
+         else
+           {
+             if (inst.reloc.type != 0)
+               {
+                 inst.error = "expression too complex";
+                 return FAIL;
                }
-             in_range = 0;
+
+             memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
+             inst.reloc.type = BFD_RELOC_ARM_MULTI;
+             inst.reloc.pc_rel = 0;
            }
+       }
 
-         if (flags & (1 << reg))
-           as_tsktsk ("Warning: Duplicated register (r%d) in register list",
-                      reg);
-         else if (reg <= cur_reg)
-           as_tsktsk ("Warning: Register range not in ascending order");
-
-         flags |= 1 << reg;
-         cur_reg = reg;
-       } while (skip_past_comma (&str) != FAIL
-                || (in_range = 1, *str++ == '-'));
-      str--;
       while (*str == ' ')
        str++;
 
-      if (*str++ != '}')
+      if (*str == '|' || *str == '+')
        {
-         inst.error = "Missing `}'";
-         return;
+         str++;
+         another_range = 1;
        }
-    }
-  else
-    {
-      expressionS expr;
+    } while (another_range);
 
-      if (my_get_expression (&expr, &str))
-       return;
-
-      if (expr.X_op == O_constant)
-       {
-         if (expr.X_add_number 
-             != (expr.X_add_number & 0x0000ffff))
-           {
-             inst.error = "invalid register mask";
-             return;
-           }
+  *strp = str;
+  return range;
+}
 
-         if ((flags & expr.X_add_number) != 0)
-           {
-             int regno = flags & expr.X_add_number;
+static void
+do_ldmstm (str, flags)
+     char *str;
+     unsigned long flags;
+{
+  int base_reg;
+  long range;
 
-             regno &= -regno;
-             regno = (1 << regno) - 1;
-             as_tsktsk ("Warning: Duplicated register (r%d) in register list",
-                        regno);
-           }
+  while (*str == ' ')
+    str++;
 
-         flags |= expr.X_add_number;
-       }
-      else
-       {
-         if (inst.reloc.type != 0)
-           {
-             inst.error = "expression too complex";
-             return;
-           }
+  if ((base_reg = reg_required_here (&str, 16)) == FAIL)
+    {
+      if (!inst.error)
+       inst.error = bad_args;
+      return;
+    }
 
-         memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
-         inst.reloc.type = BFD_RELOC_ARM_MULTI;
-         inst.reloc.pc_rel = 0;
-       }
+  if (base_reg == REG_PC)
+    {
+      inst.error = "r15 not allowed as base register";
+      return;
     }
 
   while (*str == ' ')
     str++;
-
-  if (*str == '|' || *str == '+')
+  if (*str == '!')
     {
+      flags |= WRITE_BACK;
       str++;
-      goto another_range;
+    }
+
+  if (skip_past_comma (&str) == FAIL
+      || (range = reg_list (&str)) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
     }
 
   if (*str == '^')
@@ -2585,7 +2901,8 @@ do_ldmstm (str, flags)
       str++;
       flags |= MULTI_SET_PSR;
     }
-  inst.instruction |= flags;
+
+  inst.instruction |= flags | range;
   end_of_line (str);
   return;
 }
@@ -2686,7 +3003,26 @@ do_branch (str, flags)
     return;
   inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
   inst.reloc.pc_rel = 1;
-  inst.instruction |= flags | 0x00fffffe;      /* PC-rel adjust */
+  end_of_line (str);
+  return;
+}
+
+static void
+do_bx (str, flags)
+     char *str;
+     unsigned long flags;
+{
+  int reg;
+
+  while (*str == ' ')
+    str++;
+
+  if ((reg = reg_required_here (&str, 0)) == FAIL)
+    return;
+
+  if (reg == REG_PC)
+    as_tsktsk ("Use of r15 in bx has undefined behaviour");
+
   end_of_line (str);
   return;
 }
@@ -3257,23 +3593,932 @@ do_fp_to_reg (str, flags)
   return;
 }
 
-static void
-insert_reg (entry)
-     int entry;
+/* Thumb specific routines */
+
+/* Parse and validate that a register is of the right form, this saves
+   repeated checking of this information in many similar cases. 
+   Unlike the 32-bit case we do not insert the register into the opcode 
+   here, since the position is often unknown until the full instruction 
+   has been parsed.  */
+static int
+thumb_reg (strp, hi_lo)
+     char **strp;
+     int hi_lo;
 {
-  int len = strlen (reg_table[entry].name) + 2;
-  char *buf = (char *) xmalloc (len);
-  char *buf2 = (char *) xmalloc (len);
-  int i = 0;
+  int reg;
 
-#ifdef REGISTER_PREFIX
-  buf[i++] = REGISTER_PREFIX;
-#endif
+  if ((reg = arm_reg_parse (strp)) == FAIL || ! int_register (reg))
+    {
+      inst.error = "Register expected";
+      return FAIL;
+    }
 
-  strcpy (buf + i, reg_table[entry].name);
+  switch (hi_lo)
+    {
+    case THUMB_REG_LO:
+      if (reg > 7)
+       {
+         inst.error = "lo register required";
+         return FAIL;
+       }
+      break;
 
-  for (i = 0; buf[i]; i++)
-    buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i];
+    case THUMB_REG_HI:
+      if (reg < 8)
+       {
+         inst.error = "hi register required";
+         return FAIL;
+       }
+      break;
+
+    default:
+      break;
+    }
+
+  return reg;
+}
+
+/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
+   was SUB.  */
+static void
+thumb_add_sub (str, subtract)
+     char *str;
+     int subtract;
+{
+  int Rd, Rs, Rn = FAIL;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (*str == '#')
+    {
+      Rs = Rd;
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else
+    {
+      if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+
+      if (skip_past_comma (&str) == FAIL)
+       {
+         /* Two operand format, shuffle the registers and pretend there 
+            are 3 */
+         Rn = Rs;
+         Rs = Rd;
+       }
+      else if (*str == '#')
+       {
+         str++;
+         if (my_get_expression (&inst.reloc.exp, &str))
+           return;
+       }
+      else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+    }
+
+  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+     for the latter case, EXPR contains the immediate that was found. */
+  if (Rn != FAIL)
+    {
+      /* All register format.  */
+      if (Rd > 7 || Rs > 7 || Rd > 7)
+       {
+         if (Rs != Rd)
+           {
+             inst.error = "dest and source1 must be the same register";
+             return;
+           }
+
+         /* Can't do this for SUB */
+         if (subtract)
+           {
+             inst.error = "subtract valid only on lo regs";
+             return;
+           }
+
+         inst.instruction = (T_OPCODE_ADD_HI
+                             | (Rd > 7 ? THUMB_H1 : 0)
+                             | (Rn > 7 ? THUMB_H2 : 0));
+         inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
+       }
+      else
+       {
+         inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
+         inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
+       }
+    }
+  else
+    {
+      /* Immediate expression, now things start to get nasty.  */
+
+      /* First deal with HI regs, only very restricted cases allowed:
+        Adjusting SP, and using PC or SP to get an address.  */
+      if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
+         || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
+       {
+         inst.error = "invalid Hi register with immediate";
+         return;
+       }
+
+      if (inst.reloc.exp.X_op != O_constant)
+       {
+         /* Value isn't known yet, all we can do is store all the fragments
+            we know about in the instruction and let the reloc hacking 
+            work it all out.  */
+         inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+       }
+      else
+       {
+         int offset = inst.reloc.exp.X_add_number;
+
+         if (subtract)
+           offset = -offset;
+
+         if (offset < 0)
+           {
+             offset = -offset;
+             subtract = 1;
+
+             /* Quick check, in case offset is MIN_INT */
+             if (offset < 0)
+               {
+                 inst.error = "immediate value out of range";
+                 return;
+               }
+           }
+         else
+           subtract = 0;
+
+         if (Rd == REG_SP)
+           {
+             if (offset & ~0x1fc)
+               {
+                 inst.error = "invalid immediate value for stack adjust";
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
+             inst.instruction |= offset >> 2;
+           }
+         else if (Rs == REG_PC || Rs == REG_SP)
+           {
+             if (subtract
+                 || (offset & ~0x3fc))
+               {
+                 inst.error = "invalid immediate for address calculation";
+                 return;
+               }
+             inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
+                                 : T_OPCODE_ADD_SP);
+             inst.instruction |= (Rd << 8) | (offset >> 2);
+           }
+         else if (Rs == Rd)
+           {
+             if (offset & ~0xff)
+               {
+                 inst.error = "immediate value out of range";
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
+             inst.instruction |= (Rd << 8) | offset;
+           }
+         else
+           {
+             if (offset & ~0x7)
+               {
+                 inst.error = "immediate value out of range";
+                 return;
+               }
+             inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
+             inst.instruction |= Rd | (Rs << 3) | (offset << 6);
+           }
+       }
+    }
+  end_of_line (str);
+}
+
+static void
+thumb_shift (str, shift)
+     char *str;
+     int shift;
+{
+  int Rd, Rs, Rn = FAIL;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (*str == '#')
+    {
+      /* Two operand immediate format, set Rs to Rd.  */
+      Rs = Rd;
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else
+    {
+      if ((Rs =  thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
+
+      if (skip_past_comma (&str) == FAIL)
+       {
+         /* Two operand format, shuffle the registers and pretend there
+            are 3 */
+         Rn = Rs;
+         Rs = Rd;
+       }
+      else if (*str == '#')
+       {
+         str++;
+         if (my_get_expression (&inst.reloc.exp, &str))
+           return;
+       }
+      else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
+    }
+
+  /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
+     for the latter case, EXPR contains the immediate that was found. */
+
+  if (Rn != FAIL)
+    {
+      if (Rs != Rd)
+       {
+         inst.error = "source1 and dest must be same register";
+         return;
+       }
+
+      switch (shift)
+       {
+       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
+       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
+       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
+       }
+
+      inst.instruction |= Rd | (Rn << 3);
+    }
+  else
+    {
+      switch (shift)
+       {
+       case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
+       case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
+       case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
+       }
+
+      if (inst.reloc.exp.X_op != O_constant)
+       {
+         /* Value isn't known yet, create a dummy reloc and let reloc
+            hacking fix it up */
+
+         inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+       }
+      else
+       {
+         unsigned shift_value = inst.reloc.exp.X_add_number;
+
+         if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
+           {
+             inst.error = "Invalid immediate for shift";
+             return;
+           }
+
+         /* Shifts of zero are handled by converting to LSL */
+         if (shift_value == 0)
+           inst.instruction = T_OPCODE_LSL_I;
+
+         /* Shifts of 32 are encoded as a shift of zero */
+         if (shift_value == 32)
+           shift_value = 0;
+
+         inst.instruction |= shift_value << 6;
+       }
+
+      inst.instruction |= Rd | (Rs << 3);
+    }
+  end_of_line (str);
+}
+
+static void
+thumb_mov_compare (str, move)
+     char *str;
+     int move;
+{
+  int Rd, Rs = FAIL;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (*str == '#')
+    {
+      str++;
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+    }
+  else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+    return;
+
+  if (Rs != FAIL)
+    {
+      if (Rs < 8 && Rd < 8)
+       {
+         if (move == THUMB_MOVE)
+           /* A move of two lowregs is, by convention, encoded as
+              ADD Rd, Rs, #0 */
+           inst.instruction = T_OPCODE_ADD_I3;
+         else
+           inst.instruction = T_OPCODE_CMP_LR;
+         inst.instruction |= Rd | (Rs << 3);
+       }
+      else
+       {
+         if (move == THUMB_MOVE)
+           inst.instruction = T_OPCODE_MOV_HR;
+         else
+           inst.instruction = T_OPCODE_CMP_HR;
+
+         if (Rd > 7)
+           inst.instruction |= THUMB_H1;
+
+         if (Rs > 7)
+           inst.instruction |= THUMB_H2;
+
+         inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
+       }
+    }
+  else
+    {
+      if (Rd > 7)
+       {
+         inst.error = "only lo regs allowed with immediate";
+         return;
+       }
+
+      if (move == THUMB_MOVE)
+       inst.instruction = T_OPCODE_MOV_I8;
+      else
+       inst.instruction = T_OPCODE_CMP_I8;
+
+      inst.instruction |= Rd << 8;
+
+      if (inst.reloc.exp.X_op != O_constant)
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+      else
+       {
+         unsigned value = inst.reloc.exp.X_add_number;
+
+         if (value > 255)
+           {
+             inst.error = "invalid immediate";
+             return;
+           }
+
+         inst.instruction |= value;
+       }
+    }
+
+  end_of_line (str);
+}
+
+static void
+thumb_load_store (str, load_store, size)
+     char *str;
+     int load_store;
+     int size;
+{
+  int Rd, Rb, Ro = FAIL;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (*str == '[')
+    {
+      str++;
+      if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+       return;
+
+      if (skip_past_comma (&str) != FAIL)
+       {
+         if (*str == '#')
+           {
+             str++;
+             if (my_get_expression (&inst.reloc.exp, &str))
+               return;
+           }
+         else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+           return;
+       }
+      else
+       {
+         inst.reloc.exp.X_op = O_constant;
+         inst.reloc.exp.X_add_number = 0;
+       }
+
+      if (*str != ']')
+       {
+         inst.error = "expected ']'";
+         return;
+       }
+      str++;
+    }
+  else if (*str == '=')
+    {
+      abort ();
+    }
+  else
+    {
+      if (my_get_expression (&inst.reloc.exp, &str))
+       return;
+
+      inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
+      inst.reloc.pc_rel = 1;
+      inst.reloc.exp.X_add_number -= 4; /* Pipeline offset */
+      inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+      end_of_line (str);
+      return;
+    }
+
+  if (Rb == REG_PC || Rb == REG_SP)
+    {
+      if (size != THUMB_WORD)
+       {
+         inst.error = "byte or halfword not valid for base register";
+         return;
+       }
+      else if (Rb == REG_PC && load_store != THUMB_LOAD)
+       {
+         inst.error = "R15 based store not allowed";
+         return;
+       }
+      else if (Ro != FAIL)
+       {
+         inst.error = "Invalid base register for register offset";
+         return;
+       }
+
+      if (Rb == REG_PC)
+       inst.instruction = T_OPCODE_LDR_PC;
+      else if (load_store == THUMB_LOAD)
+       inst.instruction = T_OPCODE_LDR_SP;
+      else
+       inst.instruction = T_OPCODE_STR_SP;
+
+      inst.instruction |= Rd << 8;
+      if (inst.reloc.exp.X_op == O_constant)
+       {
+         unsigned offset = inst.reloc.exp.X_add_number;
+
+         if (offset & ~0x3fc)
+           {
+             inst.error = "invalid offset";
+             return;
+           }
+
+         inst.instruction |= offset >> 2;
+       }
+      else
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+    }
+  else if (Rb > 7)
+    {
+      inst.error = "invalid base register in load/store";
+      return;
+    }
+  else if (Ro == FAIL)
+    {
+      /* Immediate offset */
+      if (size == THUMB_WORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
+      else if (size == THUMB_HALFWORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
+      else
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
+
+      inst.instruction |= Rd | (Rb << 3);
+
+      if (inst.reloc.exp.X_op == O_constant)
+       {
+         unsigned offset = inst.reloc.exp.X_add_number;
+         
+         if (offset & ~(0x1f << size))
+           {
+             inst.error = "Invalid offset";
+             return;
+           }
+         inst.instruction |= offset << 6;
+       }
+      else
+       inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+    }
+  else
+    {
+      /* Register offset */
+      if (size == THUMB_WORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
+      else if (size == THUMB_HALFWORD)
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
+      else
+       inst.instruction = (load_store == THUMB_LOAD
+                           ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
+
+      inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+    }
+
+  end_of_line (str);
+}
+
+/* Handle the Format 4 instructions that do not have equivalents in other 
+   formats.  That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
+   BIC and MVN.  */
+static void
+do_t_arit (str)
+     char *str;
+{
+  int Rd, Rs, Rn;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+    return;
+
+  if (skip_past_comma (&str) == FAIL
+      || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (skip_past_comma (&str) != FAIL)
+    {
+      /* Three operand format not allowed for TST, CMN, NEG and MVN.
+        (It isn't allowed for CMP either, but that isn't handled by this
+        function.)  */
+      if (inst.instruction == T_OPCODE_TST
+         || inst.instruction == T_OPCODE_CMN
+         || inst.instruction == T_OPCODE_NEG
+         || inst.instruction == T_OPCODE_MVN)
+       {
+         inst.error = bad_args;
+         return;
+       }
+
+      if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+       return;
+
+      if (Rs != Rd)
+       {
+         inst.error = "dest and source1 one must be the same register";
+         return;
+       }
+      Rs = Rn;
+    }
+
+  if (inst.instruction == T_OPCODE_MUL
+      && Rs == Rd)
+    as_tsktsk ("Rs and Rd must be different in MUL");
+
+  inst.instruction |= Rd | (Rs << 3);
+  end_of_line (str);
+}
+
+static void
+do_t_add (str)
+     char *str;
+{
+  thumb_add_sub (str, 0);
+}
+
+static void
+do_t_asr (str)
+     char *str;
+{
+  thumb_shift (str, THUMB_ASR);
+}
+
+static void
+do_t_branch (str)
+     char *str;
+{
+  if (my_get_expression (&inst.reloc.exp, &str))
+    return;
+  inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
+  inst.reloc.pc_rel = 1;
+  end_of_line (str);
+}
+
+static void
+do_t_bx (str)
+     char *str;
+{
+  int reg;
+
+  while (*str == ' ')
+    str++;
+
+  if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+    return;
+
+  /* This sets THUMB_H2 from the top bit of reg.  */
+  inst.instruction |= reg << 3;
+
+  /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.  The reloc
+     should cause the alignment to be checked once it is known.  This is
+     because BX PC only works if the instruction is word aligned.  */
+
+  end_of_line (str);
+}
+
+static void
+do_t_compare (str)
+     char *str;
+{
+  thumb_mov_compare (str, THUMB_COMPARE);
+}
+
+static void
+do_t_ldmstm (str)
+     char *str;
+{
+  int Rb;
+  long range;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+    return;
+
+  if (*str != '!')
+    as_warn ("Inserted missing '!': load/store multiple always writes back base register");
+  else
+    str++;
+
+  if (skip_past_comma (&str) == FAIL
+      || (range = reg_list (&str)) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (inst.reloc.type != BFD_RELOC_NONE)
+    {
+      /* This really doesn't seem worth it. */
+      inst.reloc.type = BFD_RELOC_NONE;
+      inst.error = "Expression too complex";
+      return;
+    }
+
+  if (range & ~0xff)
+    {
+      inst.error = "only lo-regs valid in load/store multiple";
+      return;
+    }
+
+  inst.instruction |= (Rb << 8) | range;
+  end_of_line (str);
+}
+
+static void
+do_t_ldr (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
+}
+
+static void
+do_t_ldrb (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
+}
+
+static void
+do_t_ldrh (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
+}
+
+static void
+do_t_lds (str)
+     char *str;
+{
+  int Rd, Rb, Ro;
+
+  while (*str == ' ')
+    str++;
+
+  if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || *str++ != '['
+      || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
+      || *str++ != ']')
+    {
+      if (! inst.error)
+       inst.error = "Syntax: ldrs[b] Rd, [Rb, Ro]";
+      return;
+    }
+
+  inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
+  end_of_line (str);
+}
+
+static void
+do_t_lsl (str)
+     char *str;
+{
+  thumb_shift (str, THUMB_LSL);
+}
+
+static void
+do_t_lsr (str)
+     char *str;
+{
+  thumb_shift (str, THUMB_LSR);
+}
+
+static void
+do_t_mov (str)
+     char *str;
+{
+  thumb_mov_compare (str, THUMB_MOVE);
+}
+
+static void
+do_t_push_pop (str)
+     char *str;
+{
+  long range;
+
+  while (*str == ' ')
+    str++;
+
+  if ((range = reg_list (&str)) == FAIL)
+    {
+      if (! inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  if (inst.reloc.type != BFD_RELOC_NONE)
+    {
+      /* This really doesn't seem worth it. */
+      inst.reloc.type = BFD_RELOC_NONE;
+      inst.error = "Expression too complex";
+      return;
+    }
+
+  if (range & ~0xff)
+    {
+      if ((inst.instruction == T_OPCODE_PUSH
+          && (range & ~0xff) == 1 << REG_LR)
+         || (inst.instruction == T_OPCODE_POP
+             && (range & ~0xff) == 1 << REG_PC))
+       {
+         inst.instruction |= THUMB_PP_PC_LR;
+         range &= 0xff;
+       }
+      else
+       {
+         inst.error = "invalid register list to push/pop instruction";
+         return;
+       }
+    }
+
+  inst.instruction |= range;
+  end_of_line (str);
+}
+
+static void
+do_t_str (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_STORE, THUMB_WORD);
+}
+
+static void
+do_t_strb (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
+}
+
+static void
+do_t_strh (str)
+     char *str;
+{
+  thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
+}
+
+static void
+do_t_sub (str)
+     char *str;
+{
+  thumb_add_sub (str, 1);
+}
+
+static void
+do_t_swi (str)
+     char *str;
+{
+  while (*str == ' ')
+    str++;
+
+  if (my_get_expression (&inst.reloc.exp, &str))
+    return;
+
+  inst.reloc.type = BFD_RELOC_ARM_SWI;
+  end_of_line (str);
+  return;
+}
+
+static void
+do_t_adr (str)
+     char *str;
+{
+  /* This is a pseudo-op of the form "adr rd, label" to be converted
+     into a relative address of the form "add rd, pc, #label-.-8" */
+  while (*str == ' ')
+    str++;
+
+  if (reg_required_here (&str, 8) == FAIL
+      || skip_past_comma (&str) == FAIL
+      || my_get_expression (&inst.reloc.exp, &str))
+    {
+      if (!inst.error)
+       inst.error = bad_args;
+      return;
+    }
+
+  inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
+  inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
+  inst.reloc.pc_rel = 1;
+  inst.instruction |= REG_PC; /* Rd is already placed into the instruction */
+  end_of_line (str);
+}
+
+static void
+insert_reg (entry)
+     int entry;
+{
+  int len = strlen (reg_table[entry].name) + 2;
+  char *buf = (char *) xmalloc (len);
+  char *buf2 = (char *) xmalloc (len);
+  int i = 0;
+
+#ifdef REGISTER_PREFIX
+  buf[i++] = REGISTER_PREFIX;
+#endif
+
+  strcpy (buf + i, reg_table[entry].name);
+
+  for (i = 0; buf[i]; i++)
+    buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i];
 
   buf2[i] = '\0';
 
@@ -3313,6 +4558,7 @@ md_begin ()
   int i;
 
   if ((arm_ops_hsh = hash_new ()) == NULL
+      || (arm_tops_hsh = hash_new ()) == NULL
       || (arm_cond_hsh = hash_new ()) == NULL
       || (arm_shift_hsh = hash_new ()) == NULL
       || (arm_reg_hsh = hash_new ()) == NULL
@@ -3321,6 +4567,8 @@ md_begin ()
     
   for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
     hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i));
+  for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
+    hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
   for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
     hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
   for (i = 0; i < sizeof (shift) / sizeof (struct asm_shift); i++)
@@ -3577,6 +4825,7 @@ md_apply_fix3 (fixP, val, seg)
   offsetT newval, temp;
   int sign;
   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
+  arm_fix_data *arm_data = (arm_fix_data *) fixP->tc_fix_data;
 
   assert (fixP->fx_r_type < BFD_RELOC_UNUSED);
 
@@ -3600,7 +4849,7 @@ md_apply_fix3 (fixP, val, seg)
     {
     case BFD_RELOC_ARM_IMMEDIATE:
       newval = validate_immediate (value);
-      temp = md_chars_to_number (buf, insn_size);
+      temp = md_chars_to_number (buf, INSN_SIZE);
 
       /* If the instruction will fail, see if we can fix things up by
         changing the opcode.  */
@@ -3613,7 +4862,7 @@ md_apply_fix3 (fixP, val, seg)
        }
 
       newval |= (temp & 0xfffff000);
-      md_number_to_chars (buf, newval, insn_size);
+      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
      case BFD_RELOC_ARM_OFFSET_IMM:
@@ -3626,10 +4875,10 @@ md_apply_fix3 (fixP, val, seg)
       if (value < 0)
        value = -value;
 
-      newval = md_chars_to_number (buf, insn_size);
+      newval = md_chars_to_number (buf, INSN_SIZE);
       newval &= 0xff7ff000;
-      newval |= value | (sign ? 0x00800000 : 0);
-      md_number_to_chars (buf, newval, insn_size);
+      newval |= value | (sign ? INDEX_UP : 0);
+      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
      case BFD_RELOC_ARM_OFFSET_IMM8:
@@ -3648,10 +4897,10 @@ md_apply_fix3 (fixP, val, seg)
       if (value < 0)
        value = -value;
 
-      newval = md_chars_to_number (buf, insn_size);
+      newval = md_chars_to_number (buf, INSN_SIZE);
       newval &= 0xff7ff0f0;
-      newval |= ((value >> 4) << 8) | value & 0xf | (sign ? 0x00800000 : 0);
-      md_number_to_chars (buf, newval, insn_size);
+      newval |= ((value >> 4) << 8) | value & 0xf | (sign ? INDEX_UP : 0);
+      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_LITERAL:
@@ -3666,14 +4915,14 @@ md_apply_fix3 (fixP, val, seg)
          break;
        }
 
-      newval = md_chars_to_number (buf, insn_size);
+      newval = md_chars_to_number (buf, INSN_SIZE);
       newval &= 0xff7ff000;
-      newval |= value | (sign ? 0x00800000 : 0);
-      md_number_to_chars (buf, newval, insn_size);
+      newval |= value | (sign ? INDEX_UP : 0);
+      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_SHIFT_IMM:
-      newval = md_chars_to_number (buf, insn_size);
+      newval = md_chars_to_number (buf, INSN_SIZE);
       if (((unsigned long) value) > 32
          || (value == 32 
              && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
@@ -3689,31 +4938,98 @@ md_apply_fix3 (fixP, val, seg)
        value = 0;
       newval &= 0xfffff07f;
       newval |= (value & 0x1f) << 7;
-      md_number_to_chars (buf, newval , insn_size);
+      md_number_to_chars (buf, newval , INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_SWI:
-      if (((unsigned long) value) > 0x00ffffff)
-       as_bad_where (fixP->fx_file, fixP->fx_line, "Invalid swi expression");
-      newval = md_chars_to_number (buf, insn_size) & 0xff000000;
-      newval |= value;
-      md_number_to_chars (buf, newval , insn_size);
+      if (arm_data->thumb_mode)
+       {
+         if (((unsigned long) value) > 0xff)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid swi expression");
+         newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
+         newval |= value;
+         md_number_to_chars (buf, newval, THUMB_SIZE);
+       }
+      else
+       {
+         if (((unsigned long) value) > 0x00ffffff)
+           as_bad_where (fixP->fx_file, fixP->fx_line, 
+                         "Invalid swi expression");
+         newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
+         newval |= value;
+         md_number_to_chars (buf, newval , INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_ARM_MULTI:
       if (((unsigned long) value) > 0xffff)
        as_bad_where (fixP->fx_file, fixP->fx_line,
                      "Invalid expression in load/store multiple");
-      newval = value | md_chars_to_number (buf, insn_size);
-      md_number_to_chars (buf, newval, insn_size);
+      newval = value | md_chars_to_number (buf, INSN_SIZE);
+      md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
     case BFD_RELOC_ARM_PCREL_BRANCH:
-      value = (value >> 2) & 0x00ffffff;
-      newval = md_chars_to_number (buf, insn_size);
-      value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
-      newval = value | (newval & 0xff000000);
-      md_number_to_chars (buf, newval, insn_size);
+      if (arm_data->thumb_mode)
+       {
+         unsigned long newval2;
+         newval = md_chars_to_number (buf, THUMB_SIZE);
+         if (fixP->fx_size == 4)
+           {
+             unsigned long diff;
+
+             newval2 = md_chars_to_number (buf, THUMB_SIZE);
+             diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
+             if (diff & 0x400000)
+               diff |= ~0x3fffff;
+             value += diff;
+             if ((value & 0x400000) && ((value & ~0x3fffff) != ~0x3fffff))
+               as_bad_where (fixP->fx_file, fixP->fx_line,
+                             "Branch with link out of range");
+
+             newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
+             newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
+             md_number_to_chars (buf, newval, THUMB_SIZE);
+             md_number_to_chars (buf, newval2, THUMB_SIZE);
+           }
+         else
+           {
+             if (newval == T_OPCODE_BRANCH)
+               {
+                 unsigned long diff = (newval & 0x7ff) << 1;
+                 if (diff & 0x800)
+                   diff |= ~0x7ff;
+
+                 value += diff;
+                 if ((value & 0x800) && ((value & ~0x7ff) != ~0x7ff))
+                   as_bad_where (fixP->fx_file, fixP->fx_line,
+                                 "Branch out of range");
+                 newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
+               }
+             else
+               {
+                 unsigned long diff = (newval & 0xff) << 1;
+                 if (diff & 0x100)
+                   diff |= ~0xff;
+
+                 value += diff;
+                 if ((value & 0x100) && ((value & ~0xff) != ~0xff))
+                   as_bad_where (fixP->fx_file, fixP->fx_line,
+                                 "Branch out of range");
+                 newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
+               }
+             md_number_to_chars (buf, newval, THUMB_SIZE);
+           }
+       }
+      else
+       {
+         value = (value >> 2) & 0x00ffffff;
+         newval = md_chars_to_number (buf, INSN_SIZE);
+         value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
+         newval = value | (newval & 0xff000000);
+         md_number_to_chars (buf, newval, INSN_SIZE);
+       }
       break;
 
     case BFD_RELOC_8:
@@ -3739,9 +5055,151 @@ md_apply_fix3 (fixP, val, seg)
                      "Illegal value for co-processor offset");
       if (value < 0)
        value = -value;
-      newval = md_chars_to_number (buf, insn_size) & 0xff7fff00;
-      newval |= (value >> 2) | (sign ?  0x00800000 : 0);
-      md_number_to_chars (buf, newval , insn_size);
+      newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
+      newval |= (value >> 2) | (sign ?  INDEX_UP : 0);
+      md_number_to_chars (buf, newval , INSN_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_THUMB_OFFSET:
+      newval = md_chars_to_number (buf, THUMB_SIZE);
+      /* Exactly what ranges, and where the offset is inserted depends on
+        the type of instruction, we can establish this from the top 4 bits */
+      switch (newval >> 12)
+       {
+       case 4: /* PC load */
+         /* PC loads are somewhat odd, bit 2 of the PC is forced to zero
+            for these loads, so we may need to round up the offset if the
+            instruction is not word aligned since the final address must
+            be.   */
+
+         if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset, target not word aligned");
+
+         if ((value + 2) & ~0x3fe)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset");
+          /* Round up, since pc will be rounded down.  */
+         newval |= (value + 2) >> 2;
+         break;
+
+       case 9: /* SP load/store */
+         if (value & ~0x3fc)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset");
+         newval |= value >> 2;
+         break;
+
+       case 6: /* Word load/store */
+         if (value & ~0x7c)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset");
+         newval |= value << 4; /* 6 - 2 */
+         break;
+
+       case 7: /* Byte load/store */
+         if (value & ~0x1f)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset");
+         newval |= value << 6;
+         break;
+
+       case 8: /* Halfword load/store */
+         if (value & ~0x3e)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         "Invalid offset");
+         newval |= value << 5; /* 6 - 1 */
+         break;
+
+       default:
+         abort ();
+       }
+      md_number_to_chars (buf, newval, THUMB_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_THUMB_ADD:
+      /* This is a complicated relocation, since we use it for all of
+         the following immediate relocations:
+            3bit ADD/SUB
+            8bit ADD/SUB
+            9bit ADD/SUB SP word-aligned
+           10bit ADD PC/SP word-aligned
+
+         The type of instruction being processed is encoded in the
+         instruction field:
+           0x8000  SUB
+           0x00F0  Rd
+           0x000F  Rs
+      */
+      newval = md_chars_to_number (buf, THUMB_SIZE);
+      {
+        int rd = (newval >> 4) & 0xf;
+        int rs = newval & 0xf;
+        int subtract = newval & 0x8000;
+
+        if (rd == REG_SP)
+          {
+            if (value & ~0x1fc)
+              as_bad_where (fixP->fx_file, fixP->fx_line,
+                            "Invalid immediate for stack address calculation");
+            newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
+            newval |= value >> 2;
+          }
+        else if (rs == REG_PC || rs == REG_SP)
+          {
+            if (subtract ||
+                value & ~0x3fc)
+              as_bad_where (fixP->fx_file, fixP->fx_line,
+                            "Invalid immediate for address calculation (value = 0x%08X)", value);
+            newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
+            newval |= value >> 2;
+          }
+        else if (rs == rd)
+          {
+            if (value & ~0xff)
+              as_bad_where (fixP->fx_file, fixP->fx_line,
+                            "Invalid 8bit immediate");
+            newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
+            newval |= (rd << 8) | value;
+          }
+        else
+          {
+            if (value & ~0x7)
+              as_bad_where (fixP->fx_file, fixP->fx_line,
+                            "Invalid 3bit immediate");
+            newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
+            newval |= rd | (rs << 3) | (value << 6);
+          }
+      }
+      md_number_to_chars (buf, newval , THUMB_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_THUMB_IMM:
+      newval = md_chars_to_number (buf, THUMB_SIZE);
+      switch (newval >> 11)
+        {
+        case 0x04: /* 8bit immediate MOV */
+        case 0x05: /* 8bit immediate CMP */
+          if (value < 0 || value > 255)
+            as_bad_where (fixP->fx_file, fixP->fx_line,
+                          "Invalid immediate: %d is too large", value);
+          newval |= value;
+          break;
+
+        default:
+          abort ();
+        }
+      md_number_to_chars (buf, newval , THUMB_SIZE);
+      break;
+
+    case BFD_RELOC_ARM_THUMB_SHIFT:
+      /* 5bit shift value (0..31) */
+      if (value < 0 || value > 31)
+       as_bad_where (fixP->fx_file, fixP->fx_line,
+                     "Illegal Thumb shift value: %d", value);
+      newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
+      newval |= value << 6;
+      md_number_to_chars (buf, newval , THUMB_SIZE);
       break;
 
     case BFD_RELOC_NONE:
@@ -3763,8 +5221,7 @@ tc_gen_reloc (section, fixp)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  assert (reloc != 0);
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
@@ -3845,6 +5302,11 @@ tc_gen_reloc (section, fixp)
              , fixp->fx_r_type);
       return NULL;
 
+    case BFD_RELOC_ARM_THUMB_OFFSET:
+      as_bad ("Internal_relocation (type %d) not fixed up (THUMB_OFFSET)"
+             , fixp->fx_r_type);
+      return NULL;
+
     default:
       abort ();
     }
@@ -3900,12 +5362,19 @@ output_inst (str)
       return;
     }
 
-  to = frag_more (insn_size);
-  md_number_to_chars (to, inst.instruction, insn_size);
+  to = frag_more (inst.size);
+  if (thumb_mode && (inst.size > 2))
+    {
+      md_number_to_chars (to, inst.instruction >> 16, 2);
+      to += 2;
+      inst.size = 2;
+    }
+
+  md_number_to_chars (to, inst.instruction, inst.size);
 
   if (inst.reloc.type != BFD_RELOC_NONE)
     fix_new_arm (frag_now, to - frag_now->fr_literal,
-                4, &inst.reloc.exp, inst.reloc.pc_rel,
+                inst.size, &inst.reloc.exp, inst.reloc.pc_rel,
                 inst.reloc.type);
 
   return;
@@ -3916,7 +5385,6 @@ md_assemble (str)
      char *str;
 {
   char c;
-  CONST struct asm_opcode *opcode;
   char *p, *q, *start;
 
   /* Align the instruction */
@@ -3950,130 +5418,153 @@ md_assemble (str)
       return;
     }
 
-  /* p now points to the end of the opcode, probably white space, but we have
-     to break the opcode up in case it contains condionals and flags;
-     keep trying with progressively smaller basic instructions until one
-     matches, or we run out of opcode. */
-  q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
-  for (; q != str; q--)
+  if (thumb_mode)
     {
-      c = *q;
-      *q = '\0';
-      opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
-      *q = c;
-      if (opcode && opcode->template)
-       {
-         unsigned long flag_bits = 0;
-         char *r;
-
-         /* Check that this instruction is supported for this CPU */
-         if ((opcode->variants & cpu_variant) == 0)
-           goto try_shorter;
+      CONST struct thumb_opcode *opcode;
 
+      c = *p;
+      *p = '\0';
+      opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str);
+      *p = c;
+      if (opcode)
+       {
          inst.instruction = opcode->value;
-         if (q == p)           /* Just a simple opcode */
+         inst.size = opcode->size;
+         (*opcode->parms)(p);
+         output_inst (start);
+         return;
+       }
+    }
+  else
+    {
+      CONST struct asm_opcode *opcode;
+
+      inst.size = INSN_SIZE;
+      /* p now points to the end of the opcode, probably white space, but we
+        have to break the opcode up in case it contains condionals and flags;
+        keep trying with progressively smaller basic instructions until one
+        matches, or we run out of opcode. */
+      q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p;
+      for (; q != str; q--)
+       {
+         c = *q;
+         *q = '\0';
+         opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str);
+         *q = c;
+         if (opcode && opcode->template)
            {
-             if (opcode->comp_suffix != 0)
-               as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
-                       opcode->comp_suffix);
-             else
+             unsigned long flag_bits = 0;
+             char *r;
+
+             /* Check that this instruction is supported for this CPU */
+             if ((opcode->variants & cpu_variant) == 0)
+               goto try_shorter;
+
+             inst.instruction = opcode->value;
+             if (q == p)               /* Just a simple opcode */
                {
-                 inst.instruction |= COND_ALWAYS;
-                 (*opcode->parms)(q, 0);
+                 if (opcode->comp_suffix != 0)
+                   as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
+                           opcode->comp_suffix);
+                 else
+                   {
+                     inst.instruction |= COND_ALWAYS;
+                     (*opcode->parms)(q, 0);
+                   }
+                 output_inst (start);
+                 return;
                }
-             output_inst (start);
-             return;
-           }
 
-         /* Now check for a conditional */
-         r = q;
-         if (p - r >= 2)
-           {
-             CONST struct asm_cond *cond;
-             char d = *(r + 2);
-             
-             *(r + 2) = '\0';
-             cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r);
-             *(r + 2) = d;
-             if (cond)
+             /* Now check for a conditional */
+             r = q;
+             if (p - r >= 2)
                {
-                 if (cond->value == 0xf0000000)
-                   as_tsktsk
-                     ("Warning: Use of the 'nv' conditional is deprecated\n");
+                 CONST struct asm_cond *cond;
+                 char d = *(r + 2);
+
+                 *(r + 2) = '\0';
+                 cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r);
+                 *(r + 2) = d;
+                 if (cond)
+                   {
+                     if (cond->value == 0xf0000000)
+                       as_tsktsk (
+"Warning: Use of the 'nv' conditional is deprecated\n");
 
-                 inst.instruction |= cond->value;
-                 r += 2;
+                     inst.instruction |= cond->value;
+                     r += 2;
+                   }
+                 else
+                   inst.instruction |= COND_ALWAYS;
                }
              else
                inst.instruction |= COND_ALWAYS;
-           }
-         else
-           inst.instruction |= COND_ALWAYS;
-
-         /* if there is a compulsory suffix, it should come here, before
-            any optional flags. */
-         if (opcode->comp_suffix)
-           {
-             CONST char *s = opcode->comp_suffix;
 
-             while (*s)
-               {
-                 inst.suffix++;
-                 if (*r == *s)
-                   break;
-                 s++;
-               }
-             
-             if (*s == '\0')
+             /* if there is a compulsory suffix, it should come here, before
+                any optional flags. */
+             if (opcode->comp_suffix)
                {
-                 as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
-                         opcode->comp_suffix);
-                 return;
-               }
-               
-             r++;
-           }
+                 CONST char *s = opcode->comp_suffix;
 
-         /* The remainder, if any should now be flags for the instruction;
-            Scan these checking each one found with the opcode.  */
-         if (r != p)
-           {
-             char d;
-             CONST struct asm_flg *flag = opcode->flags;
+                 while (*s)
+                   {
+                     inst.suffix++;
+                     if (*r == *s)
+                       break;
+                     s++;
+                   }
 
-             if (flag)
-               {
-                 int flagno;
+                 if (*s == '\0')
+                   {
+                     as_bad ("Opcode `%s' must have suffix from <%s>\n", str,
+                             opcode->comp_suffix);
+                     return;
+                   }
 
-                 d = *p;
-                 *p = '\0';
+                 r++;
+               }
+
+             /* The remainder, if any should now be flags for the instruction;
+                Scan these checking each one found with the opcode.  */
+             if (r != p)
+               {
+                 char d;
+                 CONST struct asm_flg *flag = opcode->flags;
 
-                 for (flagno = 0; flag[flagno].template; flagno++)
+                 if (flag)
                    {
-                     if ((flag[flagno].variants & cpu_variant) != 0
-                          && (! strcmp (r, flag[flagno].template)))
+                     int flagno;
+
+                     d = *p;
+                     *p = '\0';
+
+                     for (flagno = 0; flag[flagno].template; flagno++)
                        {
-                         flag_bits |= flag[flagno].set_bits;
-                         break;
+                         if (! strcmp (r, flag[flagno].template))
+                           {
+                             flag_bits |= flag[flagno].set_bits;
+                             break;
+                           }
                        }
-                   }
 
-                 *p = d;
-                 if (! flag[flagno].template)
+                     *p = d;
+                     if (! flag[flagno].template)
+                       goto try_shorter;
+                   }
+                 else
                    goto try_shorter;
                }
-             else
-               goto try_shorter;
+
+             (*opcode->parms) (p, flag_bits);
+             output_inst (start);
+             return;
            }
 
-         (*opcode->parms) (p, flag_bits);
-         output_inst (start);
-         return;
+       try_shorter:
+         ;
        }
-
-    try_shorter:
-       ;
     }
+
   /* It wasn't an instruction, but it might be a register alias of the form
      alias .req reg
      */
@@ -4156,7 +5647,7 @@ struct option md_longopts[] = {
 #endif
   {NULL, no_argument, NULL, 0}
 };
-size_t md_longopts_size = sizeof(md_longopts);
+size_t md_longopts_size = sizeof (md_longopts);
 
 int
 md_parse_option (c, arg)
@@ -4195,6 +5686,18 @@ md_parse_option (c, arg)
            cpu_variant &= ~FPU_ALL;
          break;
 
+        case 't':
+          /* Limit assembler to generating only Thumb instructions: */
+          if (! strcmp (str, "thumb"))
+            {
+              cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB;
+              cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
+              thumb_mode = 1;
+            }
+          else
+           goto bad;
+          break;
+
        default:
          if (! strcmp (str, "all"))
            {
@@ -4246,7 +5749,7 @@ md_parse_option (c, arg)
                 switch (*str)
                   {
                   case 't':
-                    cpu_variant |= ARM_HALFWORD;
+                    cpu_variant |= ARM_THUMB;
                     break;
 
                   case 'm':
@@ -4286,7 +5789,7 @@ md_show_usage (fp)
 {
   fprintf (fp,
 "-m[arm]1, -m[arm]2, -m[arm]250,\n-m[arm]3, -m[arm]6, -m[arm]7[t][[d]m]\n\
-\t\t\tselect processor architecture\n\
+-mthumb\t\t\tselect processor architecture\n\
 -mall\t\t\tallow any instruction\n\
 -mfpa10, -mfpa11\tselect floating point architecture\n\
 -mfpe-old\t\tdon't allow floating-point multiple instructions\n\
@@ -4315,6 +5818,7 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
      int reloc;
 {
   fixS *new_fix;
+  arm_fix_data *arm_data;
 
   switch (exp->X_op)
     {
@@ -4326,25 +5830,16 @@ fix_new_arm (frag, where, size, exp, pc_rel, reloc)
       break;
 
     default:
-      {
-       const char *fake;
-       symbolS *symbolP;
-       
-       /* FIXME: This should be something which decode_local_label_name
-          will handle.  */
-       fake = FAKE_LABEL_NAME;
-
-       /* Putting constant symbols in absolute_section rather than
-          expr_section is convenient for the old a.out code, for which
-          S_GET_SEGMENT does not always retrieve the value put in by
-          S_SET_SEGMENT.  */
-       symbolP = symbol_new (fake, expr_section, 0, &zero_address_frag);
-       symbolP->sy_value = *exp;
-       new_fix = fix_new (frag, where, size, symbolP, 0, pc_rel, reloc);
-      }
+      new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
+                        pc_rel, reloc);
       break;
     }
 
+  /* Mark whether the fix is to a THUMB instruction, or an ARM instruction */
+  arm_data = (arm_fix_data *) obstack_alloc (&notes, sizeof (arm_fix_data));
+  new_fix->tc_fix_data = (PTR) arm_data;
+  arm_data->thumb_mode = thumb_mode;
+
   return;
 }
 
@@ -4375,3 +5870,31 @@ arm_frob_label (sym)
 {
   last_label_seen = sym;
 }
+
+int
+arm_data_in_code ()
+{
+  if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
+    {
+      *input_line_pointer = '/';
+      input_line_pointer += 5;
+      *input_line_pointer = 0;
+      return 1;
+    }
+  return 0;
+}
+
+char *
+arm_canonicalize_symbol_name (name)
+     char *name;
+{
+  int len;
+
+  if (thumb_mode && (len = strlen (name)) > 5
+      && ! strcmp (name + len - 5, "/data"))
+    {
+      *(name + len - 5) = 0;
+    }
+
+  return name;
+}
index 0ade942bda5fcf650770e128ecd7afea62364669..28519c7edd4d2d4c746bf918febf24a8751e50a8 100644 (file)
@@ -95,7 +95,7 @@ const pseudo_typeS md_pseudo_table[] =
 /* Opcode hash table.  */
 static struct hash_control *d10v_hash;
 
-/* reg_name_search does a binary search of the pre_defined_registers
+/* reg_name_search does a binary search of the d10v_predefined_registers
    array to see if "name" is a valid regiter name.  Returns the register
    number from the array on success, or -1 on failure. */
 
@@ -107,18 +107,18 @@ reg_name_search (name)
   int cmp;
 
   low = 0;
-  high = reg_name_cnt() - 1;
+  high = d10v_reg_name_cnt() - 1;
 
   do
     {
       middle = (low + high) / 2;
-      cmp = strcasecmp (name, pre_defined_registers[middle].name);
+      cmp = strcasecmp (name, d10v_predefined_registers[middle].name);
       if (cmp < 0)
        high = middle - 1;
       else if (cmp > 0)
        low = middle + 1;
       else 
-         return pre_defined_registers[middle].value;
+         return d10v_predefined_registers[middle].value;
     }
   while (low <= high);
   return -1;
@@ -1225,7 +1225,7 @@ tc_gen_reloc (seg, fixp)
      fixS *fixp;
 {
   arelent *reloc;
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  reloc = (arelent *) xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
index d07764ec4b3528c66071f331f1a21a1cbea10d39..7f04277bdec14c852ee046f66297f6c2abd0ab0d 100644 (file)
@@ -104,7 +104,7 @@ typedef struct _i386_insn i386_insn;
 
 /* This array holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful */
-#if defined (TE_I386AIX) || defined (OBJ_ELF)
+#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 const char comment_chars[] = "#/";
 #else
 const char comment_chars[] = "#";
@@ -118,7 +118,7 @@ const char comment_chars[] = "#";
    #NO_APP at the beginning of its output. */
 /* Also note that comments started like this one will always work if
    '/' isn't otherwise defined.  */
-#if defined (TE_I386AIX) || defined (OBJ_ELF)
+#if defined (TE_I386AIX) || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
 const char line_comment_chars[] = "";
 #else
 const char line_comment_chars[] = "/";
@@ -577,10 +577,13 @@ md_begin ()
       operand_chars[(unsigned char) *p] = *p;
   }
 
-#ifdef OBJ_ELF
-  record_alignment (text_section, 2);
-  record_alignment (data_section, 2);
-  record_alignment (bss_section, 2);
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+    {
+      record_alignment (text_section, 2);
+      record_alignment (data_section, 2);
+      record_alignment (bss_section, 2);
+    }
 #endif
 }
 
@@ -2653,11 +2656,13 @@ md_apply_fix3 (fixP, valp, seg)
   if (fixP->fx_r_type == BFD_RELOC_32_PCREL && fixP->fx_addsy)
     {
 #ifndef OBJ_AOUT
-      value += fixP->fx_where + fixP->fx_frag->fr_address;
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour)
+       value += fixP->fx_where + fixP->fx_frag->fr_address;
 #endif
-#ifdef OBJ_ELF
-      if (S_GET_SEGMENT (fixP->fx_addsy) == seg
-         || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0)
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+      if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+         && (S_GET_SEGMENT (fixP->fx_addsy) == seg
+             || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0))
        {
          /* Yes, we add the values in twice.  This is because
             bfd_perform_relocation subtracts them out again.  I think
@@ -2670,8 +2675,9 @@ md_apply_fix3 (fixP, valp, seg)
 
   /* Fix a few things - the dynamic linker expects certain values here,
      and we must not dissappoint it. */
-#ifdef OBJ_ELF
-  if (fixP->fx_addsy)
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+      && fixP->fx_addsy)
     switch(fixP->fx_r_type) {
     case BFD_RELOC_386_PLT32:
       /* Make the jump instruction point to the address of the operand.  At
@@ -2860,7 +2866,7 @@ md_parse_option (c, arg)
       flag_do_long_jump = 1;
       break;
 
-#ifdef OBJ_ELF
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
       /* -k: Ignore for FreeBSD compatibility.  */
     case 'k':
       break;
@@ -2889,9 +2895,32 @@ md_show_usage (stream)
   fprintf (stream, "\
 -m                     do long jump\n");
 }
-\f
-/* We have no need to default values of symbols.  */
 
+#ifdef BFD_ASSEMBLER
+#ifdef OBJ_MAYBE_ELF
+#ifdef OBJ_MAYBE_COFF
+
+/* Pick the target format to use.  */
+
+const char  *
+i386_target_format ()
+{
+  switch (OUTPUT_FLAVOR)
+    {
+    case bfd_target_coff_flavour:
+      return "coff-i386";
+    case bfd_target_elf_flavour:
+      return "elf32-i386";
+    default:
+      abort ();
+      return NULL;
+    }
+}
+
+#endif /* OBJ_MAYBE_COFF */
+#endif /* OBJ_MAYBE_ELF */
+#endif /* BFD_ASSEMBLER */
+\f
 /* ARGSUSED */
 symbolS *
 md_undefined_symbol (name)
@@ -3001,9 +3030,7 @@ tc_gen_reloc (section, fixp)
       && fixp->fx_addsy == GOT_symbol)
     code = BFD_RELOC_386_GOTPC;
 
-  rel = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  if (rel == NULL)
-    as_fatal ("Out of memory");
+  rel = (arelent *) xmalloc (sizeof (arelent));
   rel->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   rel->address = fixp->fx_frag->fr_address + fixp->fx_where;
   if (fixp->fx_pcrel)
index 4ee9f8a171c7f3126788cdce460f4bbef96877f5..ec92ca2efb67e9d5b33b193d26a68f020fb96e02 100644 (file)
@@ -44,7 +44,7 @@ const char *m68k_comment_chars = "|";
    first line of the input file.  This is because the compiler outputs
    #NO_APP at the beginning of its output. */
 /* Also note that comments like this one will always work. */
-const char line_comment_chars[] = "#";
+const char line_comment_chars[] = "#*";
 
 const char line_separator_chars[] = "";
 
@@ -856,8 +856,7 @@ tc_gen_reloc (section, fixp)
 #undef F
 #undef MAP
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  assert (reloc != 0);
+  reloc = (arelent *) xmalloc (sizeof (arelent));
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
 #ifndef OBJ_ELF
@@ -904,7 +903,6 @@ m68k_ip (instring)
   char c;
   int losing;
   int opsfound;
-  char *crack_operand ();
   LITTLENUM_TYPE words[6];
   LITTLENUM_TYPE *wordp;
   unsigned long ok_arch = 0;
@@ -3370,6 +3368,7 @@ md_assemble (str)
              n = 1;
              break;
            case 'w':
+           case 'W':
              n = 2;
              break;
            case 'l':
index a86b2db847fb5075591a39ed7f0ed15a164191f6..9c9db9a7ebf2d06ec19608dce2f471c1a872b0dd 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-mn10300.c -- Assembler code for the Matsushita 10300
 
-   Copyright (C) 1996 Free Software Foundation.
+   Copyright (C) 1996, 1997 Free Software Foundation.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -53,6 +53,32 @@ const char EXP_CHARS[] = "eE";
 const char FLT_CHARS[] = "dD";
 \f
 
+const relax_typeS md_relax_table[] = {
+  /* bCC relaxing */
+  {0x7f, -0x80, 2, 1},
+  {0x7fff, -0x8000, 5, 2},
+  {0x7fffffff, -0x80000000, 7, 0},
+
+  /* bCC relaxing (uncommon cases) */
+  {0x7f, -0x80, 3, 4},
+  {0x7fff, -0x8000, 6, 5},
+  {0x7fffffff, -0x80000000, 8, 0},
+
+  /* call relaxing */
+  {0x7fff, -0x8000, 5, 7},
+  {0x7fffffff, -0x80000000, 7, 0},
+
+  /* calls relaxing */
+  {0x7fff, -0x8000, 4, 9},
+  {0x7fffffff, -0x80000000, 6, 0},
+
+  /* jmp relaxing */
+  {0x7f, -0x80, 2, 11},
+  {0x7fff, -0x8000, 3, 12},
+  {0x7fffffff, -0x80000000, 5, 0},
+
+};
+
 /* local functions */
 static void mn10300_insert_operand PARAMS ((unsigned long *, unsigned long *,
                                            const struct mn10300_operand *,
@@ -361,8 +387,285 @@ md_convert_frag (abfd, sec, fragP)
   asection *sec;
   fragS *fragP;
 {
-  /* printf ("call to md_convert_frag \n"); */
-  abort ();
+  static unsigned long label_count = 0;
+  char buf[40];
+
+  subseg_change (sec, 0);
+  if (fragP->fr_subtype == 0)
+    {
+      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 2;
+    }
+  else if (fragP->fr_subtype == 1)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xc8:
+         opcode = 0xc9;
+         break;
+       case 0xc9:
+         opcode = 0xc8;
+         break;
+       case 0xc0:
+         opcode = 0xc2;
+         break;
+       case 0xc2:
+         opcode = 0xc0;
+         break;
+       case 0xc3:
+         opcode = 0xc1;
+         break;
+       case 0xc1:
+         opcode = 0xc3;
+         break;
+       case 0xc4:
+         opcode = 0xc6;
+         break;
+       case 0xc6:
+         opcode = 0xc4;
+         break;
+       case 0xc7:
+         opcode = 0xc5;
+         break;
+       case 0xc5:
+         opcode = 0xc7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 1, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 2] = 0xcc;
+      fix_new (fragP, fragP->fr_fix + 3, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else if (fragP->fr_subtype == 2)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xc8:
+         opcode = 0xc9;
+         break;
+       case 0xc9:
+         opcode = 0xc8;
+         break;
+       case 0xc0:
+         opcode = 0xc2;
+         break;
+       case 0xc2:
+         opcode = 0xc0;
+         break;
+       case 0xc3:
+         opcode = 0xc1;
+         break;
+       case 0xc1:
+         opcode = 0xc3;
+         break;
+       case 0xc4:
+         opcode = 0xc6;
+         break;
+       case 0xc6:
+         opcode = 0xc4;
+         break;
+       case 0xc7:
+         opcode = 0xc5;
+         break;
+       case 0xc5:
+         opcode = 0xc7;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 1, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 2] = 0xdc;
+      fix_new (fragP, fragP->fr_fix + 3, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 7;
+    }
+  else if (fragP->fr_subtype == 3)
+    {
+      fix_new (fragP, fragP->fr_fix + 2, 1, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 4)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xe9:
+         opcode = 0xe8;
+         break;
+       case 0xea:
+         opcode = 0xeb;
+         break;
+       case 0xeb:
+         opcode = 0xea;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xcc;
+      fix_new (fragP, fragP->fr_fix + 4, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 6;
+    }
+  else if (fragP->fr_subtype == 5)
+    {
+      /* Reverse the condition of the first branch.  */
+      int offset = fragP->fr_fix;
+      int opcode = fragP->fr_literal[offset + 1] & 0xff;
+
+      switch (opcode)
+       {
+       case 0xe8:
+         opcode = 0xe9;
+         break;
+       case 0xea:
+         opcode = 0xeb;
+         break;
+       case 0xeb:
+         opcode = 0xea;
+         break;
+       default:
+         abort ();
+       }
+      fragP->fr_literal[offset + 1] = opcode;
+
+      /* Create a fixup for the reversed conditional branch.  */
+      sprintf (buf, "%s_%d", FAKE_LABEL_NAME, label_count++);
+      fix_new (fragP, fragP->fr_fix + 2, 1,
+              symbol_new (buf, sec, 0, fragP->fr_next),
+              fragP->fr_offset + 2, 1, BFD_RELOC_8_PCREL);
+
+      /* Now create the unconditional branch + fixup to the
+        final target.  */
+      fragP->fr_literal[offset + 3] = 0xdc;
+      fix_new (fragP, fragP->fr_fix + 4, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 8;
+    }
+  else if (fragP->fr_subtype == 6)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xcd;
+      fix_new (fragP, fragP->fr_fix + 1, 2, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else if (fragP->fr_subtype == 7)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xdd;
+      fragP->fr_literal[offset + 5] = fragP->fr_literal[offset + 3];
+      fragP->fr_literal[offset + 6] = fragP->fr_literal[offset + 4];
+
+      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 7;
+    }
+  else if (fragP->fr_subtype == 8)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xfa;
+      fragP->fr_literal[offset + 1] = 0xff;
+      fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 4;
+    }
+  else if (fragP->fr_subtype == 9)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xfc;
+      fragP->fr_literal[offset + 1] = 0xff;
+
+      fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol,
+              fragP->fr_offset + 2, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 6;
+    }
+  else if (fragP->fr_subtype == 10)
+    {
+      fragP->fr_literal[fragP->fr_fix] = 0xca;
+      fix_new (fragP, fragP->fr_fix + 1, 1, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_8_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 2;
+    }
+  else if (fragP->fr_subtype == 11)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xcc;
+
+      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_16_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 3;
+    }
+  else if (fragP->fr_subtype == 12)
+    {
+      int offset = fragP->fr_fix;
+      fragP->fr_literal[offset] = 0xdc;
+
+      fix_new (fragP, fragP->fr_fix + 1, 4, fragP->fr_symbol,
+              fragP->fr_offset + 1, 1, BFD_RELOC_32_PCREL);
+      fragP->fr_var = 0;
+      fragP->fr_fix += 5;
+    }
+  else
+    abort ();
 }
 
 valueT
@@ -412,7 +715,7 @@ md_assemble (str)
   struct mn10300_opcode *opcode;
   struct mn10300_opcode *next_opcode;
   const unsigned char *opindex_ptr;
-  int next_opindex;
+  int next_opindex, relaxable;
   unsigned long insn, extension, size = 0;
   char *f;
   int i;
@@ -445,6 +748,7 @@ md_assemble (str)
       char *hold;
       int extra_shift = 0;
 
+      relaxable = 0;
       fc = 0;
       match = 0;
       next_opindex = 0;
@@ -472,6 +776,9 @@ md_assemble (str)
          while (*str == ' ' || *str == ',')
            ++str;
 
+         if (operand->flags & MN10300_OPERAND_RELAX)
+           relaxable = 1;
+
          /* Gather the operand. */
          hold = input_line_pointer;
          input_line_pointer = str;
@@ -686,7 +993,8 @@ md_assemble (str)
              /* If this operand can be promoted, and it doesn't
                 fit into the allocated bitfield for this insn,
                 then promote it (ie this opcode does not match).  */
-             if (operand->flags & MN10300_OPERAND_PROMOTE
+             if (operand->flags
+                 & (MN10300_OPERAND_PROMOTE | MN10300_OPERAND_RELAX)
                  && ! check_operand (insn, operand, ex.X_add_number))
                {
                  input_line_pointer = hold;
@@ -778,192 +1086,244 @@ keep_going:
   if (opcode->format == FMT_D4)
     size = 6;
 
-  /* Allocate space for the instruction.  */
-  f = frag_more (size);
-
-  /* Fill in bytes for the instruction.  Note that opcode fields
-     are written big-endian, 16 & 32bit immediates are written
-     little endian.  Egad.  */
-  if (opcode->format == FMT_S0
-      || opcode->format == FMT_S1
-      || opcode->format == FMT_D0
-      || opcode->format == FMT_D1)
-    {
-      number_to_chars_bigendian (f, insn, size);
-    }
-  else if (opcode->format == FMT_S2
-          && opcode->opcode != 0xdf0000
-          && opcode->opcode != 0xde0000)
-    {
-      /* A format S2 instruction that is _not_ "ret" and "retf".  */
-      number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
-      number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
-    }
-  else if (opcode->format == FMT_S2)
-    {
-      /* This must be a ret or retf, which is written entirely in big-endian
-        format.  */
-      number_to_chars_bigendian (f, insn, 3);
-    }
-  else if (opcode->format == FMT_S4
-          && opcode->opcode != 0xdc000000)
-    {
-      /* This must be a format S4 "call" instruction.  What a pain.  */
-      unsigned long temp = (insn >> 8) & 0xffff;
-      number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
-      number_to_chars_littleendian (f + 1, temp, 2);
-      number_to_chars_bigendian (f + 3, insn & 0xff, 1);
-      number_to_chars_bigendian (f + 4, extension & 0xff, 1);
-    }
-  else if (opcode->format == FMT_S4)
-    {
-      /* This must be a format S4 "jmp" instruction.  */
-      unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
-      number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
-      number_to_chars_littleendian (f + 1, temp, 4);
-    }
-  else if (opcode->format == FMT_S6)
-    {
-      unsigned long temp = ((insn & 0xffffff) << 8)
-                           | ((extension >> 16) & 0xff);
-      number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
-      number_to_chars_littleendian (f + 1, temp, 4);
-      number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
-      number_to_chars_bigendian (f + 6, extension & 0xff, 1);
-    }
-  else if (opcode->format == FMT_D2
-          && opcode->opcode != 0xfaf80000
-          && opcode->opcode != 0xfaf00000
-          && opcode->opcode != 0xfaf40000)
-    {
-      /* A format D2 instruction where the 16bit immediate is
-        really a single 16bit value, not two 8bit values.  */
-      number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
-      number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
-    }
-  else if (opcode->format == FMT_D2)
-    {
-      /* A format D2 instruction where the 16bit immediate
-        is really two 8bit immediates.  */
-      number_to_chars_bigendian (f, insn, 4);
-    }
-  else if (opcode->format == FMT_D4)
-    {
-      unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
-      number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
-      number_to_chars_littleendian (f + 2, temp, 4);
-    }
-  else if (opcode->format == FMT_D5)
+  if (relaxable && fc > 0)
     {
-      unsigned long temp = ((insn & 0xffff) << 16) | ((extension >> 8) & 0xffff);
-      number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
-      number_to_chars_littleendian (f + 2, temp, 4);
-      number_to_chars_bigendian (f + 6, extension & 0xff, 1);
-    }
+      int type;
+
+      /* bCC */
+      if (size == 2)
+       type = 0;
+      /* call */
+      else if (size == 5)
+        type = 6;
+      /* calls */
+      else if (size == 4)
+       type = 8;
+      /* jmp */
+      else if (size == 3 && opcode->opcode == 0xcc0000)
+       type = 10;
+      /* bCC (uncommon cases) */
+      else
+       type = 3;
 
-  /* Create any fixups.  */
-  for (i = 0; i < fc; i++)
+      f = frag_var (rs_machine_dependent, 8, 8 - size, type,
+                   fixups[0].exp.X_add_symbol,
+                   fixups[0].exp.X_add_number,
+                   (char *)fixups[0].opindex);
+      
+      /* This is pretty hokey.  We basically just care about the
+        opcode, so we have to write out the first word big endian.
+
+        The exception is "call", which has two operands that we
+        care about.
+
+        The first operand (the register list) happens to be in the
+        first instruction word, and will be in the right place if
+        we output the first word in big endian mode.
+
+        The second operand (stack size) is in the extension word,
+        and we want it to appear as the first character in the extension
+        word (as it appears in memory).  Luckily, writing the extension
+        word in big endian format will do what we want.  */
+      number_to_chars_bigendian (f, insn, size > 4 ? 4 : size);
+      if (size > 8)
+       {
+         number_to_chars_bigendian (f + 4, extension, 4);
+         number_to_chars_bigendian (f + 8, 0, size - 8);
+       }
+      else if (size > 4)
+       number_to_chars_bigendian (f + 4, extension, size - 4);
+    }
+  else
     {
-      const struct mn10300_operand *operand;
+      /* Allocate space for the instruction.  */
+      f = frag_more (size);
+
+      /* Fill in bytes for the instruction.  Note that opcode fields
+        are written big-endian, 16 & 32bit immediates are written
+        little endian.  Egad.  */
+      if (opcode->format == FMT_S0
+         || opcode->format == FMT_S1
+         || opcode->format == FMT_D0
+         || opcode->format == FMT_D1)
+       {
+         number_to_chars_bigendian (f, insn, size);
+       }
+      else if (opcode->format == FMT_S2
+              && opcode->opcode != 0xdf0000
+              && opcode->opcode != 0xde0000)
+       {
+         /* A format S2 instruction that is _not_ "ret" and "retf".  */
+         number_to_chars_bigendian (f, (insn >> 16) & 0xff, 1);
+         number_to_chars_littleendian (f + 1, insn & 0xffff, 2);
+       }
+      else if (opcode->format == FMT_S2)
+       {
+         /* This must be a ret or retf, which is written entirely in
+            big-endian format.  */
+         number_to_chars_bigendian (f, insn, 3);
+       }
+      else if (opcode->format == FMT_S4
+              && opcode->opcode != 0xdc000000)
+       {
+         /* This must be a format S4 "call" instruction.  What a pain.  */
+         unsigned long temp = (insn >> 8) & 0xffff;
+         number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+         number_to_chars_littleendian (f + 1, temp, 2);
+         number_to_chars_bigendian (f + 3, insn & 0xff, 1);
+         number_to_chars_bigendian (f + 4, extension & 0xff, 1);
+       }
+      else if (opcode->format == FMT_S4)
+       {
+         /* This must be a format S4 "jmp" instruction.  */
+         unsigned long temp = ((insn & 0xffffff) << 8) | (extension & 0xff);
+         number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+         number_to_chars_littleendian (f + 1, temp, 4);
+       }
+      else if (opcode->format == FMT_S6)
+       {
+         unsigned long temp = ((insn & 0xffffff) << 8)
+           | ((extension >> 16) & 0xff);
+         number_to_chars_bigendian (f, (insn >> 24) & 0xff, 1);
+         number_to_chars_littleendian (f + 1, temp, 4);
+         number_to_chars_bigendian (f + 5, (extension >> 8) & 0xff, 1);
+         number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+       }
+      else if (opcode->format == FMT_D2
+              && opcode->opcode != 0xfaf80000
+              && opcode->opcode != 0xfaf00000
+              && opcode->opcode != 0xfaf40000)
+       {
+         /* A format D2 instruction where the 16bit immediate is
+            really a single 16bit value, not two 8bit values.  */
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, insn & 0xffff, 2);
+       }
+      else if (opcode->format == FMT_D2)
+       {
+         /* A format D2 instruction where the 16bit immediate
+            is really two 8bit immediates.  */
+         number_to_chars_bigendian (f, insn, 4);
+       }
+      else if (opcode->format == FMT_D4)
+       {
+         unsigned long temp = ((insn & 0xffff) << 16) | (extension & 0xffff);
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, temp, 4);
+       }
+      else if (opcode->format == FMT_D5)
+       {
+         unsigned long temp = ((insn & 0xffff) << 16)
+                               | ((extension >> 8) & 0xffff);
+         number_to_chars_bigendian (f, (insn >> 16) & 0xffff, 2);
+         number_to_chars_littleendian (f + 2, temp, 4);
+         number_to_chars_bigendian (f + 6, extension & 0xff, 1);
+       }
 
-      operand = &mn10300_operands[fixups[i].opindex];
-      if (fixups[i].reloc != BFD_RELOC_UNUSED)
+      /* Create any fixups.  */
+      for (i = 0; i < fc; i++)
        {
-         reloc_howto_type *reloc_howto;
-         int size;
-         int offset;
-         fixS *fixP;
+         const struct mn10300_operand *operand;
+
+         operand = &mn10300_operands[fixups[i].opindex];
+         if (fixups[i].reloc != BFD_RELOC_UNUSED)
+           {
+             reloc_howto_type *reloc_howto;
+             int size;
+             int offset;
+             fixS *fixP;
 
-         reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
+             reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc);
 
-         if (!reloc_howto)
-           abort();
+             if (!reloc_howto)
+               abort();
          
-         size = bfd_get_reloc_size (reloc_howto);
+             size = bfd_get_reloc_size (reloc_howto);
 
-         if (size < 1 || size > 4)
-           abort();
+             if (size < 1 || size > 4)
+               abort();
 
-         offset = 4 - size;
-         fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size,
-                             &fixups[i].exp, 
-                             reloc_howto->pc_relative,
-                             fixups[i].reloc);
-       }
-      else
-       {
-         int reloc, pcrel, reloc_size, offset;
-         fixS *fixP;
-
-         reloc = BFD_RELOC_NONE;
-         /* How big is the reloc?  Remember SPLIT relocs are
-            implicitly 32bits.  */
-         if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
-           reloc_size = 32;
+             offset = 4 - size;
+             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                                 size, &fixups[i].exp,
+                                 reloc_howto->pc_relative,
+                                 fixups[i].reloc);
+           }
          else
-           reloc_size = operand->bits;
-
-         /* Is the reloc pc-relative?  */
-         pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
-
-         /* Gross.  This disgusting hack is to make sure we
-            get the right offset for the 16/32 bit reloc in 
-            "call" instructions.  Basically they're a pain
-            because the reloc isn't at the end of the instruction.  */
-         if ((size == 5 || size == 7)
-             && (((insn >> 24) & 0xff) == 0xcd
-                 || ((insn >> 24) & 0xff) == 0xdd))
-           size -= 2;
-
-         /* Similarly for certain bit instructions which don't
-            hav their 32bit reloc at the tail of the instruction.  */
-         if (size == 7
-             && (((insn >> 16) & 0xffff) == 0xfe00
-                 || ((insn >> 16) & 0xffff) == 0xfe01
-                 || ((insn >> 16) & 0xffff) == 0xfe02))
-           size -= 1;
+           {
+             int reloc, pcrel, reloc_size, offset;
+             fixS *fixP;
+
+             reloc = BFD_RELOC_NONE;
+             /* How big is the reloc?  Remember SPLIT relocs are
+                implicitly 32bits.  */
+             if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
+               reloc_size = 32;
+             else
+               reloc_size = operand->bits;
+
+             /* Is the reloc pc-relative?  */
+             pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0;
+
+             /* Gross.  This disgusting hack is to make sure we
+                get the right offset for the 16/32 bit reloc in 
+                "call" instructions.  Basically they're a pain
+                because the reloc isn't at the end of the instruction.  */
+             if ((size == 5 || size == 7)
+                 && (((insn >> 24) & 0xff) == 0xcd
+                     || ((insn >> 24) & 0xff) == 0xdd))
+               size -= 2;
+
+             /* Similarly for certain bit instructions which don't
+                hav their 32bit reloc at the tail of the instruction.  */
+             if (size == 7
+                 && (((insn >> 16) & 0xffff) == 0xfe00
+                     || ((insn >> 16) & 0xffff) == 0xfe01
+                     || ((insn >> 16) & 0xffff) == 0xfe02))
+               size -= 1;
        
-         offset = size - reloc_size / 8;
+             offset = size - reloc_size / 8;
 
-         /* Choose a proper BFD relocation type.  */
-         if (pcrel)
-           {
-             if (reloc_size == 32)
-               reloc = BFD_RELOC_32_PCREL;
-             else if (reloc_size == 16)
-               reloc = BFD_RELOC_16_PCREL;
-             else if (reloc_size == 8)
-               reloc = BFD_RELOC_8_PCREL;
+             /* Choose a proper BFD relocation type.  */
+             if (pcrel)
+               {
+                 if (reloc_size == 32)
+                   reloc = BFD_RELOC_32_PCREL;
+                 else if (reloc_size == 16)
+                   reloc = BFD_RELOC_16_PCREL;
+                 else if (reloc_size == 8)
+                   reloc = BFD_RELOC_8_PCREL;
+                 else
+                   abort ();
+               }
              else
-               abort ();
-           }
-         else
-           {
-             if (reloc_size == 32)
-               reloc = BFD_RELOC_32;
+               {
+                 if (reloc_size == 32)
+                   reloc = BFD_RELOC_32;
+                 else if (reloc_size == 16)
+                   reloc = BFD_RELOC_16;
+                 else if (reloc_size == 8)
+                   reloc = BFD_RELOC_8;
+                 else
+                   abort ();
+               }
+
+             /* Convert the size of the reloc into what fix_new_exp wants.  */
+             reloc_size = reloc_size / 8;
+             if (reloc_size == 8)
+               reloc_size = 0;
              else if (reloc_size == 16)
-               reloc = BFD_RELOC_16;
-             else if (reloc_size == 8)
-               reloc = BFD_RELOC_8;
-             else
-               abort ();
-           }
+               reloc_size = 1;
+             else if (reloc_size == 32)
+               reloc_size = 2;
+
+             fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
+                                 reloc_size, &fixups[i].exp, pcrel,
+                                 ((bfd_reloc_code_real_type) reloc));
 
-         /* Convert the size of the reloc into what fix_new_exp wants.  */
-         reloc_size = reloc_size / 8;
-         if (reloc_size == 8)
-           reloc_size = 0;
-         else if (reloc_size == 16)
-           reloc_size = 1;
-         else if (reloc_size == 32)
-           reloc_size = 2;
-
-         fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-                             reloc_size, &fixups[i].exp, pcrel,
-                             ((bfd_reloc_code_real_type) reloc));
-
-         if (pcrel)
-           fixP->fx_offset += offset;
+             if (pcrel)
+               fixP->fx_offset += offset;
+           }
        }
     }
 }
@@ -978,7 +1338,7 @@ tc_gen_reloc (seg, fixp)
      fixS *fixp;
 {
   arelent *reloc;
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == (reloc_howto_type *) NULL)
@@ -1009,7 +1369,43 @@ md_estimate_size_before_relax (fragp, seg)
      fragS *fragp;
      asection *seg;
 {
-  return 0;
+  if (fragp->fr_subtype == 0)
+    return 2;
+  if (fragp->fr_subtype == 3)
+    return 3;
+  if (fragp->fr_subtype == 6)
+    {
+      if (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol))
+       {
+         fragp->fr_subtype = 7;
+         return 7;
+       }
+      else
+       return 5;
+    }
+  if (fragp->fr_subtype == 8)
+    {
+      if (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol))
+       {
+         fragp->fr_subtype = 9;
+         return 6;
+       }
+      else
+       return 4;
+    }
+  if (fragp->fr_subtype == 10)
+    {
+      if (!S_IS_DEFINED (fragp->fr_symbol)
+         || seg != S_GET_SEGMENT (fragp->fr_symbol))
+       {
+         fragp->fr_subtype = 12;
+         return 5;
+       }
+      else
+       return 2;
+    }
 } 
 
 long
index 00a961daf42fd81208f2bd684d6743946b68accb..49b5ee69cf7fc7df6aba9ceacd0799cd6b2862bf 100644 (file)
@@ -1,5 +1,5 @@
 /* tc-sparc.c -- Assemble for the SPARC
-   Copyright (C) 1989, 90-95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1989, 90-96, 1997 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -355,7 +355,7 @@ s_reserve (ignore)
          subseg_set (bss_section, 1); /* switch to bss */
 
          if (align)
-           frag_align (align, 0); /* do alignment */
+           frag_align (align, 0, 0); /* do alignment */
 
          /* detach from old frag */
          if (S_GET_SEGMENT(symbolP) == bss_section)
@@ -472,7 +472,7 @@ s_common (ignore)
          record_alignment (bss_section, align);
          subseg_set (bss_section, 0);
          if (align)
-           frag_align (align, 0);
+           frag_align (align, 0, 0);
          if (S_GET_SEGMENT (symbolP) == bss_section)
            symbolP->sy_frag->fr_symbol = 0;
          symbolP->sy_frag = frag_now;
@@ -515,6 +515,11 @@ s_common (ignore)
        ;
       goto allocate_common;
     }
+
+#ifdef BFD_ASSEMBLER
+  symbolP->bsym->flags |= BSF_OBJECT;
+#endif
+
   demand_empty_rest_of_line ();
   return;
 
@@ -2613,8 +2618,7 @@ tc_gen_reloc (section, fixp)
   arelent *reloc;
   bfd_reloc_code_real_type code;
 
-  reloc = (arelent *) bfd_alloc_by_size_t (stdoutput, sizeof (arelent));
-  assert (reloc != 0);
+  reloc = (arelent *) xmalloc (sizeof (arelent));
 
   reloc->sym_ptr_ptr = &fixp->fx_addsy->bsym;
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
@@ -2972,7 +2976,7 @@ md_show_usage (stream)
   fprintf (stream, "\
                        specify variant of SPARC architecture\n\
 -bump                  warn when assembler switches architectures\n\
--sparc                 ignored\n
+-sparc                 ignored\n\
 --enforce-aligned-data force .long, etc., to be aligned correctly\n");
 #ifdef OBJ_AOUT
   fprintf (stream, "\
index a67b34aee8a88b3ba06b83dc0ab7941d76c81f46..e7370753379ffb277b48e1cb91a55fadedfe83dd 100644 (file)
@@ -851,8 +851,7 @@ write_relocs (abfd, sec, xxx)
 
 #ifndef RELOC_EXPANSION_POSSIBLE
   /* Set up reloc information as well.  */
-  relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
-                                            n * sizeof (arelent *));
+  relocs = (arelent **) xmalloc (n * sizeof (arelent *));
   memset ((char*)relocs, 0, n * sizeof (arelent*));
 
   i = 0;
@@ -913,7 +912,7 @@ write_relocs (abfd, sec, xxx)
          as_bad_where (fixp->fx_file, fixp->fx_line, "relocation overflow");
          break;
        default:
-         as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+         as_fatal ("%s:%u: bad return from bfd_install_relocation",
                    fixp->fx_file, fixp->fx_line);
        }
       relocs[i++] = reloc;
@@ -921,8 +920,7 @@ write_relocs (abfd, sec, xxx)
 #else
   n = n * MAX_RELOC_EXPANSION;
   /* Set up reloc information as well.  */
-  relocs = (arelent **) bfd_alloc_by_size_t (stdoutput,
-                                            n * sizeof (arelent *));
+  relocs = (arelent **) xmalloc (stdoutput, n * sizeof (arelent *));
 
   i = 0;
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
@@ -975,7 +973,7 @@ write_relocs (abfd, sec, xxx)
                            "relocation overflow");
              break;
            default:
-             as_fatal ("%s:%u: bad return from bfd_perform_relocation",
+             as_fatal ("%s:%u: bad return from bfd_install_relocation",
                        fixp->fx_file, fixp->fx_line);
            }
         }
@@ -1339,7 +1337,7 @@ write_object_file ()
   for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next)
     {
       subseg_set (frchainP->frch_seg, frchainP->frch_subseg);
-      frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE);
+      frag_align (SUB_SEGMENT_ALIGN (now_seg), NOP_OPCODE, 0);
       /* frag_align will have left a new frag.
         Use this last frag for an empty ".fill".
 
@@ -2037,13 +2035,18 @@ relax_segment (segment_frag_root, segment)
        case rs_align:
        case rs_align_code:
          {
-           int offset = relax_align (address, (int) fragP->fr_offset);
+           addressT offset = relax_align (address, (int) fragP->fr_offset);
+
+           if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype)
+             offset = 0;
+
            if (offset % fragP->fr_var != 0)
              {
-               as_bad ("alignment padding (%d bytes) not a multiple of %ld",
-                       offset, (long) fragP->fr_var);
+               as_bad ("alignment padding (%lu bytes) not a multiple of %ld",
+                       (unsigned long) offset, (long) fragP->fr_var);
                offset -= (offset % fragP->fr_var);
              }
+
            address += offset;
          }
          break;
@@ -2086,8 +2089,8 @@ relax_segment (segment_frag_root, segment)
        for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next)
          {
            long growth = 0;
-           unsigned long was_address;
-           long offset;
+           addressT was_address;
+           offsetT offset;
            symbolS *symbolP;
 
            was_address = fragP->fr_address;
@@ -2164,12 +2167,24 @@ relax_segment (segment_frag_root, segment)
 #endif
              case rs_align:
              case rs_align_code:
-               growth = (relax_align ((relax_addressT) (address
-                                                        + fragP->fr_fix),
-                                      (int) offset)
-                         - relax_align ((relax_addressT) (was_address
-                                                          + fragP->fr_fix),
-                                        (int) offset));
+               {
+                 addressT oldoff, newoff;
+
+                 oldoff = relax_align (was_address + fragP->fr_fix,
+                                       (int) offset);
+                 newoff = relax_align (address + fragP->fr_fix,
+                                       (int) offset);
+
+                 if (fragP->fr_subtype != 0)
+                   {
+                     if (oldoff > fragP->fr_subtype)
+                       oldoff = 0;
+                     if (newoff > fragP->fr_subtype)
+                       newoff = 0;
+                   }
+
+                 growth = newoff - oldoff;
+               }
                break;
 
              case rs_org: