[Patch] Improve gas for alpha-vms

Tristan Gingold gingold@adacore.com
Tue Feb 24 10:05:00 GMT 2009
Hi,

this patch improves gas support for alpha-vms.  It mostly adds condition
handlings and support for relocation optimizations.

No regressions on alpha-linux and alpha-linuxecoff.
Extensively tested on alpha-vms (using AdaCore testsuite for vms).

[ BTW, if a vms maintainer is needed I will be happy to apply].

Tristan.

gas/
2009-02-24  Tristan Gingold  <gingold@adacore.com>
	    Eric Botcazou  <ebotcazou@adacore.com>
	    Douglas B Rupp  <rupp@gnat.com>

	* doc/as.texinfo (Overview): Mention -replace/-noreplace options
	for Alpha.
	* doc/c-alpha.texi (Alpha Options): Document -replace/-noreplace.
	* config/tc-alpha.h (TC_VALIDATE_FIX_SUB): Define to 1 (evax).
	(OBJ_SYMFIELD_TYPE): Remove.
	(tc_canonicalize_symbol_name): Define to evax_shorten_name.
	(TC_IMPLICIT_LCOMM_ALIGNMENT): For alignment to 3 on evax.
	(tc_frob_file_before_fix): Do not defined on evax.
	* config/tc-alpha.c: Always includes dwarf2dbg.h.
	Include vms.h if OBJ_EVAX.
	(struct alpha_fixup): Add xtrasym and procsym (evax only).
	(enum alpha_macro_arg): Remove trailing comma.
	(md_longopts): Add replace and noreplace arguments (evax only).
	(alpha_evax_proc_hash): New variable.
	(alpha_link_section): Make it global.
	(alpha_ctors_section, alpha_dtors_section): Removed.
	(alpha_ctors_symbol, alpha_dtors_symbol): Ditto.
	(alpha_lit8_section): Ifndef'ed on evax.
	(alpha_lit8_symbol): Ditto.
	(alpha_prologue_label): New variable.
	(alpha_linkage_symbol): New variable (evax only).
	(alpha_flag_replace): Ditto.
	(struct alpha_evax_procs): Add handler and handler_data field.
	(alpha_evax_proc): Now of type pointer.
	(alpha_linkage_fixup_root, alpha_linkage_fixup_tail): New variables.
	(struct alpha_reloc_tag): Add sym and psym fields (evax only).
	(get_alpha_reloc_tag): Initialize sym and psym fields (evax only).
	(alpha_adjust_relocs): Ifndef'ed on evax.
	(load_expression): Add opname argument.
	Implement LDA/BSR optimization for evax.
	(emit_lda): Adjust for new prototype of load_expression.
	(emit_ir_load): Ditto. Do not nothing for GP if ..lk symbols.
	(emit_loadstore): Likewise.
	(emit_ldXu): Likewise.
	(emit_stX): Likewise.
	(emit_jsrjmp): Likewise.  Implement LDA/BSR optimization for evax.
	(emit_ldgp): Avoid warning in evax case.
	(add_to_link_pool): Make it static.  Return symbolic expression rather
	than number expression for the offset.
	(s_alpha_text): Create .text symbol for evax if not already created.
	(s_alpha_comm): Do not create specific section for common symbol.
	Fill common area with zeros for evax.
	(s_alpha_prologue): Create alpha_prologue_label.
	(s_alpha_section_name): New function (evax).
	(s_alpha_section_word): Likewise.
	(section_name): New static variabke moved out from ...
	(s_alpha_section): ... here.  Create new sections on demand.
	(s_alpha_literals): New function (evax).
	(s_alpha_ent): Create alpha_evax_proc instance and insert it in the
	alpha_evax_proc_hash table.
	(s_alpha_handler): New function (evax).
	(s_alpha_frame): Adjust for new type of alpha_evax_proc.
	(s_alpha_prologue): New function (evax).
	(s_alpha_pdesc): Adjust for new type of alpha_evax_proc and new
	handling of procedures with hash table.
	Add support for condition handlers.
	(s_alpha_linkage): Create linkage_fixup instance and chain it.
	(s_alpha_fp_save): Adjust for new type of alpha_evax_proc.
	(s_alpha_mask): Likewise.
	(s_alpha_fmask): Likewise.
	(s_alpha_end): Clear alpha_evax_proc.
	(s_alpha_align): Increase max_alignment to 16.
	(alpha_print_token): Call print_expr_1 instead of print_expr.
	(md_pseudo_table): Add "section", "literals", "handler" and 
	"handler_data" (evax).  Do not ignore "prologue" on evax.
	Fix indentation.
	(md_begin): Create hash table for alpha_evax_proc_hash.
	(md_parse_option): Handle OPTION_REPLACE and OPTION_NOREPLACE.
	(md_show_usage): Mention -replace/-noreplace for evax.
	(md_apply_fix): Handle evax relocs (_NOP, _LDA, _BSR and _BOH).
	(alpha_force_relocation): Likewise.
	(alpha_fix_adjustable): Likewise. Add BFD_RELOC_16 case.
	(tc_gen_reloc): Likewise.  Add BFD_RELOC_ALPHA_LINKAGE for evax.
	(emit_insn): New cases for evax specific relocs.
	(assemble_insn): Fix indentation.
	Take care of -MDISP in operand table.
	* config/obj-evax.h (struct alpha_linkage_fixups): New struct.
	(OBJ_SYMFIELD_TYPE): New macro.
	(obj_symbol_new_hook): Define.
	(obj_frob_symbol, obj_frob_file_before_adjust): Ditto.
	(obj_frob_file_before_fix): Ditto.
	(PDSC_S_M_HANDLER_VALID): New macro.
	(PDSC_S_M_HANDLER_DATA_VALID): Ditto.
	(TC_IMPLICIT_LCOMM_ALIGNMENT): Remove.
	Add prototypes for functions declared in obj-evax.c
	* config/obj-evax.c: Include subsegs.h, struc-symbol.h, safe-ctype.h.
	(s_evax_weak): Convert to ansi-C.
	(evax_symbol_new_hook): New function.
	(evax_frob_symbol): Ditto.
	(evax_frob_file_before_adjust): Ditto.
	(evax_frob_file_before_fix): Ditto.
	(evax_shorten_name): Ditto.
	(crc32): Ditto.
	(encode_32): Ditto.
	(encode_16): Ditto.
	(decode_16): Ditto.
	(shorten_identifier): Ditto.
	(is_truncated_identifier): Ditto.
	* dwarf2dbg.c (out_debug_info): Do not append trailing slash on	VMS.
	* as.c (close_output_file): Remove #ifndef OBJ_VMS.
	(main): Ditto.

-------------- next part --------------
gas/
2009-02-24  Tristan Gingold  <gingold@adacore.com>
	    Eric Botcazou  <ebotcazou@adacore.com>
	    Douglas B Rupp  <rupp@gnat.com>

	* doc/as.texinfo (Overview): Mention -replace/-noreplace options
	for Alpha.
	* doc/c-alpha.texi (Alpha Options): Document -replace/-noreplace.
	* config/tc-alpha.h (TC_VALIDATE_FIX_SUB): Define to 1 (evax).
	(OBJ_SYMFIELD_TYPE): Remove.
	(tc_canonicalize_symbol_name): Define to evax_shorten_name.
	(TC_IMPLICIT_LCOMM_ALIGNMENT): For alignment to 3 on evax.
	(tc_frob_file_before_fix): Do not defined on evax.
	* config/tc-alpha.c: Always includes dwarf2dbg.h.
	Include vms.h if OBJ_EVAX.
	(struct alpha_fixup): Add xtrasym and procsym (evax only).
	(enum alpha_macro_arg): Remove trailing comma.
	(md_longopts): Add replace and noreplace arguments (evax only).
	(alpha_evax_proc_hash): New variable.
	(alpha_link_section): Make it global.
	(alpha_ctors_section, alpha_dtors_section): Removed.
	(alpha_ctors_symbol, alpha_dtors_symbol): Ditto.
	(alpha_lit8_section): Ifndef'ed on evax.
	(alpha_lit8_symbol): Ditto.
	(alpha_prologue_label): New variable.
	(alpha_linkage_symbol): New variable (evax only).
	(alpha_flag_replace): Ditto.
	(struct alpha_evax_procs): Add handler and handler_data field.
	(alpha_evax_proc): Now of type pointer.
	(alpha_linkage_fixup_root, alpha_linkage_fixup_tail): New variables.
	(struct alpha_reloc_tag): Add sym and psym fields (evax only).
	(get_alpha_reloc_tag): Initialize sym and psym fields (evax only).
	(alpha_adjust_relocs): Ifndef'ed on evax.
	(load_expression): Add opname argument.
	Implement LDA/BSR optimization for evax.
	(emit_lda): Adjust for new prototype of load_expression.
	(emit_ir_load): Ditto. Do not nothing for GP if ..lk symbols.
	(emit_loadstore): Likewise.
	(emit_ldXu): Likewise.
	(emit_stX): Likewise.
	(emit_jsrjmp): Likewise.  Implement LDA/BSR optimization for evax.
	(emit_ldgp): Avoid warning in evax case.
	(add_to_link_pool): Make it static.  Return symbolic expression rather
	than number expression for the offset.
	(s_alpha_text): Create .text symbol for evax if not already created.
	(s_alpha_comm): Do not create specific section for common symbol.
	Fill common area with zeros for evax.
	(s_alpha_prologue): Create alpha_prologue_label.
	(s_alpha_section_name): New function (evax).
	(s_alpha_section_word): Likewise.
	(section_name): New static variabke moved out from ...
	(s_alpha_section): ... here.  Create new sections on demand.
	(s_alpha_literals): New function (evax).
	(s_alpha_ent): Create alpha_evax_proc instance and insert it in the
	alpha_evax_proc_hash table.
	(s_alpha_handler): New function (evax).
	(s_alpha_frame): Adjust for new type of alpha_evax_proc.
	(s_alpha_prologue): New function (evax).
	(s_alpha_pdesc): Adjust for new type of alpha_evax_proc and new
	handling of procedures with hash table.
	Add support for condition handlers.
	(s_alpha_linkage): Create linkage_fixup instance and chain it.
	(s_alpha_fp_save): Adjust for new type of alpha_evax_proc.
	(s_alpha_mask): Likewise.
	(s_alpha_fmask): Likewise.
	(s_alpha_end): Clear alpha_evax_proc.
	(s_alpha_align): Increase max_alignment to 16.
	(alpha_print_token): Call print_expr_1 instead of print_expr.
	(md_pseudo_table): Add "section", "literals", "handler" and 
	"handler_data" (evax).  Do not ignore "prologue" on evax.
	Fix indentation.
	(md_begin): Create hash table for alpha_evax_proc_hash.
	(md_parse_option): Handle OPTION_REPLACE and OPTION_NOREPLACE.
	(md_show_usage): Mention -replace/-noreplace for evax.
	(md_apply_fix): Handle evax relocs (_NOP, _LDA, _BSR and _BOH).
	(alpha_force_relocation): Likewise.
	(alpha_fix_adjustable): Likewise. Add BFD_RELOC_16 case.
	(tc_gen_reloc): Likewise.  Add BFD_RELOC_ALPHA_LINKAGE for evax.
	(emit_insn): New cases for evax specific relocs.
	(assemble_insn): Fix indentation.
	Take care of -MDISP in operand table.
	* config/obj-evax.h (struct alpha_linkage_fixups): New struct.
	(OBJ_SYMFIELD_TYPE): New macro.
	(obj_symbol_new_hook): Define.
	(obj_frob_symbol, obj_frob_file_before_adjust): Ditto.
	(obj_frob_file_before_fix): Ditto.
	(PDSC_S_M_HANDLER_VALID): New macro.
	(PDSC_S_M_HANDLER_DATA_VALID): Ditto.
	(TC_IMPLICIT_LCOMM_ALIGNMENT): Remove.
	Add prototypes for functions declared in obj-evax.c
	* config/obj-evax.c: Include subsegs.h, struc-symbol.h, safe-ctype.h.
	(s_evax_weak): Convert to ansi-C.
	(evax_symbol_new_hook): New function.
	(evax_frob_symbol): Ditto.
	(evax_frob_file_before_adjust): Ditto.
	(evax_frob_file_before_fix): Ditto.
	(evax_shorten_name): Ditto.
	(crc32): Ditto.
	(encode_32): Ditto.
	(encode_16): Ditto.
	(decode_16): Ditto.
	(shorten_identifier): Ditto.
	(is_truncated_identifier): Ditto.
	* dwarf2dbg.c (out_debug_info): Do not append trailing slash on	VMS.
	* as.c (close_output_file): Remove #ifndef OBJ_VMS.
	(main): Ditto.

Index: as.c
===================================================================
RCS file: /cvs/src/src/gas/as.c,v
retrieving revision 1.81
diff -u -r1.81 as.c
--- as.c	17 Nov 2008 17:44:32 -0000	1.81
+++ as.c	24 Feb 2009 09:58:57 -0000
@@ -948,13 +948,11 @@
 #endif
 }
 
-#ifndef OBJ_VMS
 static void
 close_output_file (void)
 {
   output_file_close (out_file_name);
 }
-#endif
 
 /* The interface between the macro code and gas expression handling.  */
 
@@ -1136,10 +1134,8 @@
   input_scrub_begin ();
   expr_begin ();
 
-#ifndef OBJ_VMS /* Does its own file handling.  */
   /* It has to be called after dump_statistics ().  */
   xatexit (close_output_file);
-#endif
 
   if (flag_print_statistics)
     xatexit (dump_statistics);
Index: dwarf2dbg.c
===================================================================
RCS file: /cvs/src/src/gas/dwarf2dbg.c,v
retrieving revision 1.99
diff -u -r1.99 dwarf2dbg.c
--- dwarf2dbg.c	15 Jan 2009 12:42:52 -0000	1.99
+++ dwarf2dbg.c	24 Feb 2009 09:58:57 -0000
@@ -1636,9 +1636,15 @@
     {
       dirname = remap_debug_filename (dirs[files[1].dir]);
       len = strlen (dirname);
+#ifdef TE_VMS
+      /* Already has trailing slash.  */
+      p = frag_more (len);
+      memcpy (p, dirname, len);
+#else
       p = frag_more (len + 1);
       memcpy (p, dirname, len);
       INSERT_DIR_SEPARATOR (p, len);
+#endif
     }
   len = strlen (files[1].filename) + 1;
   p = frag_more (len);
Index: config/obj-evax.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-evax.c,v
retrieving revision 1.5
diff -u -r1.5 obj-evax.c
--- config/obj-evax.c	12 Aug 2008 23:39:30 -0000	1.5
+++ config/obj-evax.c	24 Feb 2009 09:58:57 -0000
@@ -2,6 +2,7 @@
    Copyright 1996, 1997, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Klaus K??mpf (kkaempf@progis.de) of
      proGIS Software, Aachen, Germany.
+   Extensively enhanced by Douglas Rupp of AdaCore.
 
    This file is part of GAS, the GNU Assembler
 
@@ -22,9 +23,18 @@
 
 #define OBJ_HEADER "obj-evax.h"
 
+#include "bfd.h"
+#include "vms.h"
 #include "as.h"
+#include "subsegs.h"
+#include "struc-symbol.h"
+#include "safe-ctype.h"
 
 static void s_evax_weak (int);
+static unsigned int crc32 (unsigned char *, int);
+static char *encode_32 (unsigned int);
+static char *encode_16 (unsigned int);
+static int decode_16 (const char *);
 
 const pseudo_typeS obj_pseudo_table[] =
 {
@@ -37,8 +47,7 @@
 /* Handle the weak specific pseudo-op.  */
 
 static void
-s_evax_weak (ignore)
-     int ignore;
+s_evax_weak (int ignore ATTRIBUTE_UNUSED)
 {
   char *name;
   int c;
@@ -73,11 +82,436 @@
   demand_empty_rest_of_line ();
 }
 
-/*
- * Local Variables:
- * comment-column: 0
- * fill-column: 131
- * End:
- */
+void
+evax_symbol_new_hook (symbolS *sym)
+{
+  struct evax_private_udata_struct *udata;
+
+  udata = (struct evax_private_udata_struct *)
+    xmalloc (sizeof (struct evax_private_udata_struct));
+
+  udata->bsym = symbol_get_bfdsym (sym);
+  udata->enbsym = NULL;
+  udata->origname = xstrdup (S_GET_NAME (sym));
+  udata->lkindex = 0;
+  symbol_get_bfdsym(sym)->udata.p = (PTR) udata;
+}
+
+void
+evax_frob_symbol (symbolS *sym, int *punt)
+{
+  const char *symname = S_GET_NAME (sym);
+  int symlen = strlen (symname);
+  asymbol *symbol = symbol_get_bfdsym (sym);
+
+  if (symlen > 4
+      && strcmp (symname + symlen - 4, "..en") == 0
+      && S_GET_SEGMENT (sym) == undefined_section)
+    {
+      symbol_clear_used_in_reloc (sym);
+      *punt = 1;
+    }
+
+  else if ((symbol->flags & BSF_GLOBAL) && (symbol->flags & BSF_FUNCTION))
+    {
+      struct evax_private_udata_struct *udata
+	= (struct evax_private_udata_struct *)symbol->udata.p;
+
+      /* Fix up equates of function definitions.  */
+      while (udata->enbsym == NULL)
+	{
+	  /* ??? Equates have been resolved at this point so their
+	     expression is O_constant; but they previously were
+	     O_symbol and we hope the equated symbol is still there.  */
+	  sym = symbol_get_value_expression (sym)->X_add_symbol;
+	  if (sym == NULL)
+	    abort ();
+	  symbol = symbol_get_bfdsym (sym);
+	  udata->enbsym
+	    = ((struct evax_private_udata_struct *)symbol->udata.p)->enbsym;
+	}
+    }
+}
+
+void
+evax_frob_file_before_adjust (void)
+{
+  struct alpha_linkage_fixups *l;
+  segT current_section = now_seg;
+  int current_subsec = now_subseg;
+  segment_info_type *seginfo;
+  int linkage_index = 1;
+
+  subseg_set (alpha_link_section, 0);
+  seginfo = seg_info (alpha_link_section);
+
+  for (l = alpha_linkage_fixup_root; l != NULL; l = l->next)
+    {
+      if (S_GET_SEGMENT (l->fixp->fx_addsy) == alpha_link_section)
+	{
+	  symbolS * entry_sym;
+	  fixS *fixpentry, *fixppdesc, *fixtail;
+
+	  fixtail = seginfo->fix_tail;
+
+	  /* Replace the linkage with the local symbols */
+	  entry_sym = symbol_find
+	    (((struct evax_private_udata_struct *)symbol_get_bfdsym (l->fixp->fx_addsy)->udata.p)->enbsym->name);
+	  if (!entry_sym)
+	    abort ();
+	  fixpentry = fix_new (l->fixp->fx_frag, l->fixp->fx_where, 8,
+			       entry_sym, l->fixp->fx_offset, 0,
+			       BFD_RELOC_64);
+	  fixppdesc = fix_new (l->fixp->fx_frag, l->fixp->fx_where+8, 8,
+			       l->fixp->fx_addsy, l->fixp->fx_offset, 0,
+			       BFD_RELOC_64);
+	  l->fixp->fx_size = 0;
+	  l->fixp->fx_done = 1;
+
+	  /* If not already at the tail, splice the new fixups into
+	     the chain right after the one we are nulling out */
+	  if (fixtail != l->fixp)
+	    {
+	      fixppdesc->fx_next = l->fixp->fx_next;
+	      l->fixp->fx_next = fixpentry;
+	      fixtail->fx_next = 0;
+	      seginfo->fix_tail = fixtail;
+	    }
+	}
+      else
+	{
+	  ((struct evax_private_udata_struct *)
+	   symbol_get_bfdsym (l->label)->udata.p)->lkindex = linkage_index;
+
+	  l->fixp->fx_addnumber = linkage_index;
+
+	  linkage_index += 2;
+	}
+    }
+
+  subseg_set (current_section, current_subsec);
+}
+
+void
+evax_frob_file_before_fix (void)
+{
+  /* Now that the fixups are done earlier, we need to transfer the values
+     into the BFD symbols before calling fix_segment (ideally should not
+     be done also later).  */
+  if (symbol_rootP)
+    {
+      symbolS *symp;
+
+      /* Set the value into the BFD symbol.  Up til now the value
+	 has only been kept in the gas symbolS struct.  */
+      for (symp = symbol_rootP; symp; symp = symbol_next (symp))
+	symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp);
+    }
+}
+
+/* The length is computed from the maximum allowable length of 64 less the
+   4 character ..xx extension that must be preserved (removed before
+   krunching and appended back on afterwards).  The $<nnn>.. prefix is
+   also removed and prepened back on, but doesn't enter into the length
+   computation because symbols with that prefix are always resolved
+   by the assembler and will never appear in the symbol table. At least
+   I hope that's true, TBD.  */
+#define MAX_LABEL_LENGTH 60
+
+static char *shorten_identifier (char *);
+static int is_truncated_identifier (char *);
+
+char *
+evax_shorten_name (char *id)
+{
+  int prefix_dotdot = 0;
+  char prefix [64];
+  int len = strlen (id);
+  int suffix_dotdot = len;
+  char suffix [64];
+  char *base_id;
+
+  /* This test may be too conservative.  */
+  if (len <= MAX_LABEL_LENGTH)
+    return id;
+
+  suffix [0] = 0;
+  prefix [0] = 0;
+
+  /* Check for ..xx suffix and save it.  */
+  if (strncmp (&id[len-4], "..", 2) == 0)
+    {
+      suffix_dotdot = len - 4;
+      strncpy (suffix, &id[len-4], 4);
+      suffix [4] = 0;
+    }
+
+  /* Check for $<nnn>.. prefix and save it.  */
+  if ((id[0] == '$') && ISDIGIT (id[1]))
+    {
+      int i;
+
+      for (i=2; i < len; i++)
+        {
+	  if (!ISDIGIT (id[i]))
+            {
+	      if (id[i] == '.' && id [i+1] == '.')
+                 {
+                   prefix_dotdot = i+2;
+                   strncpy (prefix, id, prefix_dotdot);
+                   prefix [prefix_dotdot] = 0;
+                 }
+               break;
+            }
+        }
+    }
+
+  /* We only need worry about krunching the base symbol.  */
+  base_id = xmalloc (suffix_dotdot - prefix_dotdot + 1);
+  strncpy (base_id, &id[prefix_dotdot], suffix_dotdot - prefix_dotdot);
+  base_id [suffix_dotdot - prefix_dotdot] = 0;
+
+  if (strlen (base_id) > MAX_LABEL_LENGTH)
+    {
+      char new_id [4096];
+      char *return_id;
+
+      strcpy (new_id, base_id);
+
+      /* Shorten it.  */
+      strcpy (new_id, shorten_identifier (new_id));
+
+      /* Prepend back the prefix if there was one.  */
+      if (prefix_dotdot)
+        {
+          memmove (&new_id [prefix_dotdot], new_id, strlen (new_id) + 1);
+          strncpy (new_id, prefix, prefix_dotdot);
+        }
+
+      /* Append back the suffix if there was one.  */
+      if (strlen (suffix))
+	strcat (new_id, suffix);
+
+      /* Save it on the heap and return.  */
+      return_id = xmalloc (strlen (new_id) + 1);
+      strcpy (return_id, new_id);
+
+      return return_id;
+    }
+  else
+    return id;
+}
+
+/* The code below implements a mechanism for truncating long
+   identifiers to an arbitrary length (set by MAX_LABEL_LENGTH).
+
+   It attempts to make each truncated identifier unique by replacing
+   part of the identifier with an encoded 32-bit CRC and an associated
+   checksum (the checksum is used as a way to determine that the name
+   was truncated).
+
+   Note that both a portion of the start and of the end of the
+   identifier may be kept.  The macro ID_SUFFIX_LENGTH will return the
+   number of characters in the suffix of the identifier that should be
+   kept.
+
+   The portion of the identifier that is going to be removed is
+   checksummed.  The checksum is then encoded as a 5-character string,
+   the characters of which are then summed.  This sum is then encoded
+   as a 3-character string.  Finally, the original length of the
+   identifier is encoded as a 3-character string.
+
+   These three strings are then concatenated together (along with an _h
+   which further designates that the name was truncated):
+
+   "original_identifier"_haaaaabbbccc
+   
+   aaaaa = 32-bit CRC
+   bbb = length of original identifier
+   ccc = sum of 32-bit CRC characters
+
+   The resulting identifier will be MAX_LABEL_LENGTH characters long.
+
+   */
+
+
+/* Table used to convert an integer into a string.  */
+
+static const char codings[] = {
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_'};
+
+/* The number of codings in the above table.  */
+static const int number_of_codings = sizeof (codings) / sizeof (char);
+
+/* Table used by decode_16 () to convert an encoded string back into
+   an integer.  */
+static char decodings[256];
+
+/* Table used by the crc32 function to calcuate the checksum.  */
+static unsigned int crc32_table[256] = {0, 0};
+
+/* Given a string in BUF, calculate a 32-bit CRC for it. 
+
+   This is used as a reasonably unique hash for the given string.  */
+
+static unsigned int
+crc32 (unsigned char *buf, int len)
+{
+  unsigned int crc = 0xffffffff;
+
+  if (! crc32_table[1])
+    {
+      /* Initialize the CRC table and the decoding table. */
+      int i, j;
+      unsigned int c;
+
+      for (i = 0; i < 256; i++)
+	{
+	  for (c = i << 24, j = 8; j > 0; --j)
+	    c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
+	  crc32_table[i] = c;
+	  decodings[i] = 0;
+	}
+      for (i = 0; i < number_of_codings; i++)
+	decodings[codings[i] & 255] = i;
+    }
+
+  while (len--)
+    {
+      crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *buf];
+      buf++;
+    }
+  return crc;
+}
+
+/* Encode the lower 32 bits of VALUE as a 5-character string.  */
+
+static char *
+encode_32 (unsigned int value)
+{
+  static char res[6];
+  int x;
+
+  res[5] = 0;
+  for(x = 0; x < 5; x++)
+    {
+      res[x] = codings[value % number_of_codings];
+      value = value / number_of_codings;
+    }
+  return res;
+}
+
+/* Encode the lower 16 bits of VALUE as a 3-character string.  */
+
+static char *
+encode_16 (unsigned int value)
+{
+  static char res[4];
+  int x;
+
+  res[3] = 0;
+  for(x = 0; x < 3; x++)
+    {
+      res[x] = codings[value % number_of_codings];
+      value = value / number_of_codings;
+    }
+  return res;
+}
+
+/* Convert the encoded string obtained from encode_16 () back into a
+   16-bit integer.  */
+
+static int
+decode_16 (const char *string)
+{
+  return decodings[(int) string[2]] * number_of_codings * number_of_codings
+    + decodings[(int) string[1]] * number_of_codings
+    + decodings[(int) string[0]];
+}
+
+/* ID_SUFFIX_LENGTH is used to determine how many characters in the
+   suffix of the identifier are to be preserved, if any.  */
+
+#ifndef ID_SUFFIX_LENGTH
+#define ID_SUFFIX_LENGTH(ID) (0)
+#endif
+
+/* Return a reasonably-unique version of NAME that is less than or
+   equal to MAX_LABEL_LENGTH characters long.  The string returned from
+   this function may be a copy of NAME; the function will never
+   actually modify the contents of NAME.  */
+
+static char newname[MAX_LABEL_LENGTH + 1];
+
+static char *
+shorten_identifier (char *name)
+{
+  int crc, len, sum, x, final_len;
+  char *crc_chars;
+  int suffix_length = ID_SUFFIX_LENGTH (name);
+
+  if ((len = strlen (name)) <= MAX_LABEL_LENGTH)
+    return name;
+
+  final_len = MAX_LABEL_LENGTH - 2 - 5 - 3 - 3 - suffix_length;
+  crc = crc32 ((unsigned char *)name + final_len,
+	       len - final_len - suffix_length);
+  crc_chars = encode_32 (crc);
+  sum = 0;
+  for (x = 0; x < 5; x++)
+    sum += crc_chars [x];
+  strncpy (newname, name, final_len);
+  newname [MAX_LABEL_LENGTH] = 0;
+  /* Now append the suffix of the original identifier, if any.  */
+  if (suffix_length)
+  strncpy (newname + MAX_LABEL_LENGTH - suffix_length,
+	   name + len - suffix_length,
+	   suffix_length);
+  strncpy (newname + final_len, "_h", 2);
+  strncpy (newname + final_len + 2 , crc_chars, 5);
+  strncpy (newname + final_len + 2 + 5, encode_16 (len), 3);
+  strncpy (newname + final_len + 2 + 5 + 3, encode_16 (sum), 3);
+  if (!is_truncated_identifier (newname))
+    abort ();
+  return newname;
+}
+
+/* Determine whether or not ID is a truncated identifier, and return a
+   non-zero value if it is.  */
+
+static int
+is_truncated_identifier (char *id)
+{
+  char *ptr;
+  int len = strlen (id);
+  /* If it's not exactly MAX_LABEL_LENGTH characters long, it can't be
+     a truncated identifier.  */
+  if (len != MAX_LABEL_LENGTH)
+    return 0;
+  
+  /* Start scanning backwards for a _h.  */
+  len = len - 3 - 3 - 5 - 2;
+  ptr = id + len;
+  while (ptr >= id)
+    {
+      if (ptr[0] == '_' && ptr[1] == 'h')
+	{
+	  /* Now see if the sum encoded in the identifer matches.  */
+	  int x, sum;
+	  sum = 0;
+	  for (x = 0; x < 5; x++)
+	    sum += ptr[x + 2];
+	  /* If it matches, this is probably a truncated identifier.  */
+	  if (sum == decode_16 (ptr + 5 + 2 + 3))
+	    return 1;
+	}
+      ptr--;
+    }
+  return 0;
+}
 
 /* end of obj-evax.c */
Index: config/obj-evax.h
===================================================================
RCS file: /cvs/src/src/gas/config/obj-evax.h,v
retrieving revision 1.7
diff -u -r1.7 obj-evax.h
--- config/obj-evax.h	3 Jul 2007 11:01:04 -0000	1.7
+++ config/obj-evax.h	24 Feb 2009 09:58:57 -0000
@@ -25,6 +25,8 @@
  * object format specific header files.
  */
 
+#include "as.h"
+
 /* define an obj specific macro off which target cpu back ends may key.  */
 #define OBJ_EVAX 1
 
@@ -33,6 +35,16 @@
 
 #define OUTPUT_FLAVOR bfd_target_evax_flavour
 
+struct fix;
+
+struct alpha_linkage_fixups
+{
+  struct alpha_linkage_fixups *next;
+  struct fix *fixp;
+  segT seg;
+  symbolS *label;
+};
+
 /*
  * SYMBOLS
  */
@@ -58,7 +70,13 @@
 
 #define OBJ_EMIT_LINENO(a,b,c)	/* must be *something*.  This no-op's it out.  */
 
-#define obj_symbol_new_hook(s)        {;}
+/* This field keeps the symbols position in the link section.  */
+#define OBJ_SYMFIELD_TYPE valueT
+
+#define obj_symbol_new_hook(s)       evax_symbol_new_hook (s)
+#define obj_frob_symbol(s,p)         evax_frob_symbol (s, &p)
+#define obj_frob_file_before_adjust  evax_frob_file_before_adjust
+#define obj_frob_file_before_fix     evax_frob_file_before_fix
 
 #define S_SET_OTHER(S,V)
 #define S_SET_TYPE(S,T)
@@ -75,13 +93,23 @@
 #define PDSC_S_K_MIN_REGISTER_SIZE 24
 #define PDSC_S_K_NULL_SIZE 16
 
-#define PDSC_S_M_BASE_REG_IS_FP 0x80	/* low byte */
+#define PDSC_S_M_HANDLER_VALID 0x10		/* low byte */
+#define PDSC_S_M_HANDLER_DATA_VALID 0x40	/* low byte */
+#define PDSC_S_M_BASE_REG_IS_FP 0x80		/* low byte */
 #define PDSC_S_M_NATIVE 0x10		/* high byte */
 #define PDSC_S_M_NO_JACKET 0x20		/* high byte */
 
 #define LKP_S_K_SIZE 16
 
-#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 3
+extern segT alpha_link_section;
+extern struct alpha_linkage_fixups *alpha_linkage_fixup_root;
+
+extern void evax_section (int);
+extern void evax_symbol_new_hook (symbolS *);
+extern void evax_frob_symbol (symbolS *, int *);
+extern void evax_frob_file_before_adjust (void);
+extern void evax_frob_file_before_fix (void);
+extern char *evax_shorten_name (char *);
 
 /*
  * Local Variables:
Index: config/tc-alpha.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.c,v
retrieving revision 1.78
diff -u -r1.78 tc-alpha.c
--- config/tc-alpha.c	15 Jan 2009 12:42:52 -0000	1.78
+++ config/tc-alpha.c	24 Feb 2009 09:58:58 -0000
@@ -57,9 +57,13 @@
 
 #ifdef OBJ_ELF
 #include "elf/alpha.h"
-#include "dwarf2dbg.h"
 #endif
 
+#ifdef OBJ_EVAX
+#include "vms.h"
+#endif
+
+#include "dwarf2dbg.h"
 #include "dw2gencfi.h"
 #include "safe-ctype.h"
 
@@ -74,6 +78,9 @@
 {
   expressionS exp;
   bfd_reloc_code_real_type reloc;
+#ifdef OBJ_EVAX
+  symbolS *xtrasym, *procsym;
+#endif
 };
 
 struct alpha_insn
@@ -92,7 +99,7 @@
     MACRO_OPIR,
     MACRO_CPIR,
     MACRO_FPR,
-    MACRO_EXP,
+    MACRO_EXP
   };
 
 struct alpha_macro
@@ -245,6 +252,12 @@
     { "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 +281,9 @@
 
 #undef AXP_REG_GP
 #define AXP_REG_GP AXP_REG_PV
+
+static struct hash_control *alpha_evax_proc_hash;
+
 #endif /* OBJ_EVAX  */
 
 /* The cpu for which we are generating code.  */
@@ -299,11 +315,11 @@
 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 +327,10 @@
 #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 +355,12 @@
    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;
+static symbolS *alpha_prologue_label;
+
+#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 +380,11 @@
 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 +393,7 @@
 
 #ifdef OBJ_EVAX
 /* Collect information about current procedure here.  */
-static struct
+struct alpha_evax_procs
 {
   symbolS *symbol;	/* Proc pdesc symbol.  */
   int pdsckind;
@@ -379,7 +406,14 @@
   long fmask;
   int type;
   int prologue;
-} alpha_evax_proc;
+  symbolS *handler;
+  int handler_data;
+};
+
+struct alpha_linkage_fixups *alpha_linkage_fixup_root;
+static struct alpha_linkage_fixups *alpha_linkage_fixup_tail;
+
+static struct alpha_evax_procs *alpha_evax_proc;
 
 static int alpha_flag_hash_long_names = 0;		/* -+ */
 static int alpha_flag_show_after_trunc = 0;		/* -H */
@@ -451,6 +485,10 @@
 struct alpha_reloc_tag
 {
   fixS *master;			/* The literal reloc.  */
+#ifdef OBJ_EVAX
+  struct symbol *sym;
+  struct symbol *psym;
+#endif
   fixS *slaves;			/* Head of linked list of lituses.  */
   segT segment;			/* Segment relocs are in or undefined_section.  */
   long sequence;		/* Sequence #.  */
@@ -527,6 +565,10 @@
 static void assemble_insn (const struct alpha_opcode *, const expressionS *, int, struct alpha_insn *, 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 char *s_alpha_section_name (void);
+static symbolS *add_to_link_pool (symbolS *, symbolS *, offsetT);
+#endif
 
 static struct alpha_reloc_tag *
 get_alpha_reloc_tag (long sequence)
@@ -550,11 +592,17 @@
       errmsg = hash_insert (alpha_literal_hash, info->string, (void *) info);
       if (errmsg)
 	as_fatal (errmsg);
+#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,
@@ -718,6 +766,8 @@
   if (alpha_literal_hash)
     bfd_map_over_sections (stdoutput, alpha_adjust_relocs, NULL);
 }
+
+#endif
 
 #ifdef DEBUG_ALPHA
 static void
@@ -1176,7 +1226,8 @@
 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;
@@ -1268,11 +1319,9 @@
 	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)
 	  {
 	    if (range_signed_16 (addend))
 	      {
@@ -1292,20 +1341,97 @@
 	  }
 	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;
+		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)
+		  {
+		    char *ensymname;
+		    symbolS *ensym;
+		    volatile asymbol *dummy;
+
+		    ptr1 = strstr (symname, "..") + 2;
+		    if (ptr1 > ptr2)
+		      ptr1 = symname;
+		    ensymname = (char *) xmalloc (ptr2 - ptr1 + 5);
+		    memcpy (ensymname, ptr1, ptr2 - ptr1);
+		    memcpy (ensymname + (ptr2 - ptr1), "..en", 5);
+
+		    assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS);
+		    insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_NOP;
+		    ensym = symbol_find_or_make (ensymname);
+		    ensym->sy_used = 1;
+		    /* 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.  */
+		    dummy = symbol_get_bfdsym (exp->X_add_symbol);
+		  }
+		else if (alpha_flag_replace && targreg == 27)
+		  {
+		    char *psymname;
+		    symbolS *psym;
+
+		    ptr1 = strstr (symname, "..") + 2;
+		    if (ptr1 > ptr2)
+		      ptr1 = symname;
+		    psymname = (char *) xmalloc (ptr2 - ptr1 + 1);
+		    memcpy (psymname, ptr1, ptr2 - ptr1);
+		    psymname [ptr2 - ptr1] = 0;
+		    assert (insn.nfixups + 1 <= MAX_INSN_FIXUPS);
+		    insn.fixups[insn.nfixups].reloc = BFD_RELOC_ALPHA_LDA;
+		    psym = symbol_find_or_make (psymname);
+		    psym->sy_used = 1;
+		    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);
+	      {
+		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 (alpha_evax_proc->symbol,
+					    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 +1461,7 @@
       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 +1483,20 @@
 
   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 (alpha_evax_proc->symbol,
+				 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
@@ -1525,7 +1655,7 @@
   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
@@ -1636,8 +1766,20 @@
 	  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:
+	      assert (size >= 1 && size <= 4);
+	    }
+ 
 	  pcrel = reloc_howto->pc_relative;
 	}
 
@@ -1784,6 +1926,18 @@
 	  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)
 	    {
@@ -1963,8 +2117,9 @@
 	}
 
       /* 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);
@@ -2000,15 +2155,22 @@
   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], 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);
 
@@ -2049,7 +2211,8 @@
       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], opname);
     }
   else
     {
@@ -2100,7 +2263,7 @@
 	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];
@@ -2252,7 +2415,7 @@
 	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);
@@ -2662,15 +2825,14 @@
   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
@@ -2688,6 +2850,41 @@
       insn.sequence = lituse;
     }
 
+#ifdef OBJ_EVAX
+  if (alpha_flag_replace
+      && r == AXP_REG_RA
+      && tok[tokidx].X_add_symbol
+      && alpha_linkage_symbol)
+    {
+      const char *symname = S_GET_NAME (tok[tokidx].X_add_symbol);
+      int symlen = strlen (symname);
+      char *ensymname;
+
+      ensymname = (char *) xmalloc (symlen + 5);
+      memcpy (ensymname, symname, symlen);
+      memcpy (ensymname + symlen, "..en", 5);
+
+      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;
+    }
+#endif
+
   emit_insn (&insn);
 }
 
@@ -2784,7 +2981,10 @@
   insn.sequence = next_sequence_num--;
 
   emit_insn (&insn);
-#endif /* OBJ_ECOFF || OBJ_ELF */
+#else /* OBJ_ECOFF || OBJ_ELF */
+  /* Avoid warning.  */
+  tok = NULL;
+#endif
 }
 
 /* The macro table.  */
@@ -3153,7 +3353,7 @@
 
    Add new fixup only if offset isn't 16bit.  */
 
-valueT
+static symbolS *
 add_to_link_pool (symbolS *basesym,
 		  symbolS *sym,
 		  offsetT addend)
@@ -3161,12 +3361,13 @@
   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;
-
-  offset = - *symbol_get_obj (basesym);
+  symbolS *linksym, *expsym;
+  expressionS e;
+  
+  offset = 0; /* ??? DBR */
 
   /* @@ This assumes all entries in a given section will be of the same
      size...  Probably correct, but unwise to rely on.  */
@@ -3175,31 +3376,44 @@
   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->tc_fix_data.info
+	    && fixp->tc_fix_data.info->sym
+	    && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym)
+	  offset += 8;
+	
+	if (fixp->fx_addsy == sym
+	    && fixp->fx_offset == (valueT)addend
+	    && fixp->tc_fix_data.info
+	    && fixp->tc_fix_data.info->sym
+	    && fixp->tc_fix_data.info->sym->sy_value.X_op_symbol == basesym)
+	  return fixp->tc_fix_data.info->sym;
       }
 
   /* Not found in 16bit signed range.  */
 
   subseg_set (alpha_link_section, 0);
+  linksym = symbol_new
+    (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now);
   p = frag_more (8);
   memset (p, 0, 8);
 
-  fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0,
-	   BFD_RELOC_64);
+  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);
+
+  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 expsym;
 }
-
 #endif /* OBJ_EVAX */
 
 /* Assembler directives.  */
@@ -3209,13 +3423,25 @@
 
 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;
   alpha_current_align = 0;
@@ -3239,8 +3465,7 @@
 
 #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)
@@ -3248,13 +3473,9 @@
   char *name;
   char c;
   char *p;
-  offsetT temp;
+  offsetT temp, size;
   symbolS *symbolP;
-#ifdef OBJ_EVAX
-  segT current_section = now_seg;
-  int current_subsec = now_subseg;
-  segT new_seg;
-#endif
+  int log_align = 0;
 
   name = input_line_pointer;
   c = get_symbol_end ();
@@ -3271,35 +3492,17 @@
       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"));
@@ -3308,44 +3511,108 @@
     }
 
 #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;
+      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,
+				 EGPS_S_V_OVR | EGPS_S_V_GBL | EGPS_S_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);
+
+      symbolP->sy_frag = 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);
+  
+#ifndef OBJ_EVAX
+  know (symbolP->sy_frag == &zero_address_frag);
 #endif
-
-  know (symbol_get_frag (symbolP) == &zero_address_frag);
-
   demand_empty_rest_of_line ();
 }
 
@@ -3623,6 +3890,8 @@
 
   arg = get_absolute_expression ();
   demand_empty_rest_of_line ();
+  alpha_prologue_label = symbol_new
+    (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now);
 
   if (ECOFF_DEBUGGING)
     sym = ecoff_get_cur_proc_sym ();
@@ -3886,24 +4155,169 @@
 
 #ifdef OBJ_EVAX
 
+/* Get name of section.  */
+static 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 = xmalloc (end - input_line_pointer + 1);
+      memcpy (name, input_line_pointer, end - input_line_pointer);
+      name[end - input_line_pointer] = '\0';
+      input_line_pointer = end;
+    }
+  SKIP_WHITESPACE ();
+  return name;
+}
+
+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_S_V_PIC;
+      else if (strncmp (str, "LIB", 3) == 0)
+	flag = EGPS_S_V_LIB;
+      else if (strncmp (str, "OVR", 3) == 0)
+	flag = EGPS_S_V_OVR;
+      else if (strncmp (str, "REL", 3) == 0)
+	flag = EGPS_S_V_REL;
+      else if (strncmp (str, "GBL", 3) == 0)
+	flag = EGPS_S_V_GBL;
+      else if (strncmp (str, "SHR", 3) == 0)
+	flag = EGPS_S_V_SHR;
+      else if (strncmp (str, "EXE", 3) == 0)
+	flag = EGPS_S_V_EXE;
+      else if (strncmp (str, "WRT", 3) == 0)
+	flag = EGPS_S_V_WRT;
+      else if (strncmp (str, "VEC", 3) == 0)
+	flag = EGPS_S_V_VEC;
+      else if (strncmp (str, "MOD", 3) == 0)
+	{
+	  flag = no ? EGPS_S_V_NOMOD : EGPS_S_V_NOMOD << EGPS_S_V_NO_SHIFT;
+	  no = 0;
+	}
+      else if (strncmp (str, "COM", 3) == 0)
+	flag = EGPS_S_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_S_V_NO_SHIFT;
+  else
+    return flag;
+}
+
 /* Handle the section specific pseudo-op.  */
 
+#define EVAX_SECTION_COUNT 5
+
+static 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" };
+  char *name, *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 ();
+     	      beg = input_line_pointer;
+     	      c = get_symbol_end ();
+     	      *input_line_pointer = c;
+
+     	      vms_flags |= s_alpha_section_word (beg, input_line_pointer - beg);
+
+     	      SKIP_WHITESPACE ();
+     	    }
+     	  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);
     }
-  temp = get_absolute_expression ();
-  subseg_new (section_name[secid], 0);
+  else
+    {
+      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;
@@ -3918,16 +4332,21 @@
   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;
+  alpha_evax_proc
+    = (struct alpha_evax_procs *) xmalloc (sizeof (struct alpha_evax_procs));
+
+  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);
 
@@ -3940,11 +4359,44 @@
 
   symbol = make_expr_symbol (&symexpr);
   symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION;
-  alpha_evax_proc.symbol = symbol;
+  alpha_evax_proc->symbol = symbol;
+
+  (void) hash_insert
+    (alpha_evax_proc_hash,
+     symbol_get_bfdsym (alpha_evax_proc->symbol)->name, (PTR)alpha_evax_proc);
 
   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 = input_line_pointer;
+      name_end = get_symbol_end ();
+
+      if (! is_name_beginner (*name))
+	{
+	  as_warn (_(".handler directive has no name"));
+	  *input_line_pointer = name_end;
+	}
+      else
+	{
+	  symbolS *sym;
+
+	  sym = symbol_find_or_make (name);
+	  symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION;
+	  alpha_evax_proc->handler = sym;
+	  *input_line_pointer = name_end;
+	}
+      }
+  demand_empty_rest_of_line ();
+}
+
 /* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives.  */
 
 static void
@@ -3952,7 +4404,7 @@
 {
   long val;
 
-  alpha_evax_proc.framereg = tc_get_register (1);
+  alpha_evax_proc->framereg = tc_get_register (1);
 
   SKIP_WHITESPACE ();
   if (*input_line_pointer++ != ','
@@ -3964,7 +4416,7 @@
       return;
     }
 
-  alpha_evax_proc.framesize = val;
+  alpha_evax_proc->framesize = val;
 
   (void) tc_get_register (1);
   SKIP_WHITESPACE ();
@@ -3975,7 +4427,18 @@
       demand_empty_rest_of_line ();
       return;
     }
-  alpha_evax_proc.rsa_offset = get_absolute_expression ();
+  alpha_evax_proc->rsa_offset = get_absolute_expression ();
+}
+
+static void
+s_alpha_prologue (int ignore ATTRIBUTE_UNUSED)
+{
+  int arg;
+
+  arg = get_absolute_expression ();
+  demand_empty_rest_of_line ();
+  alpha_prologue_label = symbol_new
+    (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now);
 }
 
 static void
@@ -3983,12 +4446,14 @@
 {
   char *name;
   char name_end;
-  long val;
   register char *p;
   expressionS exp;
   symbolS *entry_sym;
   fixS *fixp;
   segment_info_type *seginfo = seg_info (alpha_link_section);
+  const char *entry_sym_name;
+  char *sym_name;
+  int len;
 
   if (now_seg != alpha_link_section)
     {
@@ -3997,30 +4462,42 @@
       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"));
+      as_warn (_(".pdesc directive has no entry symbol"));
       demand_empty_rest_of_line ();
       return;
     }
-
-  *symbol_get_obj (alpha_evax_proc.symbol) =
-    (valueT) seginfo->literal_pool_size;
-
-  expression (&exp);
-  if (exp.X_op != O_symbol)
+  
+  entry_sym = make_expr_symbol (&exp);
+  entry_sym_name = symbol_get_bfdsym (entry_sym)->name;
+ 
+  len = strlen (entry_sym_name);
+  sym_name = (char *) xmalloc (len - 4 + 1);
+  strncpy (sym_name, entry_sym_name, len - 4);
+  sym_name [len - 4] = 0;
+  
+  alpha_evax_proc = (struct alpha_evax_procs *)
+    hash_find (alpha_evax_proc_hash, sym_name);
+ 
+  if (!alpha_evax_proc || !S_IS_DEFINED (alpha_evax_proc->symbol))
     {
-      as_warn (_(".pdesc directive has no entry symbol"));
+      as_fatal (_(".pdesc has no matching .ent"));
       demand_empty_rest_of_line ();
       return;
     }
 
-  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);
+  *symbol_get_obj (alpha_evax_proc->symbol) =
+    (valueT) seginfo->literal_pool_size;
 
+  alpha_evax_proc->symbol->sy_obj = (valueT)seginfo->literal_pool_size;
+ 
+  /* 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++ != ',')
     {
@@ -4034,13 +4511,13 @@
   name_end = get_symbol_end ();
 
   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
     {
@@ -4062,53 +4539,58 @@
   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);
 
-  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);
+  p = frag_more (6);
+  fixp = fix_new (frag_now, p - frag_now->fr_literal, 6, 0, 0, 0, 0);
   fixp->fx_done = 1;
-  seginfo->literal_pool_size += 8;
-
+  seginfo->literal_pool_size += 6;
+  
   /* pdesc+16: Size.  */
-  md_number_to_chars (p, (valueT) alpha_evax_proc.framesize, 4);
+  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.  */
@@ -4119,8 +4601,25 @@
 
   /* pdesc+24: register masks.  */
 
-  md_number_to_chars (p, alpha_evax_proc.imask, 4);
-  md_number_to_chars (p + 4, alpha_evax_proc.fmask, 4);
+  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)
+    {
+      p = frag_more (8);
+      fixp = fix_new (frag_now, p - frag_now->fr_literal, 8,
+	              alpha_evax_proc->handler, 0, 0, BFD_RELOC_64);
+    }
+
+  if (alpha_evax_proc->handler_data)
+    {
+      /* 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;
+      md_number_to_chars (p, alpha_evax_proc->handler_data, 8);
+    }
 }
 
 /* Support for crash debug on vms.  */
@@ -4165,6 +4664,7 @@
 {
   expressionS exp;
   char *p;
+  fixS *fixp;
 
 #ifdef md_flush_pending_output
   md_flush_pending_output ();
@@ -4177,10 +4677,36 @@
     }
   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);
+
+      linkage_fixup = (struct alpha_linkage_fixups *)
+	xmalloc (sizeof (struct alpha_linkage_fixups));
+
+      linkage_fixup->fixp = fixp;
+      linkage_fixup->next = 0;
+
+      if (alpha_insn_label == 0)
+	alpha_insn_label = symbol_new
+	  (FAKE_LABEL_NAME, now_seg, (valueT) frag_now_fix (), frag_now);
+      linkage_fixup->label = alpha_insn_label;
+
+      if (alpha_linkage_fixup_root == 0)
+	{
+	  alpha_linkage_fixup_root = alpha_linkage_fixup_tail = linkage_fixup;
+	  alpha_linkage_fixup_tail->next = 0;
+	}
+      else
+	{
+	  alpha_linkage_fixup_tail->next = linkage_fixup;
+	  alpha_linkage_fixup_tail = linkage_fixup;
+	  alpha_linkage_fixup_tail->next = 0;
+	}
     }
   demand_empty_rest_of_line ();
 }
@@ -4212,7 +4738,7 @@
 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 ();
 }
@@ -4229,7 +4755,7 @@
     }
   else
     {
-      alpha_evax_proc.imask = val;
+      alpha_evax_proc->imask = val;
       (void) get_absolute_expression ();
     }
   demand_empty_rest_of_line ();
@@ -4247,7 +4773,7 @@
     }
   else
     {
-      alpha_evax_proc.fmask = val;
+      alpha_evax_proc->fmask = val;
       (void) get_absolute_expression ();
     }
   demand_empty_rest_of_line ();
@@ -4261,7 +4787,7 @@
   c = get_symbol_end ();
   *input_line_pointer = c;
   demand_empty_rest_of_line ();
-  alpha_evax_proc.symbol = 0;
+  alpha_evax_proc = 0;
 }
 
 static void
@@ -4485,7 +5011,7 @@
 {
   int align;
   char fill, *pfill;
-  long max_alignment = 15;
+  long max_alignment = 16;
 
   align = get_absolute_expression ();
   if (align > max_alignment)
@@ -4612,12 +5138,12 @@
       {
 	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;
     }
 }
@@ -4643,22 +5169,26 @@
   {"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.  */
@@ -4683,8 +5213,12 @@
   {"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'},
   {"s_floating", s_alpha_float_cons, 'f'},
@@ -4955,6 +5489,7 @@
 
 #ifdef OBJ_EVAX
   create_literal_section (".link", &alpha_link_section, &alpha_link_symbol);
+  alpha_evax_proc_hash = hash_new ();
 #endif
 
 #ifdef OBJ_ELF
@@ -5089,6 +5624,14 @@
 
     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:
@@ -5128,8 +5671,9 @@
 #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
 }
@@ -5294,6 +5838,79 @@
     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 ((abs (value) >> 2) & ~0xfffff)
+	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 ((abs (value)) & ~0x7fff)
+	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 ((abs (value) >> 2) & ~0xfffff)
+	{
+	  /* 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;
@@ -5463,6 +6080,12 @@
     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:
@@ -5502,6 +6125,7 @@
     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:
@@ -5555,6 +6179,13 @@
 	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;
@@ -5615,6 +6246,62 @@
 #endif
     }
 
+#ifdef OBJ_EVAX
+  switch (fixp->fx_r_type)
+    {
+      struct evax_private_udata_struct *udata;
+      const char *pname;
+      int pname_len;
+
+    case BFD_RELOC_ALPHA_LINKAGE:
+      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 = xstrdup (pname);
+	  my_pname [pname_len - 4] = 0;
+	  sym = symbol_find (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 = (struct evax_private_udata_struct *)
+	xmalloc (sizeof (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;
 }
 
Index: config/tc-alpha.h
===================================================================
RCS file: /cvs/src/src/gas/config/tc-alpha.h,v
retrieving revision 1.28
diff -u -r1.28 tc-alpha.h
--- config/tc-alpha.h	15 Jan 2009 12:42:52 -0000	1.28
+++ config/tc-alpha.h	24 Feb 2009 09:58:58 -0000
@@ -69,9 +69,9 @@
 #define md_operand(x)
 
 #ifdef OBJ_EVAX
+#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1
 
-/* This field keeps the symbols position in the link section.  */
-#define OBJ_SYMFIELD_TYPE valueT
+#define tc_canonicalize_symbol_name evax_shorten_name
 
 #define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) \
       fix_new_exp (FRAG, OFF, (int)LEN, EXP, 0, \
@@ -81,7 +81,9 @@
 	: BFD_RELOC_ALPHA_LINKAGE);
 #endif
 
-#ifndef VMS
+#ifdef OBJ_EVAX
+#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 3
+#else
 #define TC_IMPLICIT_LCOMM_ALIGNMENT(size, align) \
   do							\
     {							\
@@ -133,12 +135,14 @@
 #define RELOC_OP_P
 #endif
 
+#ifndef OBJ_EVAX
 /* Before the relocations are written, reorder them, so that user
    supplied !lituse relocations follow the appropriate !literal
    relocations.  Also convert the gas-internal relocations to the
    appropriate linker relocations.  */
 #define tc_frob_file_before_fix() alpha_before_fix ()
 extern void alpha_before_fix (void);
+#endif
 
 #ifdef OBJ_ELF
 #define md_end  alpha_elf_md_end
Index: doc/as.texinfo
===================================================================
RCS file: /cvs/src/src/gas/doc/as.texinfo,v
retrieving revision 1.195
diff -u -r1.195 as.texinfo
--- doc/as.texinfo	23 Dec 2008 19:10:21 -0000	1.195
+++ doc/as.texinfo	24 Feb 2009 09:58:58 -0000
@@ -248,6 +248,7 @@
 @emph{Target Alpha options:}
    [@b{-m@var{cpu}}]
    [@b{-mdebug} | @b{-no-mdebug}]
+   [@b{-replace} | @b{-noreplace}]
    [@b{-relax}] [@b{-g}] [@b{-G@var{size}}]
    [@b{-F}] [@b{-32addr}]
 @end ifset
Index: doc/c-alpha.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-alpha.texi,v
retrieving revision 1.8
diff -u -r1.8 c-alpha.texi
--- doc/c-alpha.texi	31 May 2005 22:53:11 -0000	1.8
+++ doc/c-alpha.texi	24 Feb 2009 09:58:58 -0000
@@ -90,6 +90,15 @@
 because not all symbol arithmetic can be represented.  However, the option
 can still be useful in specific applications.
 
+@cindex @code{-replace} command line option, Alpha
+@cindex @code{-noreplace} command line option, Alpha
+@item -replace
+@item -noreplace
+Enables or disables the optimization of procedure calls, both at assemblage
+and at link time.  These options are only available for VMS targets and
+@code{-replace} is the default.  See section 1.4.1 of the OpenVMS Linker
+Utility Manual.
+
 @cindex @code{-g} command line option, Alpha
 @item -g
 This option is used when the compiler generates debug information.  When


More information about the Binutils mailing list