]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gas/config/tc-alpha.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gas / config / tc-alpha.c
index e8f0bad55f34fae4a4bbe924d028f2c0ffc3fa1c..030ba21b523dbbface7dc218043f073420ad36d6 100644 (file)
@@ -1,6 +1,5 @@
 /* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU.
-   Copyright 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1989-2021 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.
@@ -11,7 +10,7 @@
 
    GAS is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
 
 #include "as.h"
 #include "subsegs.h"
-#include "struc-symbol.h"
 #include "ecoff.h"
 
 #include "opcode/alpha.h"
 
 #ifdef OBJ_ELF
 #include "elf/alpha.h"
-#include "dwarf2dbg.h"
 #endif
 
+#ifdef OBJ_EVAX
+#include "vms.h"
+#include "vms/egps.h"
+#endif
+
+#include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 #include "safe-ctype.h"
 \f
 #define MAX_INSN_FIXUPS                 2
 #define MAX_INSN_ARGS           5
 
+/* Used since new relocation types are introduced in this
+   file (DUMMY_RELOC_LITUSE_*) */
+typedef int extended_bfd_reloc_code_real_type;
+
 struct alpha_fixup
 {
   expressionS exp;
-  bfd_reloc_code_real_type reloc;
+  /* bfd_reloc_code_real_type reloc; */
+  extended_bfd_reloc_code_real_type reloc;
+#ifdef OBJ_EVAX
+  /* The symbol of the item in the linkage section.  */
+  symbolS *xtrasym;
+
+  /* The symbol of the procedure descriptor.  */
+  symbolS *procsym;
+#endif
 };
 
 struct alpha_insn
@@ -92,7 +107,7 @@ enum alpha_macro_arg
     MACRO_OPIR,
     MACRO_CPIR,
     MACRO_FPR,
-    MACRO_EXP,
+    MACRO_EXP
   };
 
 struct alpha_macro
@@ -225,7 +240,7 @@ const char EXP_CHARS[] = "eE";
 /* Characters which mean that a number is a floating point constant,
    as in 0d1.0.  */
 /* XXX: Do all of these really get used on the alpha??  */
-char FLT_CHARS[] = "rRsSfFdDxXpP";
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
 
 #ifdef OBJ_EVAX
 const char *md_shortopts = "Fm:g+1h:HG:";
@@ -244,6 +259,12 @@ struct option md_longopts[] =
 #define OPTION_NO_MDEBUG (OPTION_MDEBUG + 1)
     { "mdebug", no_argument, NULL, OPTION_MDEBUG },
     { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG },
+#endif
+#ifdef OBJ_EVAX
+#define OPTION_REPLACE (OPTION_RELAX + 1)
+#define OPTION_NOREPLACE (OPTION_REPLACE+1)
+    { "replace", no_argument, NULL, OPTION_REPLACE },
+    { "noreplace", no_argument, NULL, OPTION_NOREPLACE },
 #endif
     { NULL, no_argument, NULL, 0 }
   };
@@ -268,6 +289,7 @@ size_t md_longopts_size = sizeof (md_longopts);
 
 #undef AXP_REG_GP
 #define AXP_REG_GP AXP_REG_PV
+
 #endif /* OBJ_EVAX  */
 
 /* The cpu for which we are generating code.  */
@@ -275,10 +297,10 @@ static unsigned alpha_target = AXP_OPCODE_BASE;
 static const char *alpha_target_name = "<all>";
 
 /* The hash table of instruction opcodes.  */
-static struct hash_control *alpha_opcode_hash;
+static htab_t alpha_opcode_hash;
 
 /* The hash table of macro opcodes.  */
-static struct hash_control *alpha_macro_hash;
+static htab_t alpha_macro_hash;
 
 #ifdef OBJ_ECOFF
 /* The $gp relocation symbol.  */
@@ -299,11 +321,11 @@ static symbolS *alpha_register_table[64];
 static segT alpha_lita_section;
 #endif
 #ifdef OBJ_EVAX
-static segT alpha_link_section;
-static segT alpha_ctors_section;
-static segT alpha_dtors_section;
+segT alpha_link_section;
 #endif
+#ifndef OBJ_EVAX
 static segT alpha_lit8_section;
+#endif
 
 /* Symbols referring to said sections.  */
 #ifdef OBJ_ECOFF
@@ -311,10 +333,10 @@ static symbolS *alpha_lita_symbol;
 #endif
 #ifdef OBJ_EVAX
 static symbolS *alpha_link_symbol;
-static symbolS *alpha_ctors_symbol;
-static symbolS *alpha_dtors_symbol;
 #endif
+#ifndef OBJ_EVAX
 static symbolS *alpha_lit8_symbol;
+#endif
 
 /* Literal for .litX+0x8000 within .lita.  */
 #ifdef OBJ_ECOFF
@@ -339,6 +361,14 @@ static int alpha_addr32_on = 0;
    and the section happens to not be on an eight byte boundary, it
    will align both the symbol and the .quad to an eight byte boundary.  */
 static symbolS *alpha_insn_label;
+#if defined(OBJ_ELF) || defined (OBJ_EVAX)
+static symbolS *alpha_prologue_label;
+#endif
+
+#ifdef OBJ_EVAX
+/* Symbol associate with the current jsr instruction.  */
+static symbolS *alpha_linkage_symbol;
+#endif
 
 /* Whether we should automatically align data generation pseudo-ops.
    .align 0 will turn this off.  */
@@ -358,6 +388,11 @@ static int alpha_debug;
 int alpha_flag_mdebug = -1;
 #endif
 
+#ifdef OBJ_EVAX
+/* Whether to perform the VMS procedure call optimization.  */
+int alpha_flag_replace = 1;
+#endif
+
 /* Don't fully resolve relocations, allowing code movement in the linker.  */
 static int alpha_flag_relax;
 
@@ -366,7 +401,7 @@ static int g_switch_value = 8;
 
 #ifdef OBJ_EVAX
 /* Collect information about current procedure here.  */
-static struct
+struct alpha_evax_procs
 {
   symbolS *symbol;     /* Proc pdesc symbol.  */
   int pdsckind;
@@ -379,7 +414,17 @@ static struct
   long fmask;
   int type;
   int prologue;
-} alpha_evax_proc;
+  symbolS *handler;
+  int handler_data;
+};
+
+/* Linked list of .linkage fixups.  */
+struct alpha_linkage_fixups *alpha_linkage_fixup_root;
+static struct alpha_linkage_fixups *alpha_linkage_fixup_tail;
+
+/* Current procedure descriptor.  */
+static struct alpha_evax_procs *alpha_evax_proc;
+static struct alpha_evax_procs alpha_evax_proc_data;
 
 static int alpha_flag_hash_long_names = 0;             /* -+ */
 static int alpha_flag_show_after_trunc = 0;            /* -H */
@@ -407,7 +452,7 @@ static const struct alpha_reloc_op_tag
   const char *name;                            /* String to lookup.  */
   size_t length;                               /* Size of the string.  */
   operatorT op;                                        /* Which operator to use.  */
-  bfd_reloc_code_real_type reloc;              /* Relocation before frob.  */
+  extended_bfd_reloc_code_real_type reloc;
   unsigned int require_seq : 1;                        /* Require a sequence number.  */
   unsigned int allow_seq : 1;                  /* Allow a sequence number.  */
 }
@@ -451,6 +496,10 @@ static const int alpha_num_reloc_op
 struct alpha_reloc_tag
 {
   fixS *master;                        /* The literal reloc.  */
+#ifdef OBJ_EVAX
+  struct symbol *sym;          /* Linkage section item symbol.  */
+  struct symbol *psym;         /* Pdesc symbol.  */
+#endif
   fixS *slaves;                        /* Head of linked list of lituses.  */
   segT segment;                        /* Segment relocs are in or undefined_section.  */
   long sequence;               /* Sequence #.  */
@@ -465,7 +514,7 @@ struct alpha_reloc_tag
 };
 
 /* Hash table to link up literals with the appropriate lituse.  */
-static struct hash_control *alpha_literal_hash;
+static htab_t alpha_literal_hash;
 
 /* Sequence numbers for internal use by macros.  */
 static long next_sequence_num = -1;
@@ -524,9 +573,13 @@ static const char * const mskXh_op[] = { NULL,    "mskwh", "msklh", "mskqh" };
 static const char * const stX_op[] = { "stb", "stw", "stl", "stq" };
 static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL };
 
-static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, bfd_reloc_code_real_type);
+static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, extended_bfd_reloc_code_real_type);
 static void emit_insn (struct alpha_insn *);
 static void assemble_tokens (const char *, const expressionS *, int, int);
+#ifdef OBJ_EVAX
+static const char *s_alpha_section_name (void);
+static symbolS *add_to_link_pool (symbolS *, offsetT);
+#endif
 \f
 static struct alpha_reloc_tag *
 get_alpha_reloc_tag (long sequence)
@@ -536,25 +589,29 @@ get_alpha_reloc_tag (long sequence)
 
   sprintf (buffer, "!%ld", sequence);
 
-  info = (struct alpha_reloc_tag *) hash_find (alpha_literal_hash, buffer);
+  info = (struct alpha_reloc_tag *) str_hash_find (alpha_literal_hash, buffer);
   if (! info)
     {
       size_t len = strlen (buffer);
-      const char *errmsg;
 
-      info = xcalloc (sizeof (struct alpha_reloc_tag) + len, 1);
+      info = (struct alpha_reloc_tag *)
+          xcalloc (sizeof (struct alpha_reloc_tag) + len, 1);
 
       info->segment = now_seg;
       info->sequence = sequence;
       strcpy (info->string, buffer);
-      errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info);
-      if (errmsg)
-       as_fatal (errmsg);
+      str_hash_insert (alpha_literal_hash, info->string, info, 0);
+#ifdef OBJ_EVAX
+      info->sym = 0;
+      info->psym = 0;
+#endif
     }
 
   return info;
 }
 
+#ifndef OBJ_EVAX
+
 static void
 alpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED,
                     asection *sec,
@@ -645,7 +702,7 @@ alpha_adjust_relocs (bfd *abfd ATTRIBUTE_UNUSED,
      present.  Not implemented.
 
      Also suppress the optimization if the !literals/!lituses are spread
-     in different segments.  This can happen with "intersting" uses of
+     in different segments.  This can happen with "interesting" uses of
      inline assembly; examples are present in the Linux kernel semaphores.  */
 
   for (fixp = seginfo->fix_root; fixp; fixp = next)
@@ -718,6 +775,8 @@ alpha_before_fix (void)
   if (alpha_literal_hash)
     bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL);
 }
+
+#endif
 \f
 #ifdef DEBUG_ALPHA
 static void
@@ -858,8 +917,7 @@ tokenize_arguments (char *str,
 
          ++input_line_pointer;
          SKIP_WHITESPACE ();
-         p = input_line_pointer;
-         c = get_symbol_end ();
+         c = get_symbol_name (&p);
 
          /* Parse !relocation_type.  */
          len = input_line_pointer - p;
@@ -880,7 +938,7 @@ tokenize_arguments (char *str,
            }
 
          *input_line_pointer = c;
-         SKIP_WHITESPACE ();
+         SKIP_WHITESPACE_AFTER_NAME ();
          if (*input_line_pointer != '!')
            {
              if (r->require_seq)
@@ -943,6 +1001,7 @@ tokenize_arguments (char *str,
            /* ... then fall through to plain expression.  */
            input_line_pointer = hold;
          }
+         /* Fall through.  */
 
        default:
          if (saw_arg && !saw_comma)
@@ -959,7 +1018,7 @@ tokenize_arguments (char *str,
        }
     }
 
-fini:
+ fini:
   if (saw_comma)
     goto err;
   input_line_pointer = old_input_line_pointer;
@@ -973,7 +1032,7 @@ fini:
 
   return ntok - (end_tok - tok);
 
-err:
+ err:
 #ifdef RELOC_OP_P
   is_end_of_line[(unsigned char) '!'] = 0;
 #endif
@@ -981,7 +1040,7 @@ err:
   return TOKENIZE_ERROR;
 
 #ifdef RELOC_OP_P
-err_report:
+ err_report:
   is_end_of_line[(unsigned char) '!'] = 0;
 #endif
   input_line_pointer = old_input_line_pointer;
@@ -1109,7 +1168,8 @@ assemble_tokens_to_insn (const char *opname,
   const struct alpha_opcode *opcode;
 
   /* Search opcodes.  */
-  opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
+  opcode = (const struct alpha_opcode *) str_hash_find (alpha_opcode_hash,
+                                                       opname);
   if (opcode)
     {
       int cpumatch;
@@ -1143,10 +1203,9 @@ create_literal_section (const char *name,
 
   *secp = new_sec = subseg_new (name, 0);
   subseg_set (current_section, current_subsec);
-  bfd_set_section_alignment (stdoutput, new_sec, 4);
-  bfd_set_section_flags (stdoutput, new_sec,
-                        SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
-                        | SEC_DATA);
+  bfd_set_section_alignment (new_sec, 4);
+  bfd_set_section_flags (new_sec, (SEC_RELOC | SEC_ALLOC | SEC_LOAD
+                                  | SEC_READONLY | SEC_DATA));
 
   S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec));
 }
@@ -1176,7 +1235,8 @@ static long
 load_expression (int targreg,
                 const expressionS *exp,
                 int *pbasereg,
-                expressionS *poffset)
+                expressionS *poffset,
+                const char *opname)
 {
   long emit_lituse = 0;
   offsetT addend = exp->X_add_number;
@@ -1227,7 +1287,7 @@ load_expression (int targreg,
 
        assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
-       assert (insn.nfixups == 1);
+       gas_assert (insn.nfixups == 1);
        insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
        insn.sequence = emit_lituse = next_sequence_num--;
 #endif /* OBJ_ECOFF */
@@ -1263,49 +1323,130 @@ load_expression (int targreg,
 
        assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
-       assert (insn.nfixups == 1);
+       gas_assert (insn.nfixups == 1);
        insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL;
        insn.sequence = emit_lituse = next_sequence_num--;
 #endif /* OBJ_ELF */
 #ifdef OBJ_EVAX
-       offsetT link;
-
        /* Find symbol or symbol pointer in link section.  */
 
-       if (exp->X_add_symbol == alpha_evax_proc.symbol)
+       if (exp->X_add_symbol == alpha_evax_proc->symbol)
          {
+            /* Linkage-relative expression.  */
+            set_tok_reg (newtok[0], targreg);
+
            if (range_signed_16 (addend))
              {
-               set_tok_reg (newtok[0], targreg);
                set_tok_const (newtok[1], addend);
-               set_tok_preg (newtok[2], basereg);
-               assemble_tokens_to_insn ("lda", newtok, 3, &insn);
                addend = 0;
              }
            else
              {
-               set_tok_reg (newtok[0], targreg);
                set_tok_const (newtok[1], 0);
-               set_tok_preg (newtok[2], basereg);
-               assemble_tokens_to_insn ("lda", newtok, 3, &insn);
              }
+            set_tok_preg (newtok[2], basereg);
+            assemble_tokens_to_insn ("lda", newtok, 3, &insn);
          }
        else
          {
-           if (!range_signed_32 (addend))
+           const char *symname = S_GET_NAME (exp->X_add_symbol);
+           const char *ptr1, *ptr2;
+           int symlen = strlen (symname);
+
+           if ((symlen > 4 &&
+                strcmp (ptr2 = &symname [symlen - 4], "..lk") == 0))
              {
-               link = add_to_link_pool (alpha_evax_proc.symbol,
-                                        exp->X_add_symbol, addend);
-               addend = 0;
+                /* Access to an item whose address is stored in the linkage
+                   section.  Just read the address.  */
+               set_tok_reg (newtok[0], targreg);
+
+               newtok[1] = *exp;
+               newtok[1].X_op = O_subtract;
+               newtok[1].X_op_symbol = alpha_evax_proc->symbol;
+
+               set_tok_preg (newtok[2], basereg);
+               assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+               alpha_linkage_symbol = exp->X_add_symbol;
+
+               if (poffset)
+                 set_tok_const (*poffset, 0);
+
+               if (alpha_flag_replace && targreg == 26)
+                 {
+                    /* Add a NOP fixup for 'ldX $26,YYY..NAME..lk'.  */
+                   char *ensymname;
+                   symbolS *ensym;
+
+                    /* Build the entry name as 'NAME..en'.  */
+                   ptr1 = strstr (symname, "..") + 2;
+                   if (ptr1 > ptr2)
+                     ptr1 = symname;
+                   ensymname = XNEWVEC (char, ptr2 - ptr1 + 5);
+                   memcpy (ensymname, ptr1, ptr2 - ptr1);
+                   memcpy (ensymname + (ptr2 - ptr1), "..en", 5);
+
+                   gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS);
+                   insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_NOP;
+                   ensym = symbol_find_or_make (ensymname);
+                   free (ensymname);
+                   symbol_mark_used (ensym);
+                   /* The fixup must be the same as the BFD_RELOC_ALPHA_BOH
+                      case in emit_jsrjmp.  See B.4.5.2 of the OpenVMS Linker
+                      Utility Manual.  */
+                   insn.fixups[insn.nfixups].exp.X_op = O_symbol;
+                   insn.fixups[insn.nfixups].exp.X_add_symbol = ensym;
+                   insn.fixups[insn.nfixups].exp.X_add_number = 0;
+                   insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol;
+                   insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol;
+                   insn.nfixups++;
+
+                   /* ??? Force bsym to be instantiated now, as it will be
+                      too late to do so in tc_gen_reloc.  */
+                   symbol_get_bfdsym (exp->X_add_symbol);
+                 }
+               else if (alpha_flag_replace && targreg == 27)
+                 {
+                    /* Add a lda fixup for 'ldX $27,YYY.NAME..lk+8'.  */
+                   char *psymname;
+                   symbolS *psym;
+
+                    /* Extract NAME.  */
+                   ptr1 = strstr (symname, "..") + 2;
+                   if (ptr1 > ptr2)
+                     ptr1 = symname;
+                   psymname = xmemdup0 (ptr1, ptr2 - ptr1);
+
+                   gas_assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS);
+                   insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_LDA;
+                   psym = symbol_find_or_make (psymname);
+                   free (psymname);
+                   symbol_mark_used (psym);
+                   insn.fixups[insn.nfixups].exp.X_op = O_subtract;
+                   insn.fixups[insn.nfixups].exp.X_add_symbol = psym;
+                   insn.fixups[insn.nfixups].exp.X_op_symbol = alpha_evax_proc->symbol;
+                   insn.fixups[insn.nfixups].exp.X_add_number = 0;
+                   insn.fixups[insn.nfixups].xtrasym = alpha_linkage_symbol;
+                   insn.fixups[insn.nfixups].procsym = alpha_evax_proc->symbol;
+                   insn.nfixups++;
+                 }
+
+               emit_insn (&insn);
+               return 0;
              }
            else
-             link = add_to_link_pool (alpha_evax_proc.symbol,
-                                      exp->X_add_symbol, 0);
+             {
+                /* Not in the linkage section.  Put the value into the linkage
+                   section.  */
+               symbolS *linkexp;
 
-           set_tok_reg (newtok[0], targreg);
-           set_tok_const (newtok[1], link);
-           set_tok_preg (newtok[2], basereg);
-           assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+               if (!range_signed_32 (addend))
+                 addend = sign_extend_32 (addend);
+               linkexp = add_to_link_pool (exp->X_add_symbol, 0);
+               set_tok_reg (newtok[0], targreg);
+               set_tok_sym (newtok[1], linkexp, 0);
+               set_tok_preg (newtok[2], basereg);
+               assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
+             }
          }
 #endif /* OBJ_EVAX */
 
@@ -1335,7 +1476,7 @@ load_expression (int targreg,
       set_tok_reg (newtok[0], targreg);
       newtok[1] = *exp;
       set_tok_preg (newtok[2], basereg);
-      assemble_tokens ("lda", newtok, 3, 0);
+      assemble_tokens (opname, newtok, 3, 0);
 
       if (poffset)
        set_tok_const (*poffset, 0);
@@ -1357,16 +1498,19 @@ load_expression (int targreg,
 
   if (!range_signed_32 (addend))
     {
+#ifdef OBJ_EVAX
+      symbolS *litexp;
+#else
       offsetT lit;
       long seq_num = next_sequence_num--;
+#endif
 
       /* 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);
+      litexp = add_to_link_pool (section_symbol (absolute_section), addend);
       set_tok_reg (newtok[0], targreg);
-      set_tok_const (newtok[1], lit);
+      set_tok_sym (newtok[1], litexp, 0);
       set_tok_preg (newtok[2], alpha_gp_register);
       assemble_tokens ("ldq", newtok, 3, 0);
 #else
@@ -1412,7 +1556,7 @@ load_expression (int targreg,
 
       assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
-      assert (insn.nfixups == 1);
+      gas_assert (insn.nfixups == 1);
 #ifdef OBJ_ECOFF
       insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL;
 #endif
@@ -1430,7 +1574,7 @@ load_expression (int targreg,
 
       assemble_tokens_to_insn ("ldq", newtok, 3, &insn);
 
-      assert (insn.nfixups < MAX_INSN_FIXUPS);
+      gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
       insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
       insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
@@ -1525,7 +1669,7 @@ emit_lda (const expressionS *tok,
   else
     basereg = tok[2].X_add_number;
 
-  (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL);
+  (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, "lda");
 }
 
 /* The ldah macro differs from the ldah instruction in that it has $31
@@ -1631,18 +1775,31 @@ emit_insn (struct alpha_insn *insn)
        }
       else
        {
-         reloc_howto_type *reloc_howto
-           = bfd_reloc_type_lookup (stdoutput, fixup->reloc);
-         assert (reloc_howto);
+         reloc_howto_type *reloc_howto =
+              bfd_reloc_type_lookup (stdoutput,
+                                     (bfd_reloc_code_real_type) fixup->reloc);
+         gas_assert (reloc_howto);
 
          size = bfd_get_reloc_size (reloc_howto);
-         assert (size >= 1 && size <= 4);
+
+         switch (fixup->reloc)
+           {
+#ifdef OBJ_EVAX
+           case BFD_RELOC_ALPHA_NOP:
+           case BFD_RELOC_ALPHA_BSR:
+           case BFD_RELOC_ALPHA_LDA:
+           case BFD_RELOC_ALPHA_BOH:
+             break;
+#endif
+           default:
+             gas_assert (size >= 1 && size <= 4);
+           }
 
          pcrel = reloc_howto->pc_relative;
        }
 
       fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size,
-                         &fixup->exp, pcrel, fixup->reloc);
+                         &fixup->exp, pcrel, (bfd_reloc_code_real_type) fixup->reloc);
 
       /* Turn off complaints that the addend is too large for some fixups,
          and copy in the sequence number for the explicit relocations.  */
@@ -1784,6 +1941,18 @@ emit_insn (struct alpha_insn *insn)
          fixP->tc_fix_data.info = info;
          break;
 #endif
+#ifdef OBJ_EVAX
+       case BFD_RELOC_ALPHA_NOP:
+       case BFD_RELOC_ALPHA_LDA:
+       case BFD_RELOC_ALPHA_BSR:
+       case BFD_RELOC_ALPHA_BOH:
+         info = get_alpha_reloc_tag (next_sequence_num--);
+         fixP->tc_fix_data.info = info;
+         fixP->tc_fix_data.info->sym = fixup->xtrasym;
+         fixP->tc_fix_data.info->psym = fixup->procsym;
+         break;
+#endif
+
        default:
          if ((int) fixup->reloc < 0)
            {
@@ -1801,7 +1970,7 @@ static unsigned
 insert_operand (unsigned insn,
                const struct alpha_operand *operand,
                offsetT val,
-               char *file,
+               const char *file,
                unsigned line)
 {
   if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW))
@@ -1820,7 +1989,7 @@ insert_operand (unsigned insn,
        }
 
       if (val < min || val > max)
-       as_warn_value_out_of_range (_("operand"), val, min, max, file, line);
+       as_bad_value_out_of_range (_("operand"), val, min, max, file, line);
     }
 
   if (operand->insert)
@@ -1829,7 +1998,7 @@ insert_operand (unsigned insn,
 
       insn = (*operand->insert) (insn, val, &errmsg);
       if (errmsg)
-       as_warn (errmsg);
+       as_warn ("%s", errmsg);
     }
   else
     insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
@@ -1845,7 +2014,7 @@ assemble_insn (const struct alpha_opcode *opcode,
               const expressionS *tok,
               int ntok,
               struct alpha_insn *insn,
-              bfd_reloc_code_real_type reloc)
+              extended_bfd_reloc_code_real_type reloc)
 {
   const struct alpha_operand *reloc_operand = NULL;
   const expressionS *reloc_exp = NULL;
@@ -1904,7 +2073,7 @@ assemble_insn (const struct alpha_opcode *opcode,
 
        case O_constant:
          image = insert_operand (image, operand, t->X_add_number, NULL, 0);
-         assert (reloc_operand == NULL);
+         gas_assert (reloc_operand == NULL);
          reloc_operand = operand;
          reloc_exp = t;
          break;
@@ -1934,7 +2103,7 @@ assemble_insn (const struct alpha_opcode *opcode,
              if (reloc == BFD_RELOC_UNUSED)
                reloc = operand->default_reloc;
 
-             assert (reloc_operand == NULL);
+             gas_assert (reloc_operand == NULL);
              reloc_operand = operand;
              reloc_exp = t;
            }
@@ -1963,12 +2132,15 @@ assemble_insn (const struct alpha_opcode *opcode,
        }
 
       /* If this is a real relocation (as opposed to a lituse hint), then
-        the relocation width should match the operand width.  */
-      else if (reloc < BFD_RELOC_UNUSED)
+        the relocation width should match the operand width.
+        Take care of -MDISP in operand table.  */
+      else if (reloc < BFD_RELOC_UNUSED && reloc > 0)
        {
          reloc_howto_type *reloc_howto
-           = bfd_reloc_type_lookup (stdoutput, reloc);
-         if (reloc_howto->bitsize != reloc_operand->bits)
+              = bfd_reloc_type_lookup (stdoutput,
+                                       (bfd_reloc_code_real_type) reloc);
+         if (reloc_operand == NULL
+             || reloc_howto->bitsize != reloc_operand->bits)
            {
              as_bad (_("invalid relocation for field"));
              return;
@@ -1999,14 +2171,21 @@ emit_ir_load (const expressionS *tok,
   long lituse;
   expressionS newtok[3];
   struct alpha_insn insn;
+  const char *symname
+    = tok[1].X_add_symbol ? S_GET_NAME (tok[1].X_add_symbol): "";
+  int symlen = strlen (symname);
 
   if (ntok == 2)
     basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register);
   else
     basereg = tok[2].X_add_number;
 
-  lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg,
-                           &newtok[1]);
+  lituse = load_expression (tok[0].X_add_number, &tok[1],
+                           &basereg, &newtok[1], (const char *) opname);
+
+  if (basereg == alpha_gp_register &&
+      (symlen > 4 && strcmp (&symname [symlen - 4], "..lk") == 0))
+    return;
 
   newtok[0] = tok[0];
   set_tok_preg (newtok[2], basereg);
@@ -2015,7 +2194,7 @@ emit_ir_load (const expressionS *tok,
 
   if (lituse)
     {
-      assert (insn.nfixups < MAX_INSN_FIXUPS);
+      gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
       insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
       insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
@@ -2048,7 +2227,8 @@ emit_loadstore (const expressionS *tok,
       if (alpha_noat_on)
        as_bad (_("macro requires $at register while noat in effect"));
 
-      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1]);
+      lituse = load_expression (AXP_REG_AT, &tok[1],
+                               &basereg, &newtok[1], (const char *) opname);
     }
   else
     {
@@ -2063,7 +2243,7 @@ emit_loadstore (const expressionS *tok,
 
   if (lituse)
     {
-      assert (insn.nfixups < MAX_INSN_FIXUPS);
+      gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
       insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
       insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
@@ -2099,7 +2279,7 @@ emit_ldXu (const expressionS *tok,
        basereg = tok[2].X_add_number;
 
       /* Emit "lda $at, exp".  */
-      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
+      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda");
 
       /* Emit "ldq_u targ, 0($at)".  */
       newtok[0] = tok[0];
@@ -2109,7 +2289,7 @@ emit_ldXu (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2125,7 +2305,7 @@ emit_ldXu (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2251,7 +2431,7 @@ emit_stX (const expressionS *tok,
        basereg = tok[2].X_add_number;
 
       /* Emit "lda $at, exp".  */
-      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL);
+      lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, NULL, "lda");
 
       /* Emit "ldq_u $t9, 0($at)".  */
       set_tok_reg (newtok[0], AXP_REG_T9);
@@ -2261,7 +2441,7 @@ emit_stX (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2278,7 +2458,7 @@ emit_stX (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2294,7 +2474,7 @@ emit_stX (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BYTOFF;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2314,7 +2494,7 @@ emit_stX (const expressionS *tok,
 
       if (lituse)
        {
-         assert (insn.nfixups < MAX_INSN_FIXUPS);
+         gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
          insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_BASE;
          insn.fixups[insn.nfixups].exp.X_op = O_absent;
          insn.nfixups++;
@@ -2661,15 +2841,14 @@ emit_jsrjmp (const expressionS *tok,
   else
     {
       int basereg = alpha_gp_register;
-      lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL);
+      lituse = load_expression (r = AXP_REG_PV, &tok[tokidx],
+                               &basereg, NULL, opname);
     }
 #endif
 
   set_tok_cpreg (newtok[1], r);
 
-#ifdef OBJ_EVAX
-  /* FIXME: Add hint relocs to BFD for evax.  */
-#else
+#ifndef OBJ_EVAX
   if (tokidx < ntok)
     newtok[2] = tok[tokidx];
   else
@@ -2680,13 +2859,51 @@ emit_jsrjmp (const expressionS *tok,
 
   if (lituse)
     {
-      assert (insn.nfixups < MAX_INSN_FIXUPS);
+      gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
       insn.fixups[insn.nfixups].reloc = DUMMY_RELOC_LITUSE_JSR;
       insn.fixups[insn.nfixups].exp.X_op = O_absent;
       insn.nfixups++;
       insn.sequence = lituse;
     }
 
+#ifdef OBJ_EVAX
+  if (alpha_flag_replace
+      && r == AXP_REG_RA
+      && tok[tokidx].X_add_symbol
+      && alpha_linkage_symbol)
+    {
+      /* Create a BOH reloc for 'jsr $27,NAME'.  */
+      const char *symname = S_GET_NAME (tok[tokidx].X_add_symbol);
+      int symlen = strlen (symname);
+      char *ensymname;
+
+      /* Build the entry name as 'NAME..en'.  */
+      ensymname = XNEWVEC (char, symlen + 5);
+      memcpy (ensymname, symname, symlen);
+      memcpy (ensymname + symlen, "..en", 5);
+
+      gas_assert (insn.nfixups < MAX_INSN_FIXUPS);
+      if (insn.nfixups > 0)
+       {
+         memmove (&insn.fixups[1], &insn.fixups[0],
+                  sizeof(struct alpha_fixup) * insn.nfixups);
+       }
+
+      /* The fixup must be the same as the BFD_RELOC_ALPHA_NOP
+        case in load_expression.  See B.4.5.2 of the OpenVMS
+        Linker Utility Manual.  */
+      insn.fixups[0].reloc = BFD_RELOC_ALPHA_BOH;
+      insn.fixups[0].exp.X_op = O_symbol;
+      insn.fixups[0].exp.X_add_symbol = symbol_find_or_make (ensymname);
+      insn.fixups[0].exp.X_add_number = 0;
+      insn.fixups[0].xtrasym = alpha_linkage_symbol;
+      insn.fixups[0].procsym = alpha_evax_proc->symbol;
+      insn.nfixups++;
+      alpha_linkage_symbol = 0;
+      free (ensymname);
+    }
+#endif
+
   emit_insn (&insn);
 }
 
@@ -2728,7 +2945,7 @@ emit_retjcr (const expressionS *tok,
 /* Implement the ldgp macro.  */
 
 static void
-emit_ldgp (const expressionS *tok,
+emit_ldgp (const expressionS *tok ATTRIBUTE_UNUSED,
           int ntok ATTRIBUTE_UNUSED,
           const void * unused ATTRIBUTE_UNUSED)
 {
@@ -3086,7 +3303,7 @@ assemble_tokens (const char *opname,
   const struct alpha_opcode *opcode;
   const struct alpha_macro *macro;
   int cpumatch = 1;
-  bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
+  extended_bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
 
 #ifdef RELOC_OP_P
   /* If a user-specified relocation is present, this is not a macro.  */
@@ -3099,8 +3316,8 @@ assemble_tokens (const char *opname,
 #endif
   if (local_macros_on)
     {
-      macro = ((const struct alpha_macro *)
-              hash_find (alpha_macro_hash, opname));
+      macro = (const struct alpha_macro *) str_hash_find (alpha_macro_hash,
+                                                         opname);
       if (macro)
        {
          found_something = 1;
@@ -3114,7 +3331,8 @@ assemble_tokens (const char *opname,
     }
 
   /* Search opcodes.  */
-  opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname);
+  opcode = (const struct alpha_opcode *) str_hash_find (alpha_opcode_hash,
+                                                       opname);
   if (opcode)
     {
       found_something = 1;
@@ -3147,25 +3365,24 @@ assemble_tokens (const char *opname,
 \f
 #ifdef OBJ_EVAX
 
-/* Add symbol+addend to link pool.
-   Return offset from basesym to entry in link pool.
+/* Add sym+addend to link pool.
+   Return offset from current procedure value (pv) to entry in link pool.
 
    Add new fixup only if offset isn't 16bit.  */
 
-valueT
-add_to_link_pool (symbolS *basesym,
-                 symbolS *sym,
-                 offsetT addend)
+static symbolS *
+add_to_link_pool (symbolS *sym, offsetT addend)
 {
+  symbolS *basesym;
   segT current_section = now_seg;
   int current_subsec = now_subseg;
-  valueT offset;
-  bfd_reloc_code_real_type reloc_type;
   char *p;
   segment_info_type *seginfo = seg_info (alpha_link_section);
   fixS *fixp;
+  symbolS *linksym, *expsym;
+  expressionS e;
 
-  offset = - *symbol_get_obj (basesym);
+  basesym = alpha_evax_proc->symbol;
 
   /* @@ This assumes all entries in a given section will be of the same
      size...  Probably correct, but unwise to rely on.  */
@@ -3174,31 +3391,42 @@ add_to_link_pool (symbolS *basesym,
   if (seginfo->frchainP)
     for (fixp = seginfo->frchainP->fix_root;
         fixp != (fixS *) NULL;
-        fixp = fixp->fx_next, offset += 8)
+        fixp = fixp->fx_next)
       {
-       if (fixp->fx_addsy == sym && fixp->fx_offset == addend)
-         {
-           if (range_signed_16 (offset))
-             {
-               return offset;
-             }
-         }
+       if (fixp->fx_addsy == sym
+           && fixp->fx_offset == (valueT)addend
+           && fixp->tc_fix_data.info
+           && fixp->tc_fix_data.info->sym
+           && symbol_symbolS (fixp->tc_fix_data.info->sym)
+           && (symbol_get_value_expression (fixp->tc_fix_data.info->sym)
+               ->X_op_symbol == basesym))
+         return fixp->tc_fix_data.info->sym;
       }
 
-  /* Not found in 16bit signed range.  */
-
+  /* Not found, add a new entry.  */
   subseg_set (alpha_link_section, 0);
+  linksym = symbol_new (FAKE_LABEL_NAME, now_seg, frag_now, frag_now_fix ());
   p = frag_more (8);
   memset (p, 0, 8);
 
-  fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0,
-          BFD_RELOC_64);
+  /* Create a symbol for 'basesym - linksym' (offset of the added entry).  */
+  e.X_op = O_subtract;
+  e.X_add_symbol = linksym;
+  e.X_op_symbol = basesym;
+  e.X_add_number = 0;
+  expsym = make_expr_symbol (&e);
+
+  /* Create a fixup for the entry.  */
+  fixp = fix_new
+    (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, BFD_RELOC_64);
+  fixp->tc_fix_data.info = get_alpha_reloc_tag (next_sequence_num--);
+  fixp->tc_fix_data.info->sym = expsym;
 
   subseg_set (current_section, current_subsec);
-  seginfo->literal_pool_size += 8;
-  return offset;
-}
 
+  /* Return the symbol.  */
+  return expsym;
+}
 #endif /* OBJ_EVAX */
 \f
 /* Assembler directives.  */
@@ -3208,12 +3436,24 @@ add_to_link_pool (symbolS *basesym,
 
 static void
 s_alpha_text (int i)
-
 {
 #ifdef OBJ_ELF
   obj_elf_text (i);
 #else
   s_text (i);
+#endif
+#ifdef OBJ_EVAX
+  {
+    symbolS * symbolP;
+
+    symbolP = symbol_find (".text");
+    if (symbolP == NULL)
+      {
+       symbolP = symbol_make (".text");
+       S_SET_SEGMENT (symbolP, text_section);
+       symbol_table_insert (symbolP);
+      }
+  }
 #endif
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
@@ -3238,8 +3478,7 @@ s_alpha_data (int i)
 
 #if defined (OBJ_ECOFF) || defined (OBJ_EVAX)
 
-/* Handle the OSF/1 and openVMS .comm pseudo quirks.
-   openVMS constructs a section for every common symbol.  */
+/* Handle the OSF/1 and openVMS .comm pseudo quirks.  */
 
 static void
 s_alpha_comm (int ignore ATTRIBUTE_UNUSED)
@@ -3247,22 +3486,20 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED)
   char *name;
   char c;
   char *p;
-  offsetT temp;
+  offsetT size;
   symbolS *symbolP;
 #ifdef OBJ_EVAX
-  segT current_section = now_seg;
-  int current_subsec = now_subseg;
-  segT new_seg;
+  offsetT temp;
+  int log_align = 0;
 #endif
 
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (&name);
 
   /* Just after name is now '\0'.  */
   p = input_line_pointer;
   *p = c;
 
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
 
   /* Alpha OSF/1 compiler doesn't provide the comma, gcc does.  */
   if (*input_line_pointer == ',')
@@ -3270,35 +3507,17 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED)
       input_line_pointer++;
       SKIP_WHITESPACE ();
     }
-  if ((temp = get_absolute_expression ()) < 0)
+  if ((size = get_absolute_expression ()) < 0)
     {
-      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp);
+      as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size);
       ignore_rest_of_line ();
       return;
     }
 
   *p = 0;
   symbolP = symbol_find_or_make (name);
-
-#ifdef OBJ_EVAX
-  /* Make a section for the common symbol.  */
-  new_seg = subseg_new (xstrdup (name), 0);
-#endif
-
   *p = c;
 
-#ifdef OBJ_EVAX
-  /* Alignment might follow.  */
-  if (*input_line_pointer == ',')
-    {
-      offsetT align;
-
-      input_line_pointer++;
-      align = get_absolute_expression ();
-      bfd_set_section_alignment (stdoutput, new_seg, align);
-    }
-#endif
-
   if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP))
     {
       as_bad (_("Ignoring attempt to re-define symbol"));
@@ -3307,44 +3526,108 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED)
     }
 
 #ifdef OBJ_EVAX
-  if (bfd_section_size (stdoutput, new_seg) > 0)
+  if (*input_line_pointer != ',')
+    temp = 8; /* Default alignment.  */
+  else
     {
-      if (bfd_section_size (stdoutput, new_seg) != temp)
-       as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
-               S_GET_NAME (symbolP),
-               (long) bfd_section_size (stdoutput, new_seg),
-               (long) temp);
+      input_line_pointer++;
+      SKIP_WHITESPACE ();
+      temp = get_absolute_expression ();
     }
-#else
-  if (S_GET_VALUE (symbolP))
+
+  /* ??? Unlike on OSF/1, the alignment factor is not in log units.  */
+  while ((temp >>= 1) != 0)
+    ++log_align;
+
+  if (*input_line_pointer == ',')
     {
-      if (S_GET_VALUE (symbolP) != (valueT) temp)
-       as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
-               S_GET_NAME (symbolP),
-               (long) S_GET_VALUE (symbolP),
-               (long) temp);
+      /* Extended form of the directive
+
+          .comm symbol, size, alignment, section
+
+         where the "common" semantics is transferred to the section.
+         The symbol is effectively an alias for the section name.  */
+
+      segT sec;
+      const char *sec_name;
+      symbolS *sec_symbol;
+      segT current_seg = now_seg;
+      subsegT current_subseg = now_subseg;
+      int cur_size;
+
+      input_line_pointer++;
+      SKIP_WHITESPACE ();
+      sec_name = s_alpha_section_name ();
+      sec_symbol = symbol_find_or_make (sec_name);
+      sec = subseg_new (sec_name, 0);
+      S_SET_SEGMENT (sec_symbol, sec);
+      symbol_get_bfdsym (sec_symbol)->flags |= BSF_SECTION_SYM;
+      bfd_vms_set_section_flags (stdoutput, sec, 0,
+                                EGPS__V_OVR | EGPS__V_GBL | EGPS__V_NOMOD);
+      record_alignment (sec, log_align);
+
+      /* Reuse stab_string_size to store the size of the section.  */
+      cur_size = seg_info (sec)->stabu.stab_string_size;
+      if ((int) size > cur_size)
+       {
+         char *pfrag
+           = frag_var (rs_fill, 1, 1, (relax_substateT)0, NULL,
+                       (valueT)size - (valueT)cur_size, NULL);
+         *pfrag = 0;
+         seg_info (sec)->stabu.stab_string_size = (int)size;
+       }
+
+      S_SET_SEGMENT (symbolP, sec);
+
+      subseg_set (current_seg, current_subseg);
+    }
+  else
+    {
+      /* Regular form of the directive
+
+          .comm symbol, size, alignment
+
+        where the "common" semantics in on the symbol.
+        These symbols are assembled in the .bss section.  */
+
+      char *pfrag;
+      segT current_seg = now_seg;
+      subsegT current_subseg = now_subseg;
+
+      subseg_set (bss_section, 1);
+      frag_align (log_align, 0, 0);
+      record_alignment (bss_section, log_align);
+
+      symbol_set_frag (symbolP, frag_now);
+      pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP,
+                        size, NULL);
+      *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) size)
+        as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."),
+                S_GET_NAME (symbolP),
+                (long) S_GET_VALUE (symbolP),
+                (long) size);
+    }
   else
     {
-#ifdef OBJ_EVAX
-      subseg_set (new_seg, 0);
-      p = frag_more (temp);
-      new_seg->flags |= SEC_IS_COMMON;
-      S_SET_SEGMENT (symbolP, new_seg);
-#else
-      S_SET_VALUE (symbolP, (valueT) temp);
-      S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
+#ifndef OBJ_EVAX
+      S_SET_VALUE (symbolP, (valueT) size);
 #endif
       S_SET_EXTERNAL (symbolP);
     }
 
-#ifdef OBJ_EVAX
-  subseg_set (current_section, current_subsec);
-#endif
-
+#ifndef OBJ_EVAX
   know (symbol_get_frag (symbolP) == &zero_address_frag);
-
+#endif
   demand_empty_rest_of_line ();
 }
 
@@ -3358,9 +3641,7 @@ s_alpha_comm (int ignore ATTRIBUTE_UNUSED)
 static void
 s_alpha_rdata (int ignore ATTRIBUTE_UNUSED)
 {
-  int temp;
-
-  temp = get_absolute_expression ();
+  get_absolute_expression ();
   subseg_new (".rdata", 0);
   demand_empty_rest_of_line ();
   alpha_insn_label = NULL;
@@ -3378,9 +3659,7 @@ s_alpha_rdata (int ignore ATTRIBUTE_UNUSED)
 static void
 s_alpha_sdata (int ignore ATTRIBUTE_UNUSED)
 {
-  int temp;
-
-  temp = get_absolute_expression ();
+  get_absolute_expression ();
   subseg_new (".sdata", 0);
   demand_empty_rest_of_line ();
   alpha_insn_label = NULL;
@@ -3410,6 +3689,8 @@ static struct alpha_elf_frame_data *all_frame_data;
 static struct alpha_elf_frame_data **plast_frame_data = &all_frame_data;
 static struct alpha_elf_frame_data *cur_frame_data;
 
+extern int all_cfi_sections;
+
 /* Handle the .section pseudo-op.  This is like the usual one, but it
    clears alpha_insn_label and restores auto alignment.  */
 
@@ -3431,13 +3712,15 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED)
   else
     {
       char *name, name_end;
-      name = input_line_pointer;
-      name_end = get_symbol_end ();
+
+      name_end = get_symbol_name (&name);
+      /* CFI_EMIT_eh_frame is the default.  */
+      all_cfi_sections = CFI_EMIT_eh_frame;
 
       if (! is_name_beginner (*name))
        {
          as_warn (_(".ent directive has no name"));
-         *input_line_pointer = name_end;
+         (void) restore_line_pointer (name_end);
        }
       else
        {
@@ -3449,7 +3732,7 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED)
          sym = symbol_find_or_make (name);
          symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
 
-         cur_frame_data = calloc (1, sizeof (*cur_frame_data));
+         cur_frame_data = XCNEW (struct alpha_elf_frame_data);
          cur_frame_data->func_sym = sym;
 
          /* Provide sensible defaults.  */
@@ -3462,7 +3745,7 @@ s_alpha_ent (int dummy ATTRIBUTE_UNUSED)
          /* The .ent directive is sometimes followed by a number.  Not sure
             what it really means, but ignore it.  */
          *input_line_pointer = name_end;
-         SKIP_WHITESPACE ();
+         SKIP_WHITESPACE_AFTER_NAME ();
          if (*input_line_pointer == ',')
            {
              input_line_pointer++;
@@ -3483,13 +3766,12 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED)
   else
     {
       char *name, name_end;
-      name = input_line_pointer;
-      name_end = get_symbol_end ();
+
+      name_end = get_symbol_name (&name);
 
       if (! is_name_beginner (*name))
        {
          as_warn (_(".end directive has no name"));
-         *input_line_pointer = name_end;
        }
       else
        {
@@ -3505,7 +3787,7 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED)
          if (sym && cur_frame_data)
            {
              OBJ_SYMFIELD_TYPE *obj = symbol_get_obj (sym);
-             expressionS *exp = xmalloc (sizeof (expressionS));
+             expressionS *exp = XNEW (expressionS);
 
              obj->size = exp;
              exp->X_op = O_subtract;
@@ -3517,9 +3799,9 @@ s_alpha_end (int dummy ATTRIBUTE_UNUSED)
            }
 
          cur_frame_data = NULL;
-
-         *input_line_pointer = name_end;
        }
+
+      (void) restore_line_pointer (name_end);
       demand_empty_rest_of_line ();
     }
 }
@@ -3622,6 +3904,8 @@ s_alpha_prologue (int ignore ATTRIBUTE_UNUSED)
 
   arg = get_absolute_expression ();
   demand_empty_rest_of_line ();
+  alpha_prologue_label = symbol_new (FAKE_LABEL_NAME, now_seg, frag_now,
+                                    frag_now_fix ());
 
   if (ECOFF_DEBUGGING)
     sym = ecoff_get_cur_proc_sym ();
@@ -3671,9 +3955,7 @@ s_alpha_file (int ignore ATTRIBUTE_UNUSED)
       discard_rest_of_line ();
 
       len = input_line_pointer - start;
-      first_file_directive = xmalloc (len + 1);
-      memcpy (first_file_directive, start, len);
-      first_file_directive[len] = '\0';
+      first_file_directive = xmemdup0 (start, len);
 
       input_line_pointer = start;
     }
@@ -3700,8 +3982,8 @@ s_alpha_stab (int n)
   if (alpha_flag_mdebug < 0)
     {
       segT sec = subseg_new (".mdebug", 0);
-      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
-      bfd_set_section_alignment (stdoutput, sec, 3);
+      bfd_set_section_flags (sec, SEC_HAS_CONTENTS | SEC_READONLY);
+      bfd_set_section_alignment (sec, 3);
 
       ecoff_read_begin_hook ();
 
@@ -3722,7 +4004,7 @@ s_alpha_stab (int n)
 static void
 s_alpha_coff_wrapper (int which)
 {
-  static void (* const fns[]) PARAMS ((int)) = {
+  static void (* const fns[]) (int) = {
     ecoff_directive_begin,
     ecoff_directive_bend,
     ecoff_directive_def,
@@ -3733,7 +4015,7 @@ s_alpha_coff_wrapper (int which)
     ecoff_directive_val,
   };
 
-  assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns)));
+  gas_assert (which >= 0 && which < (int) (sizeof (fns)/sizeof (*fns)));
 
   if (ECOFF_DEBUGGING)
     (*fns[which]) (0);
@@ -3759,6 +4041,14 @@ alpha_elf_md_end (void)
   if (bfd_get_section_by_name (stdoutput, ".eh_frame") != NULL)
     return;
 
+  /* ??? In theory we could look for functions for which we have
+     generated unwind info via CFI directives, and those we have not.
+     Those we have not could still get their unwind info from here.
+     For now, do nothing if we've seen any CFI directives.  Note that
+     the above test will not trigger, as we've not emitted data yet.  */
+  if (all_fde_data != NULL)
+    return;
+
   /* Generate .eh_frame data for the unwind directives specified.  */
   for (p = all_frame_data; p ; p = p->next)
     if (p->prologue_sym)
@@ -3766,9 +4056,10 @@ alpha_elf_md_end (void)
        /* Create a temporary symbol at the same location as our
           function symbol.  This prevents problems with globals.  */
        cfi_new_fde (symbol_temp_new (S_GET_SEGMENT (p->func_sym),
-                                     S_GET_VALUE (p->func_sym),
-                                     symbol_get_frag (p->func_sym)));
+                                     symbol_get_frag (p->func_sym),
+                                     S_GET_VALUE (p->func_sym)));
 
+       cfi_set_sections ();
        cfi_set_return_column (p->ra_regno);
        cfi_add_CFA_def_cfa_register (30);
        if (p->fp_regno != 30 || p->mask || p->fmask || p->frame_size)
@@ -3833,19 +4124,20 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED)
   symbolS *sym;
   int other;
 
-  name = input_line_pointer;
-  name_end = get_symbol_end ();
+  name_end = get_symbol_name (&name);
 
   if (! is_name_beginner (*name))
     {
       as_bad (_(".usepv directive has no name"));
-      *input_line_pointer = name_end;
+      (void) restore_line_pointer (name_end);
       ignore_rest_of_line ();
       return;
     }
 
   sym = symbol_find_or_make (name);
-  *input_line_pointer++ = name_end;
+  name_end = restore_line_pointer (name_end);
+  if (! is_end_of_line[(unsigned char) name_end])
+    input_line_pointer++;
 
   if (name_end != ',')
     {
@@ -3855,8 +4147,8 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED)
     }
 
   SKIP_WHITESPACE ();
-  which = input_line_pointer;
-  which_end = get_symbol_end ();
+
+  which_end = get_symbol_name (&which);
 
   if (strcmp (which, "no") == 0)
     other = STO_ALPHA_NOPV;
@@ -3868,7 +4160,7 @@ s_alpha_usepv (int unused ATTRIBUTE_UNUSED)
       other = 0;
     }
 
-  *input_line_pointer = which_end;
+  (void) restore_line_pointer (which_end);
   demand_empty_rest_of_line ();
 
   S_SET_OTHER (sym, other | (S_GET_OTHER (sym) & ~STO_ALPHA_STD_GPLOAD));
@@ -3885,24 +4177,178 @@ alpha_cfi_frame_initial_instructions (void)
 
 #ifdef OBJ_EVAX
 
+/* Get name of section.  */
+static const char *
+s_alpha_section_name (void)
+{
+  char *name;
+
+  SKIP_WHITESPACE ();
+  if (*input_line_pointer == '"')
+    {
+      int dummy;
+
+      name = demand_copy_C_string (&dummy);
+      if (name == NULL)
+       {
+         ignore_rest_of_line ();
+         return NULL;
+       }
+    }
+  else
+    {
+      char *end = input_line_pointer;
+
+      while (0 == strchr ("\n\t,; ", *end))
+       end++;
+      if (end == input_line_pointer)
+       {
+         as_warn (_("missing name"));
+         ignore_rest_of_line ();
+         return NULL;
+       }
+
+      name = xmemdup0 (input_line_pointer, end - input_line_pointer);
+      input_line_pointer = end;
+    }
+  SKIP_WHITESPACE ();
+  return name;
+}
+
+/* Put clear/set flags in one flagword.  The LSBs are flags to be set,
+   the MSBs are the flags to be cleared.  */
+
+#define EGPS__V_NO_SHIFT 16
+#define EGPS__V_MASK    0xffff
+
+/* Parse one VMS section flag.  */
+
+static flagword
+s_alpha_section_word (char *str, size_t len)
+{
+  int no = 0;
+  flagword flag = 0;
+
+  if (len == 5 && strncmp (str, "NO", 2) == 0)
+    {
+      no = 1;
+      str += 2;
+      len -= 2;
+    }
+
+  if (len == 3)
+    {
+      if (strncmp (str, "PIC", 3) == 0)
+       flag = EGPS__V_PIC;
+      else if (strncmp (str, "LIB", 3) == 0)
+       flag = EGPS__V_LIB;
+      else if (strncmp (str, "OVR", 3) == 0)
+       flag = EGPS__V_OVR;
+      else if (strncmp (str, "REL", 3) == 0)
+       flag = EGPS__V_REL;
+      else if (strncmp (str, "GBL", 3) == 0)
+       flag = EGPS__V_GBL;
+      else if (strncmp (str, "SHR", 3) == 0)
+       flag = EGPS__V_SHR;
+      else if (strncmp (str, "EXE", 3) == 0)
+       flag = EGPS__V_EXE;
+      else if (strncmp (str, "WRT", 3) == 0)
+       flag = EGPS__V_WRT;
+      else if (strncmp (str, "VEC", 3) == 0)
+       flag = EGPS__V_VEC;
+      else if (strncmp (str, "MOD", 3) == 0)
+       {
+         flag = no ? EGPS__V_NOMOD : EGPS__V_NOMOD << EGPS__V_NO_SHIFT;
+         no = 0;
+       }
+      else if (strncmp (str, "COM", 3) == 0)
+       flag = EGPS__V_COM;
+    }
+
+  if (flag == 0)
+    {
+      char c = str[len];
+      str[len] = 0;
+      as_warn (_("unknown section attribute %s"), str);
+      str[len] = c;
+      return 0;
+    }
+
+  if (no)
+    return flag << EGPS__V_NO_SHIFT;
+  else
+    return flag;
+}
+
 /* Handle the section specific pseudo-op.  */
 
+#define EVAX_SECTION_COUNT 5
+
+static const char *section_name[EVAX_SECTION_COUNT + 1] =
+  { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" };
+
 static void
 s_alpha_section (int secid)
 {
-  int temp;
-#define EVAX_SECTION_COUNT 5
-  static char *section_name[EVAX_SECTION_COUNT + 1] =
-    { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" };
+  const char *name;
+  char *beg;
+  segT sec;
+  flagword vms_flags = 0;
+  symbolS *symbol;
 
-  if ((secid <= 0) || (secid > EVAX_SECTION_COUNT))
+  if (secid == 0)
     {
-      as_fatal (_("Unknown section directive"));
-      demand_empty_rest_of_line ();
-      return;
+      name = s_alpha_section_name ();
+      if (name == NULL)
+        return;
+      sec = subseg_new (name, 0);
+      if (*input_line_pointer == ',')
+        {
+          /* Skip the comma.  */
+          ++input_line_pointer;
+          SKIP_WHITESPACE ();
+
+         do
+           {
+             char c;
+
+             SKIP_WHITESPACE ();
+             c = get_symbol_name (&beg);
+             *input_line_pointer = c;
+
+             vms_flags |= s_alpha_section_word (beg, input_line_pointer - beg);
+
+             SKIP_WHITESPACE_AFTER_NAME ();
+           }
+         while (*input_line_pointer++ == ',');
+
+         --input_line_pointer;
+        }
+
+       symbol = symbol_find_or_make (name);
+       S_SET_SEGMENT (symbol, sec);
+       symbol_get_bfdsym (symbol)->flags |= BSF_SECTION_SYM;
+        bfd_vms_set_section_flags
+          (stdoutput, sec,
+           (vms_flags >> EGPS__V_NO_SHIFT) & EGPS__V_MASK,
+           vms_flags & EGPS__V_MASK);
+    }
+  else
+    {
+      get_absolute_expression ();
+      subseg_new (section_name[secid], 0);
     }
-  temp = get_absolute_expression ();
-  subseg_new (section_name[secid], 0);
+
+  demand_empty_rest_of_line ();
+  alpha_insn_label = NULL;
+  alpha_auto_align_on = 1;
+  alpha_current_align = 0;
+}
+
+static void
+s_alpha_literals (int ignore ATTRIBUTE_UNUSED)
+{
+  subseg_new (".literals", 0);
   demand_empty_rest_of_line ();
   alpha_insn_label = NULL;
   alpha_auto_align_on = 1;
@@ -3917,16 +4363,23 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED)
   symbolS *symbol;
   expressionS symexpr;
 
-  alpha_evax_proc.pdsckind = 0;
-  alpha_evax_proc.framereg = -1;
-  alpha_evax_proc.framesize = 0;
-  alpha_evax_proc.rsa_offset = 0;
-  alpha_evax_proc.ra_save = AXP_REG_RA;
-  alpha_evax_proc.fp_save = -1;
-  alpha_evax_proc.imask = 0;
-  alpha_evax_proc.fmask = 0;
-  alpha_evax_proc.prologue = 0;
-  alpha_evax_proc.type = 0;
+  if (alpha_evax_proc != NULL)
+    as_bad (_("previous .ent not closed by a .end"));
+
+  alpha_evax_proc = &alpha_evax_proc_data;
+
+  alpha_evax_proc->pdsckind = 0;
+  alpha_evax_proc->framereg = -1;
+  alpha_evax_proc->framesize = 0;
+  alpha_evax_proc->rsa_offset = 0;
+  alpha_evax_proc->ra_save = AXP_REG_RA;
+  alpha_evax_proc->fp_save = -1;
+  alpha_evax_proc->imask = 0;
+  alpha_evax_proc->fmask = 0;
+  alpha_evax_proc->prologue = 0;
+  alpha_evax_proc->type = 0;
+  alpha_evax_proc->handler = 0;
+  alpha_evax_proc->handler_data = 0;
 
   expression (&symexpr);
 
@@ -3939,7 +4392,37 @@ s_alpha_ent (int ignore ATTRIBUTE_UNUSED)
 
   symbol = make_expr_symbol (&symexpr);
   symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
-  alpha_evax_proc.symbol = symbol;
+  alpha_evax_proc->symbol = symbol;
+
+  demand_empty_rest_of_line ();
+}
+
+static void
+s_alpha_handler (int is_data)
+{
+  if (is_data)
+    alpha_evax_proc->handler_data = get_absolute_expression ();
+  else
+    {
+      char *name, name_end;
+
+      name_end = get_symbol_name (&name);
+
+      if (! is_name_beginner (*name))
+       {
+         as_warn (_(".handler directive has no name"));
+       }
+      else
+       {
+         symbolS *sym;
+
+         sym = symbol_find_or_make (name);
+         symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
+         alpha_evax_proc->handler = sym;
+       }
+
+      (void) restore_line_pointer (name_end);
+    }
 
   demand_empty_rest_of_line ();
 }
@@ -3950,8 +4433,9 @@ static void
 s_alpha_frame (int ignore ATTRIBUTE_UNUSED)
 {
   long val;
+  int ra;
 
-  alpha_evax_proc.framereg = tc_get_register (1);
+  alpha_evax_proc->framereg = tc_get_register (1);
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer++ != ','
@@ -3963,9 +4447,12 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED)
       return;
     }
 
-  alpha_evax_proc.framesize = val;
+  alpha_evax_proc->framesize = val;
+
+  ra = tc_get_register (1);
+  if (ra != AXP_REG_RA)
+    as_warn (_("Bad RA (%d) register for .frame"), ra);
 
-  (void) tc_get_register (1);
   SKIP_WHITESPACE ();
   if (*input_line_pointer++ != ',')
     {
@@ -3974,51 +4461,77 @@ s_alpha_frame (int ignore ATTRIBUTE_UNUSED)
       demand_empty_rest_of_line ();
       return;
     }
-  alpha_evax_proc.rsa_offset = get_absolute_expression ();
+  alpha_evax_proc->rsa_offset = get_absolute_expression ();
+}
+
+/* Parse .prologue.  */
+
+static void
+s_alpha_prologue (int ignore ATTRIBUTE_UNUSED)
+{
+  demand_empty_rest_of_line ();
+  alpha_prologue_label = symbol_new (FAKE_LABEL_NAME, now_seg, frag_now,
+                                    frag_now_fix ());
 }
 
+/* Parse .pdesc <entry_name>,{null|stack|reg}
+   Insert a procedure descriptor.  */
+
 static void
 s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   char name_end;
-  long val;
-  register char *p;
+  char *p;
   expressionS exp;
   symbolS *entry_sym;
+  const char *entry_sym_name;
+  const char *pdesc_sym_name;
   fixS *fixp;
-  segment_info_type *seginfo = seg_info (alpha_link_section);
+  size_t len;
 
   if (now_seg != alpha_link_section)
     {
       as_bad (_(".pdesc directive not in link (.link) section"));
-      demand_empty_rest_of_line ();
       return;
     }
 
-  if ((alpha_evax_proc.symbol == 0)
-      || (!S_IS_DEFINED (alpha_evax_proc.symbol)))
+  expression (&exp);
+  if (exp.X_op != O_symbol)
     {
-      as_fatal (_(".pdesc has no matching .ent"));
-      demand_empty_rest_of_line ();
+      as_bad (_(".pdesc directive has no entry symbol"));
       return;
     }
 
-  *symbol_get_obj (alpha_evax_proc.symbol) =
-    (valueT) seginfo->literal_pool_size;
+  entry_sym = make_expr_symbol (&exp);
+  entry_sym_name = S_GET_NAME (entry_sym);
 
-  expression (&exp);
-  if (exp.X_op != O_symbol)
+  /* Strip "..en".  */
+  len = strlen (entry_sym_name);
+  if (len < 4 || strcmp (entry_sym_name + len - 4, "..en") != 0)
     {
-      as_warn (_(".pdesc directive has no entry symbol"));
-      demand_empty_rest_of_line ();
+      as_bad (_(".pdesc has a bad entry symbol"));
       return;
     }
+  len -= 4;
+  pdesc_sym_name = S_GET_NAME (alpha_evax_proc->symbol);
 
-  entry_sym = make_expr_symbol (&exp);
-  /* Save bfd symbol of proc desc in function symbol.  */
-  symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p
-    = symbol_get_bfdsym (entry_sym);
+  if (!alpha_evax_proc
+      || !S_IS_DEFINED (alpha_evax_proc->symbol)
+      || strlen (pdesc_sym_name) != len
+      || memcmp (entry_sym_name, pdesc_sym_name, len) != 0)
+    {
+      as_fatal (_(".pdesc doesn't match with last .ent"));
+      return;
+    }
+
+  /* Define pdesc symbol.  */
+  symbol_set_value_now (alpha_evax_proc->symbol);
+
+  /* Save bfd symbol of proc entry in function symbol.  */
+  ((struct evax_private_udata_struct *)
+     symbol_get_bfdsym (alpha_evax_proc->symbol)->udata.p)->enbsym
+       = symbol_get_bfdsym (entry_sym);
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer++ != ',')
@@ -4029,26 +4542,26 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED)
     }
 
   SKIP_WHITESPACE ();
-  name = input_line_pointer;
-  name_end = get_symbol_end ();
+  name_end = get_symbol_name (&name);
 
   if (strncmp (name, "stack", 5) == 0)
-    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK;
+    alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_STACK;
 
   else if (strncmp (name, "reg", 3) == 0)
-    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER;
+    alpha_evax_proc->pdsckind = PDSC_S_K_KIND_FP_REGISTER;
 
   else if (strncmp (name, "null", 4) == 0)
-    alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL;
+    alpha_evax_proc->pdsckind = PDSC_S_K_KIND_NULL;
 
   else
     {
+      (void) restore_line_pointer (name_end);
       as_fatal (_("unknown procedure kind"));
       demand_empty_rest_of_line ();
       return;
     }
 
-  *input_line_pointer = name_end;
+  (void) restore_line_pointer (name_end);
   demand_empty_rest_of_line ();
 
 #ifdef md_flush_pending_output
@@ -4059,67 +4572,73 @@ s_alpha_pdesc (int ignore ATTRIBUTE_UNUSED)
   p = frag_more (16);
   fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
   fixp->fx_done = 1;
-  seginfo->literal_pool_size += 16;
 
-  *p = alpha_evax_proc.pdsckind
-    | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0);
+  *p = alpha_evax_proc->pdsckind
+    | ((alpha_evax_proc->framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0)
+    | ((alpha_evax_proc->handler) ? PDSC_S_M_HANDLER_VALID : 0)
+    | ((alpha_evax_proc->handler_data) ? PDSC_S_M_HANDLER_DATA_VALID : 0);
   *(p + 1) = PDSC_S_M_NATIVE | PDSC_S_M_NO_JACKET;
 
-  switch (alpha_evax_proc.pdsckind)
+  switch (alpha_evax_proc->pdsckind)
     {
     case PDSC_S_K_KIND_NULL:
       *(p + 2) = 0;
       *(p + 3) = 0;
       break;
     case PDSC_S_K_KIND_FP_REGISTER:
-      *(p + 2) = alpha_evax_proc.fp_save;
-      *(p + 3) = alpha_evax_proc.ra_save;
+      *(p + 2) = alpha_evax_proc->fp_save;
+      *(p + 3) = alpha_evax_proc->ra_save;
       break;
     case PDSC_S_K_KIND_FP_STACK:
-      md_number_to_chars (p + 2, (valueT) alpha_evax_proc.rsa_offset, 2);
+      md_number_to_chars (p + 2, (valueT) alpha_evax_proc->rsa_offset, 2);
       break;
     default:           /* impossible */
       break;
     }
 
   *(p + 4) = 0;
-  *(p + 5) = alpha_evax_proc.type & 0x0f;
+  *(p + 5) = alpha_evax_proc->type & 0x0f;
 
   /* Signature offset.  */
   md_number_to_chars (p + 6, (valueT) 0, 2);
 
-  fix_new_exp (frag_now, p - frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64);
+  fix_new_exp (frag_now, p - frag_now->fr_literal + 8,
+               8, &exp, 0, BFD_RELOC_64);
 
-  if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL)
+  if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_NULL)
     return;
 
-  /* Add dummy fix to make add_to_link_pool work.  */
-  p = frag_more (8);
-  fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
-  fixp->fx_done = 1;
-  seginfo->literal_pool_size += 8;
-
   /* pdesc+16: Size.  */
-  md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4);
-
+  p = frag_more (6);
+  md_number_to_chars (p, (valueT) alpha_evax_proc->framesize, 4);
   md_number_to_chars (p + 4, (valueT) 0, 2);
 
   /* Entry length.  */
-  md_number_to_chars (p + 6, alpha_evax_proc.prologue, 2);
+  exp.X_op = O_subtract;
+  exp.X_add_symbol = alpha_prologue_label;
+  exp.X_op_symbol = entry_sym;
+  emit_expr (&exp, 2);
 
-  if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER)
+  if (alpha_evax_proc->pdsckind == PDSC_S_K_KIND_FP_REGISTER)
     return;
 
-  /* Add dummy fix to make add_to_link_pool work.  */
+  /* pdesc+24: register masks.  */
   p = frag_more (8);
-  fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0);
-  fixp->fx_done = 1;
-  seginfo->literal_pool_size += 8;
+  md_number_to_chars (p, alpha_evax_proc->imask, 4);
+  md_number_to_chars (p + 4, alpha_evax_proc->fmask, 4);
 
-  /* pdesc+24: register masks.  */
+  if (alpha_evax_proc->handler)
+    {
+      p = frag_more (8);
+      fixp = fix_new (frag_now, p - frag_now->fr_literal, 8,
+                     alpha_evax_proc->handler, 0, 0, BFD_RELOC_64);
+    }
 
-  md_number_to_chars (p, alpha_evax_proc.imask, 4);
-  md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4);
+  if (alpha_evax_proc->handler_data)
+    {
+      p = frag_more (8);
+      md_number_to_chars (p, alpha_evax_proc->handler_data, 8);
+    }
 }
 
 /* Support for crash debug on vms.  */
@@ -4129,7 +4648,6 @@ s_alpha_name (int ignore ATTRIBUTE_UNUSED)
 {
   char *p;
   expressionS exp;
-  segment_info_type *seginfo = seg_info (alpha_link_section);
 
   if (now_seg != alpha_link_section)
     {
@@ -4154,16 +4672,19 @@ s_alpha_name (int ignore ATTRIBUTE_UNUSED)
 
   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);
 }
 
+/* Parse .linkage <symbol>.
+   Create a linkage pair relocation.  */
+
 static void
 s_alpha_linkage (int ignore ATTRIBUTE_UNUSED)
 {
   expressionS exp;
   char *p;
+  fixS *fixp;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -4176,14 +4697,37 @@ s_alpha_linkage (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
+      struct alpha_linkage_fixups *linkage_fixup;
+
       p = frag_more (LKP_S_K_SIZE);
       memset (p, 0, LKP_S_K_SIZE);
-      fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\
-                  BFD_RELOC_ALPHA_LINKAGE);
+      fixp = fix_new_exp
+       (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,
+        BFD_RELOC_ALPHA_LINKAGE);
+
+      if (alpha_insn_label == NULL)
+       alpha_insn_label = symbol_new (FAKE_LABEL_NAME, now_seg, frag_now,
+                                      frag_now_fix ());
+
+      /* Create a linkage element.  */
+      linkage_fixup = XNEW (struct alpha_linkage_fixups);
+      linkage_fixup->fixp = fixp;
+      linkage_fixup->next = NULL;
+      linkage_fixup->label = alpha_insn_label;
+
+      /* Append it to the list.  */
+      if (alpha_linkage_fixup_root == NULL)
+        alpha_linkage_fixup_root = linkage_fixup;
+      else
+        alpha_linkage_fixup_tail->next = linkage_fixup;
+      alpha_linkage_fixup_tail = linkage_fixup;
     }
   demand_empty_rest_of_line ();
 }
 
+/* Parse .code_address <symbol>.
+   Create a code address relocation.  */
+
 static void
 s_alpha_code_address (int ignore ATTRIBUTE_UNUSED)
 {
@@ -4210,8 +4754,7 @@ s_alpha_code_address (int ignore ATTRIBUTE_UNUSED)
 static void
 s_alpha_fp_save (int ignore ATTRIBUTE_UNUSED)
 {
-
-  alpha_evax_proc.fp_save = tc_get_register (1);
+  alpha_evax_proc->fp_save = tc_get_register (1);
 
   demand_empty_rest_of_line ();
 }
@@ -4228,7 +4771,7 @@ s_alpha_mask (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
-      alpha_evax_proc.imask = val;
+      alpha_evax_proc->imask = val;
       (void) get_absolute_expression ();
     }
   demand_empty_rest_of_line ();
@@ -4246,7 +4789,7 @@ s_alpha_fmask (int ignore ATTRIBUTE_UNUSED)
     }
   else
     {
-      alpha_evax_proc.fmask = val;
+      alpha_evax_proc->fmask = val;
       (void) get_absolute_expression ();
     }
   demand_empty_rest_of_line ();
@@ -4255,12 +4798,13 @@ s_alpha_fmask (int ignore ATTRIBUTE_UNUSED)
 static void
 s_alpha_end (int ignore ATTRIBUTE_UNUSED)
 {
+  char *name;
   char c;
 
-  c = get_symbol_end ();
-  *input_line_pointer = c;
+  c = get_symbol_name (&name);
+  (void) restore_line_pointer (c);
   demand_empty_rest_of_line ();
-  alpha_evax_proc.symbol = 0;
+  alpha_evax_proc = NULL;
 }
 
 static void
@@ -4336,7 +4880,7 @@ s_alpha_gprel32 (int ignore ATTRIBUTE_UNUSED)
 }
 
 /* Handle floating point allocation pseudo-ops.  This is like the
-   generic vresion, but it makes sure the current label, if any, is
+   generic version, but it makes sure the current label, if any, is
    correctly aligned.  */
 
 static void
@@ -4389,12 +4933,11 @@ s_alpha_proc (int is_static ATTRIBUTE_UNUSED)
 
   /* Takes ".proc name,nargs".  */
   SKIP_WHITESPACE ();
-  name = input_line_pointer;
-  c = get_symbol_end ();
+  c = get_symbol_name (&name);
   p = input_line_pointer;
   symbolP = symbol_find_or_make (name);
   *p = c;
-  SKIP_WHITESPACE ();
+  SKIP_WHITESPACE_AFTER_NAME ();
   if (*input_line_pointer != ',')
     {
       *p = 0;
@@ -4409,6 +4952,7 @@ s_alpha_proc (int is_static ATTRIBUTE_UNUSED)
       temp = get_absolute_expression ();
     }
   /*  *symbol_get_obj (symbolP) = (signed char) temp; */
+  (void) symbolP;
   as_warn (_("unhandled: .proc %s,%d"), name, temp);
   demand_empty_rest_of_line ();
 }
@@ -4423,9 +4967,8 @@ s_alpha_set (int x ATTRIBUTE_UNUSED)
   int yesno = 1;
 
   SKIP_WHITESPACE ();
-  name = input_line_pointer;
-  ch = get_symbol_end ();
 
+  ch = get_symbol_name (&name);
   s = name;
   if (s[0] == 'n' && s[1] == 'o')
     {
@@ -4445,7 +4988,7 @@ s_alpha_set (int x ATTRIBUTE_UNUSED)
   else
     as_warn (_("Tried to .set unrecognized mode `%s'"), name);
 
-  *input_line_pointer = ch;
+  (void) restore_line_pointer (ch);
   demand_empty_rest_of_line ();
 }
 
@@ -4484,7 +5027,7 @@ s_alpha_align (int ignore ATTRIBUTE_UNUSED)
 {
   int align;
   char fill, *pfill;
-  long max_alignment = 15;
+  long max_alignment = 16;
 
   align = get_absolute_expression ();
   if (align > max_alignment)
@@ -4510,12 +5053,13 @@ s_alpha_align (int ignore ATTRIBUTE_UNUSED)
   if (align != 0)
     {
       alpha_auto_align_on = 1;
-      alpha_align (align, pfill, alpha_insn_label, 1);
+      alpha_align (align, pfill, NULL, 1);
     }
   else
     {
       alpha_auto_align_on = 0;
     }
+  alpha_insn_label = NULL;
 
   demand_empty_rest_of_line ();
 }
@@ -4527,7 +5071,7 @@ s_alpha_stringer (int terminate)
 {
   alpha_current_align = 0;
   alpha_insn_label = NULL;
-  stringer (terminate);
+  stringer (8 + terminate);
 }
 
 /* Hook the normal space processing to reset known alignment.  */
@@ -4579,8 +5123,8 @@ s_alpha_arch (int ignored ATTRIBUTE_UNUSED)
   const struct cpu_type *p;
 
   SKIP_WHITESPACE ();
-  name = input_line_pointer;
-  ch = get_symbol_end ();
+
+  ch = get_symbol_name (&name);
 
   for (p = cpu_types; p->name; ++p)
     if (strcmp (name, p->name) == 0)
@@ -4588,10 +5132,10 @@ s_alpha_arch (int ignored ATTRIBUTE_UNUSED)
        alpha_target_name = p->name, alpha_target = p->flags;
        goto found;
       }
-  as_warn ("Unknown CPU identifier `%s'", name);
+  as_warn (_("Unknown CPU identifier `%s'"), name);
 
-found:
-  *input_line_pointer = ch;
+ found:
+  (void) restore_line_pointer (ch);
   demand_empty_rest_of_line ();
 }
 \f
@@ -4611,12 +5155,12 @@ alpha_print_token (FILE *f, const expressionS *exp)
       {
        expressionS nexp = *exp;
        nexp.X_op = O_register;
-       print_expr (f, &nexp);
+       print_expr_1 (f, &nexp);
       }
       putc (')', f);
       break;
     default:
-      print_expr (f, exp);
+      print_expr_1 (f, exp);
       break;
     }
 }
@@ -4642,22 +5186,26 @@ const pseudo_typeS md_pseudo_table[] =
   {"sect.s", s_alpha_section, 0},
 #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},
-  { "end", s_alpha_end, 0},
-  { "file", s_alpha_file, 0},
-  { "rdata", s_alpha_section, 1},
-  { "comm", s_alpha_comm, 0},
-  { "link", s_alpha_section, 3},
-  { "ctors", s_alpha_section, 4},
-  { "dtors", s_alpha_section, 5},
+  {"section", s_alpha_section, 0},
+  {"literals", s_alpha_literals, 0},
+  {"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},
+  {"end", s_alpha_end, 0},
+  {"file", s_alpha_file, 0},
+  {"rdata", s_alpha_section, 1},
+  {"comm", s_alpha_comm, 0},
+  {"link", s_alpha_section, 3},
+  {"ctors", s_alpha_section, 4},
+  {"dtors", s_alpha_section, 5},
+  {"handler", s_alpha_handler, 0},
+  {"handler_data", s_alpha_handler, 1},
 #endif
 #ifdef OBJ_ELF
   /* Frame related pseudos.  */
@@ -4681,8 +5229,12 @@ const pseudo_typeS md_pseudo_table[] =
   {"scl", s_alpha_coff_wrapper, 5},
   {"tag", s_alpha_coff_wrapper, 6},
   {"val", s_alpha_coff_wrapper, 7},
+#else
+#ifdef OBJ_EVAX
+  {"prologue", s_alpha_prologue, 0},
 #else
   {"prologue", s_ignore, 0},
+#endif
 #endif
   {"gprel32", s_alpha_gprel32, 0},
   {"t_floating", s_alpha_float_cons, 'd'},
@@ -4738,7 +5290,6 @@ const pseudo_typeS md_pseudo_table[] =
 
 /* @@@ GP selection voodoo.  All of this seems overly complicated and
    unnecessary; which is the primary reason it's for ECOFF only.  */
-static inline void maybe_set_gp PARAMS ((asection *));
 
 static inline void
 maybe_set_gp (asection *sec)
@@ -4747,7 +5298,7 @@ maybe_set_gp (asection *sec)
 
   if (!sec)
     return;
-  vma = bfd_get_section_vma (foo, sec);
+  vma = bfd_section_vma (sec);
   if (vma && vma < alpha_gp_value)
     alpha_gp_value = vma;
 }
@@ -4755,7 +5306,7 @@ maybe_set_gp (asection *sec)
 static void
 select_gp_value (void)
 {
-  assert (alpha_gp_value == 0);
+  gas_assert (alpha_gp_value == 0);
 
   /* Get minus-one in whatever width...  */
   alpha_gp_value = 0;
@@ -4780,20 +5331,20 @@ select_gp_value (void)
 #ifdef OBJ_ELF
 /* Map 's' to SHF_ALPHA_GPREL.  */
 
-int
-alpha_elf_section_letter (int letter, char **ptr_msg)
+bfd_vma
+alpha_elf_section_letter (int letter, const char **ptr_msg)
 {
   if (letter == 's')
     return SHF_ALPHA_GPREL;
 
-  *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
+  *ptr_msg = _("bad .section directive: want a,s,w,x,M,S,G,T in string");
   return -1;
 }
 
 /* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA.  */
 
 flagword
-alpha_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
+alpha_elf_section_flags (flagword flags, bfd_vma attr, int type ATTRIBUTE_UNUSED)
 {
   if (attr & SHF_ALPHA_GPREL)
     flags |= SEC_SMALL_DATA;
@@ -4807,8 +5358,8 @@ alpha_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
 void
 alpha_handle_align (fragS *fragp)
 {
-  static char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f };
-  static char const nopunop[8] =
+  static unsigned char const unop[4] = { 0x00, 0x00, 0xfe, 0x2f };
+  static unsigned char const nopunop[8] =
   {
     0x1f, 0x04, 0xff, 0x47,
     0x00, 0x00, 0xfe, 0x2f
@@ -4862,21 +5413,19 @@ md_begin (void)
     expressionS e;
 
     e.X_op = O_max;
-    assert (e.X_op == O_max);
+    gas_assert (e.X_op == O_max);
   }
 
   /* Create the opcode hash table.  */
-  alpha_opcode_hash = hash_new ();
+  alpha_opcode_hash = str_htab_create ();
 
   for (i = 0; i < alpha_num_opcodes;)
     {
-      const char *name, *retval, *slash;
+      const char *name, *slash;
 
       name = alpha_opcodes[i].name;
-      retval = hash_insert (alpha_opcode_hash, name, (void *) &alpha_opcodes[i]);
-      if (retval)
-       as_fatal (_("internal error: can't hash opcode `%s': %s"),
-                 name, retval);
+      if (str_hash_insert (alpha_opcode_hash, name, &alpha_opcodes[i], 0))
+       as_fatal (_("duplicate %s"), name);
 
       /* Some opcodes include modifiers of various sorts with a "/mod"
         syntax, like the architecture manual suggests.  However, for
@@ -4885,12 +5434,12 @@ md_begin (void)
 
       if ((slash = strchr (name, '/')) != NULL)
        {
-         char *p = xmalloc (strlen (name));
+         char *p = XNEWVEC (char, strlen (name));
 
          memcpy (p, name, slash - name);
          strcpy (p + (slash - name), slash + 1);
 
-         (void) hash_insert (alpha_opcode_hash, p, (void *) &alpha_opcodes[i]);
+         (void) str_hash_insert (alpha_opcode_hash, p, &alpha_opcodes[i], 0);
          /* Ignore failures -- the opcode table does duplicate some
             variants in different forms, like "hw_stq" and "hw_st/q".  */
        }
@@ -4902,17 +5451,15 @@ md_begin (void)
     }
 
   /* Create the macro hash table.  */
-  alpha_macro_hash = hash_new ();
+  alpha_macro_hash = str_htab_create ();
 
   for (i = 0; i < alpha_num_macros;)
     {
-      const char *name, *retval;
+      const char *name;
 
       name = alpha_macros[i].name;
-      retval = hash_insert (alpha_macro_hash, name, (void *) &alpha_macros[i]);
-      if (retval)
-       as_fatal (_("internal error: can't hash macro `%s': %s"),
-                 name, retval);
+      if (str_hash_insert (alpha_macro_hash, name, &alpha_macros[i], 0))
+       as_fatal (_("duplicate %s"), name);
 
       while (++i < alpha_num_macros
             && (alpha_macros[i].name == name
@@ -4926,8 +5473,8 @@ md_begin (void)
       char name[4];
 
       sprintf (name, "$%d", i);
-      alpha_register_table[i] = symbol_create (name, reg_section, i,
-                                              &zero_address_frag);
+      alpha_register_table[i] = symbol_create (name, reg_section,
+                                              &zero_address_frag, i);
     }
 
   for (; i < 64; ++i)
@@ -4935,8 +5482,8 @@ md_begin (void)
       char name[5];
 
       sprintf (name, "$f%d", i - 32);
-      alpha_register_table[i] = symbol_create (name, reg_section, i,
-                                              &zero_address_frag);
+      alpha_register_table[i] = symbol_create (name, reg_section,
+                                              &zero_address_frag, i);
     }
 
   /* Create the special symbols and sections we'll be using.  */
@@ -4949,8 +5496,8 @@ md_begin (void)
 
   /* For handling the GP, create a symbol that won't be output in the
      symbol table.  We'll edit it out of relocs later.  */
-  alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000,
-                                  &zero_address_frag);
+  alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section,
+                                  &zero_address_frag, 0x8000);
 #endif
 
 #ifdef OBJ_EVAX
@@ -4961,13 +5508,13 @@ md_begin (void)
   if (ECOFF_DEBUGGING)
     {
       segT sec = subseg_new (".mdebug", (subsegT) 0);
-      bfd_set_section_flags (stdoutput, sec, SEC_HAS_CONTENTS | SEC_READONLY);
-      bfd_set_section_alignment (stdoutput, sec, 3);
+      bfd_set_section_flags (sec, SEC_HAS_CONTENTS | SEC_READONLY);
+      bfd_set_section_alignment (sec, 3);
     }
 #endif
 
   /* Create literal lookup hash table.  */
-  alpha_literal_hash = hash_new ();
+  alpha_literal_hash = str_htab_create ();
 
   subseg_set (text_section, 0);
 }
@@ -5009,7 +5556,7 @@ md_assemble (char *str)
 valueT
 md_section_align (segT seg, valueT size)
 {
-  int align = bfd_get_section_alignment (stdoutput, seg);
+  int align = bfd_section_alignment (seg);
   valueT mask = ((valueT) 1 << align) - 1;
 
   return (size + mask) & ~mask;
@@ -5020,70 +5567,31 @@ md_section_align (segT seg, valueT size)
    of LITTLENUMS emitted is stored in *SIZEP.  An error message is
    returned, or NULL on OK.  */
 
-/* Equal to MAX_PRECISION in atof-ieee.c.  */
-#define MAX_LITTLENUMS 6
-
-extern char *vax_md_atof (int, char *, int *);
-
-char *
+const char *
 md_atof (int type, char *litP, int *sizeP)
 {
-  int prec;
-  LITTLENUM_TYPE words[MAX_LITTLENUMS];
-  LITTLENUM_TYPE *wordP;
-  char *t;
+  extern const char *vax_md_atof (int, char *, int *);
 
   switch (type)
     {
       /* VAX floats.  */
     case 'G':
-      /* VAX md_atof doesn't like "G" for some reason.  */
+      /* vax_md_atof() doesn't like "G" for some reason.  */
       type = 'g';
+      /* Fall through.  */
     case 'F':
     case 'D':
       return vax_md_atof (type, litP, sizeP);
 
-      /* IEEE floats.  */
-    case 'f':
-      prec = 2;
-      break;
-
-    case 'd':
-      prec = 4;
-      break;
-
-    case 'x':
-    case 'X':
-      prec = 6;
-      break;
-
-    case 'p':
-    case 'P':
-      prec = 6;
-      break;
-
     default:
-      *sizeP = 0;
-      return _("Bad call to MD_ATOF()");
+      return ieee_md_atof (type, litP, sizeP, FALSE);
     }
-  t = atof_ieee (input_line_pointer, type, words);
-  if (t)
-    input_line_pointer = t;
-  *sizeP = prec * sizeof (LITTLENUM_TYPE);
-
-  for (wordP = words + prec - 1; prec--;)
-    {
-      md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE));
-      litP += sizeof (LITTLENUM_TYPE);
-    }
-
-  return 0;
 }
 
 /* Take care of the target-specific command-line options.  */
 
 int
-md_parse_option (int c, char *arg)
+md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
@@ -5129,6 +5637,14 @@ md_parse_option (int c, char *arg)
 
     case 'h':                  /* For gnu-c/vax compatibility.  */
       break;
+
+    case OPTION_REPLACE:
+      alpha_flag_replace = 1;
+      break;
+
+    case OPTION_NOREPLACE:
+      alpha_flag_replace = 0;
+      break;
 #endif
 
     case OPTION_RELAX:
@@ -5168,8 +5684,9 @@ Alpha options:\n\
 #ifdef OBJ_EVAX
   fputs (_("\
 VMS options:\n\
--+                     hash encode (don't truncate) names longer than 64 characters\n\
--H                     show new symbol after hash truncation\n"),
+-+                     encode (don't truncate) names longer than 64 characters\n\
+-H                     show new symbol after hash truncation\n\
+-replace/-noreplace    enable or disable the optimization of procedure calls\n"),
        stream);
 #endif
 }
@@ -5246,6 +5763,12 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
       md_number_to_chars (fixpos, value, 2);
       break;
 
+    case BFD_RELOC_8:
+      if (fixP->fx_pcrel)
+       fixP->fx_r_type = BFD_RELOC_8_PCREL;
+      size = 1;
+      goto do_reloc_xx;
+
     case BFD_RELOC_16:
       if (fixP->fx_pcrel)
        fixP->fx_r_type = BFD_RELOC_16_PCREL;
@@ -5273,7 +5796,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
 
 #ifdef OBJ_ECOFF
     case BFD_RELOC_GPREL32:
-      assert (fixP->fx_subsy == alpha_gp_symbol);
+      gas_assert (fixP->fx_subsy == alpha_gp_symbol);
       fixP->fx_subsy = 0;
       /* FIXME: inherited this obliviousness of `value' -- why?  */
       md_number_to_chars (fixpos, -alpha_gp_value, 4);
@@ -5334,6 +5857,79 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
     case BFD_RELOC_ALPHA_CODEADDR:
       return;
 
+#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_NOP:
+      value -= (8 + 4); /* PC-relative, base is jsr+4.  */
+
+      /* From B.4.5.2 of the OpenVMS Linker Utility Manual:
+        "Finally, the ETIR$C_STC_BSR command passes the same address
+         as ETIR$C_STC_NOP (so that they will fail or succeed together),
+         and the same test is done again."  */
+      if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
+       {
+         fixP->fx_addnumber = -value;
+         return;
+       }
+
+      if (value + (1u << 22) >= (1u << 23))
+       goto done;
+      else
+       {
+         /* Change to a nop.  */
+         image = 0x47FF041F;
+         goto write_done;
+       }
+
+    case BFD_RELOC_ALPHA_LDA:
+      /* fixup_segment sets fixP->fx_addsy to NULL when it can pre-compute
+        the value for an O_subtract.  */
+      if (fixP->fx_addsy
+         && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
+       {
+         fixP->fx_addnumber = symbol_get_bfdsym (fixP->fx_subsy)->value;
+         return;
+       }
+
+      if (value + (1u << 15) >= (1u << 16))
+       goto done;
+      else
+       {
+         /* Change to an lda.  */
+         image = 0x237B0000 | (value & 0xFFFF);
+         goto write_done;
+       }
+
+    case BFD_RELOC_ALPHA_BSR:
+    case BFD_RELOC_ALPHA_BOH:
+      value -= 4; /* PC-relative, base is jsr+4.  */
+
+      /* See comment in the BFD_RELOC_ALPHA_NOP case above.  */
+      if (S_GET_SEGMENT (fixP->fx_addsy) == undefined_section)
+       {
+         fixP->fx_addnumber = -value;
+         return;
+       }
+
+      if (value + (1u << 22) >= (1u << 23))
+       {
+         /* Out of range.  */
+         if (fixP->fx_r_type == BFD_RELOC_ALPHA_BOH)
+           {
+             /* Add a hint.  */
+             image = bfd_getl32(fixpos);
+             image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF);
+             goto write_done;
+           }
+         goto done;
+       }
+      else
+       {
+         /* Change to a branch.  */
+         image = 0xD3400000 | ((value >> 2) & 0x1FFFFF);
+         goto write_done;
+       }
+#endif
+
     case BFD_RELOC_VTABLE_INHERIT:
     case BFD_RELOC_VTABLE_ENTRY:
       return;
@@ -5346,7 +5942,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
          as_fatal (_("unhandled relocation type %s"),
                    bfd_get_reloc_code_name (fixP->fx_r_type));
 
-       assert (-(int) fixP->fx_r_type < (int) alpha_num_operands);
+       gas_assert (-(int) fixP->fx_r_type < (int) alpha_num_operands);
        operand = &alpha_operands[-(int) fixP->fx_r_type];
 
        /* The rest of these fixups only exist internally during symbol
@@ -5374,10 +5970,10 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
       goto done;
     }
 
-write_done:
+ write_done:
   md_number_to_chars (fixpos, image, 4);
 
-done:
+ done:
   fixP->fx_done = 1;
 }
 
@@ -5503,6 +6099,12 @@ alpha_force_relocation (fixS *f)
     case BFD_RELOC_ALPHA_TPREL_HI16:
     case BFD_RELOC_ALPHA_TPREL_LO16:
     case BFD_RELOC_ALPHA_TPREL16:
+#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_NOP:
+    case BFD_RELOC_ALPHA_BSR:
+    case BFD_RELOC_ALPHA_LDA:
+    case BFD_RELOC_ALPHA_BOH:
+#endif
       return 1;
 
     default:
@@ -5542,6 +6144,7 @@ alpha_fix_adjustable (fixS *f)
     case BFD_RELOC_ALPHA_GPREL_HI16:
     case BFD_RELOC_ALPHA_GPREL_LO16:
     case BFD_RELOC_23_PCREL_S2:
+    case BFD_RELOC_16:
     case BFD_RELOC_32:
     case BFD_RELOC_64:
     case BFD_RELOC_ALPHA_HINT:
@@ -5595,6 +6198,13 @@ alpha_fix_adjustable (fixS *f)
        return 1;
       }
 #endif
+#ifdef OBJ_EVAX
+    case BFD_RELOC_ALPHA_NOP:
+    case BFD_RELOC_ALPHA_BSR:
+    case BFD_RELOC_ALPHA_LDA:
+    case BFD_RELOC_ALPHA_BOH:
+      return 1;
+#endif
 
     default:
       return 1;
@@ -5610,14 +6220,14 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED,
 {
   arelent *reloc;
 
-  reloc = xmalloc (sizeof (* reloc));
-  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+  reloc = XNEW (arelent);
+  reloc->sym_ptr_ptr = XNEW (asymbol *);
   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
   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 ((int) fixp->fx_r_type > 0);
+  gas_assert ((int) fixp->fx_r_type > 0);
 
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
   if (reloc->howto == NULL)
@@ -5632,28 +6242,73 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED,
     as_fatal (_("internal error? cannot generate `%s' relocation"),
              bfd_get_reloc_code_name (fixp->fx_r_type));
 
-  assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
+  gas_assert (!fixp->fx_pcrel == !reloc->howto->pc_relative);
+
+  reloc->addend = fixp->fx_offset;
 
 #ifdef OBJ_ECOFF
+  /* Fake out bfd_perform_relocation. sigh.  */
+  /* ??? Better would be to use the special_function hook.  */
   if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL)
-    /* Fake out bfd_perform_relocation. sigh.  */
     reloc->addend = -alpha_gp_value;
-  else
 #endif
+
+#ifdef OBJ_EVAX
+  switch (fixp->fx_r_type)
     {
-      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
-         of thing, and as a result we need to fake it out here.  */
-      if ((S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)
-          || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_MERGE)
-          || (S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_THREAD_LOCAL))
-         && !S_IS_COMMON (fixp->fx_addsy))
-       reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value;
-#endif
+      struct evax_private_udata_struct *udata;
+      const char *pname;
+      int pname_len;
+
+    case BFD_RELOC_ALPHA_LINKAGE:
+      /* Copy the linkage index.  */
+      reloc->addend = fixp->fx_addnumber;
+      break;
+
+    case BFD_RELOC_ALPHA_NOP:
+    case BFD_RELOC_ALPHA_BSR:
+    case BFD_RELOC_ALPHA_LDA:
+    case BFD_RELOC_ALPHA_BOH:
+      pname = symbol_get_bfdsym (fixp->fx_addsy)->name;
+
+      /* We need the non-suffixed name of the procedure.  Beware that
+      the main symbol might be equated so look it up and take its name.  */
+      pname_len = strlen (pname);
+      if (pname_len > 4 && strcmp (pname + pname_len - 4, "..en") == 0)
+       {
+         symbolS *sym;
+         char *my_pname = xmemdup0 (pname, pname_len - 4);
+         sym = symbol_find (my_pname);
+         free (my_pname);
+         if (sym == NULL)
+           abort ();
+
+         while (symbol_equated_reloc_p (sym))
+           {
+             symbolS *n = symbol_get_value_expression (sym)->X_add_symbol;
+
+             /* We must avoid looping, as that can occur with a badly
+                written program.  */
+             if (n == sym)
+               break;
+             sym = n;
+           }
+         pname = symbol_get_bfdsym (sym)->name;
+       }
+
+      udata = XNEW (struct evax_private_udata_struct);
+      udata->enbsym = symbol_get_bfdsym (fixp->fx_addsy);
+      udata->bsym = symbol_get_bfdsym (fixp->tc_fix_data.info->psym);
+      udata->origname = (char *)pname;
+      udata->lkindex = ((struct evax_private_udata_struct *)
+        symbol_get_bfdsym (fixp->tc_fix_data.info->sym)->udata.p)->lkindex;
+      reloc->sym_ptr_ptr = (void *)udata;
+      reloc->addend = fixp->fx_addnumber;
+
+    default:
+      break;
     }
+#endif
 
   return reloc;
 }
@@ -5672,8 +6327,8 @@ tc_get_register (int frame ATTRIBUTE_UNUSED)
   SKIP_WHITESPACE ();
   if (*input_line_pointer == '$')
     {
-      char *s = input_line_pointer;
-      char c = get_symbol_end ();
+      char *s;
+      char c = get_symbol_name (&s);
       symbolS *sym = md_undefined_symbol (s);
 
       *strchr (s, '\0') = c;
@@ -5682,7 +6337,7 @@ tc_get_register (int frame ATTRIBUTE_UNUSED)
     }
   as_warn (_("frame reg expected, using $%d."), framereg);
 
-found:
+ found:
   note_gpreg (framereg);
   return framereg;
 }
@@ -5709,5 +6364,4 @@ alpha_frob_file_before_adjust (void)
 /* The Alpha has support for some VAX floating point types, as well as for
    IEEE floating point.  We consider IEEE to be the primary floating point
    format, and sneak in the VAX floating point support here.  */
-#define md_atof vax_md_atof
 #include "config/atof-vax.c"